This commit is contained in:
2025-10-20 14:10:54 +02:00
parent 75ca8fd840
commit d2c1970ef8
732 changed files with 101915 additions and 2 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,229 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_AEGIS_State128L', \false)) {
return;
}
if (!\defined('SODIUM_COMPAT_AEGIS_C0')) {
\define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\r\x15\"7Y\x90\xe9yb");
}
if (!\defined('SODIUM_COMPAT_AEGIS_C1')) {
\define('SODIUM_COMPAT_AEGIS_C1', "\xdb=\x18Um\xc2/\xf1 \x111Bs\xb5(\xdd");
}
class ParagonIE_Sodium_Core_AEGIS_State128L
{
/** @var array<int, string> $state */
protected $state;
public function __construct()
{
$this->state = \array_fill(0, 8, '');
}
/**
* @internal Only use this for unit tests!
* @return string[]
*/
public function getState()
{
return \array_values($this->state);
}
/**
* @param array $input
* @return self
* @throws SodiumException
*
* @internal Only for unit tests
*/
public static function initForUnitTests(array $input)
{
if (\count($input) < 8) {
throw new \SodiumException('invalid input');
}
$state = new self();
for ($i = 0; $i < 8; ++$i) {
$state->state[$i] = $input[$i];
}
return $state;
}
/**
* @param string $key
* @param string $nonce
* @return self
*/
public static function init($key, $nonce)
{
$state = new self();
// S0 = key ^ nonce
$state->state[0] = $key ^ $nonce;
// S1 = C1
$state->state[1] = \SODIUM_COMPAT_AEGIS_C1;
// S2 = C0
$state->state[2] = \SODIUM_COMPAT_AEGIS_C0;
// S3 = C1
$state->state[3] = \SODIUM_COMPAT_AEGIS_C1;
// S4 = key ^ nonce
$state->state[4] = $key ^ $nonce;
// S5 = key ^ C0
$state->state[5] = $key ^ \SODIUM_COMPAT_AEGIS_C0;
// S6 = key ^ C1
$state->state[6] = $key ^ \SODIUM_COMPAT_AEGIS_C1;
// S7 = key ^ C0
$state->state[7] = $key ^ \SODIUM_COMPAT_AEGIS_C0;
// Repeat(10, Update(nonce, key))
for ($i = 0; $i < 10; ++$i) {
$state->update($nonce, $key);
}
return $state;
}
/**
* @param string $ai
* @return self
*/
public function absorb($ai)
{
if (\ParagonIE_Sodium_Core_Util::strlen($ai) !== 32) {
throw new \SodiumException('Input must be two AES blocks in size');
}
$t0 = \ParagonIE_Sodium_Core_Util::substr($ai, 0, 16);
$t1 = \ParagonIE_Sodium_Core_Util::substr($ai, 16, 16);
return $this->update($t0, $t1);
}
/**
* @param string $ci
* @return string
* @throws SodiumException
*/
public function dec($ci)
{
if (\ParagonIE_Sodium_Core_Util::strlen($ci) !== 32) {
throw new \SodiumException('Input must be two AES blocks in size');
}
// z0 = S6 ^ S1 ^ (S2 & S3)
$z0 = $this->state[6] ^ $this->state[1] ^ \ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// z1 = S2 ^ S5 ^ (S6 & S7)
$z1 = $this->state[2] ^ $this->state[5] ^ \ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
// t0, t1 = Split(xi, 128)
$t0 = \ParagonIE_Sodium_Core_Util::substr($ci, 0, 16);
$t1 = \ParagonIE_Sodium_Core_Util::substr($ci, 16, 16);
// out0 = t0 ^ z0
// out1 = t1 ^ z1
$out0 = $t0 ^ $z0;
$out1 = $t1 ^ $z1;
// Update(out0, out1)
// xi = out0 || out1
$this->update($out0, $out1);
return $out0 . $out1;
}
/**
* @param string $cn
* @return string
*/
public function decPartial($cn)
{
$len = \ParagonIE_Sodium_Core_Util::strlen($cn);
// z0 = S6 ^ S1 ^ (S2 & S3)
$z0 = $this->state[6] ^ $this->state[1] ^ \ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// z1 = S2 ^ S5 ^ (S6 & S7)
$z1 = $this->state[2] ^ $this->state[5] ^ \ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
// t0, t1 = Split(ZeroPad(cn, 256), 128)
$cn = \str_pad($cn, 32, "\x00", \STR_PAD_RIGHT);
$t0 = \ParagonIE_Sodium_Core_Util::substr($cn, 0, 16);
$t1 = \ParagonIE_Sodium_Core_Util::substr($cn, 16, 16);
// out0 = t0 ^ z0
// out1 = t1 ^ z1
$out0 = $t0 ^ $z0;
$out1 = $t1 ^ $z1;
// xn = Truncate(out0 || out1, |cn|)
$xn = \ParagonIE_Sodium_Core_Util::substr($out0 . $out1, 0, $len);
// v0, v1 = Split(ZeroPad(xn, 256), 128)
$padded = \str_pad($xn, 32, "\x00", \STR_PAD_RIGHT);
$v0 = \ParagonIE_Sodium_Core_Util::substr($padded, 0, 16);
$v1 = \ParagonIE_Sodium_Core_Util::substr($padded, 16, 16);
// Update(v0, v1)
$this->update($v0, $v1);
// return xn
return $xn;
}
/**
* @param string $xi
* @return string
* @throws SodiumException
*/
public function enc($xi)
{
if (\ParagonIE_Sodium_Core_Util::strlen($xi) !== 32) {
throw new \SodiumException('Input must be two AES blocks in size');
}
// z0 = S6 ^ S1 ^ (S2 & S3)
$z0 = $this->state[6] ^ $this->state[1] ^ \ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// z1 = S2 ^ S5 ^ (S6 & S7)
$z1 = $this->state[2] ^ $this->state[5] ^ \ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
// t0, t1 = Split(xi, 128)
$t0 = \ParagonIE_Sodium_Core_Util::substr($xi, 0, 16);
$t1 = \ParagonIE_Sodium_Core_Util::substr($xi, 16, 16);
// out0 = t0 ^ z0
// out1 = t1 ^ z1
$out0 = $t0 ^ $z0;
$out1 = $t1 ^ $z1;
// Update(t0, t1)
// ci = out0 || out1
$this->update($t0, $t1);
// return ci
return $out0 . $out1;
}
/**
* @param int $ad_len_bits
* @param int $msg_len_bits
* @return string
*/
public function finalize($ad_len_bits, $msg_len_bits)
{
$encoded = \ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) . \ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
$t = $this->state[2] ^ $encoded;
for ($i = 0; $i < 7; ++$i) {
$this->update($t, $t);
}
return ($this->state[0] ^ $this->state[1] ^ $this->state[2] ^ $this->state[3]) . ($this->state[4] ^ $this->state[5] ^ $this->state[6] ^ $this->state[7]);
}
/**
* @param string $m0
* @param string $m1
* @return self
*/
public function update($m0, $m1)
{
/*
S'0 = AESRound(S7, S0 ^ M0)
S'1 = AESRound(S0, S1)
S'2 = AESRound(S1, S2)
S'3 = AESRound(S2, S3)
S'4 = AESRound(S3, S4 ^ M1)
S'5 = AESRound(S4, S5)
S'6 = AESRound(S5, S6)
S'7 = AESRound(S6, S7)
*/
list($s_0, $s_1) = \ParagonIE_Sodium_Core_AES::doubleRound($this->state[7], $this->state[0] ^ $m0, $this->state[0], $this->state[1]);
list($s_2, $s_3) = \ParagonIE_Sodium_Core_AES::doubleRound($this->state[1], $this->state[2], $this->state[2], $this->state[3]);
list($s_4, $s_5) = \ParagonIE_Sodium_Core_AES::doubleRound($this->state[3], $this->state[4] ^ $m1, $this->state[4], $this->state[5]);
list($s_6, $s_7) = \ParagonIE_Sodium_Core_AES::doubleRound($this->state[5], $this->state[6], $this->state[6], $this->state[7]);
/*
S0 = S'0
S1 = S'1
S2 = S'2
S3 = S'3
S4 = S'4
S5 = S'5
S6 = S'6
S7 = S'7
*/
$this->state[0] = $s_0;
$this->state[1] = $s_1;
$this->state[2] = $s_2;
$this->state[3] = $s_3;
$this->state[4] = $s_4;
$this->state[5] = $s_5;
$this->state[6] = $s_6;
$this->state[7] = $s_7;
return $this;
}
}

View File

@@ -0,0 +1,200 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_AEGIS_State256', \false)) {
return;
}
if (!\defined('SODIUM_COMPAT_AEGIS_C0')) {
\define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\r\x15\"7Y\x90\xe9yb");
}
if (!\defined('SODIUM_COMPAT_AEGIS_C1')) {
\define('SODIUM_COMPAT_AEGIS_C1', "\xdb=\x18Um\xc2/\xf1 \x111Bs\xb5(\xdd");
}
class ParagonIE_Sodium_Core_AEGIS_State256
{
/** @var array<int, string> $state */
protected $state;
public function __construct()
{
$this->state = \array_fill(0, 6, '');
}
/**
* @internal Only use this for unit tests!
* @return string[]
*/
public function getState()
{
return \array_values($this->state);
}
/**
* @param array $input
* @return self
* @throws SodiumException
*
* @internal Only for unit tests
*/
public static function initForUnitTests(array $input)
{
if (\count($input) < 6) {
throw new \SodiumException('invalid input');
}
$state = new self();
for ($i = 0; $i < 6; ++$i) {
$state->state[$i] = $input[$i];
}
return $state;
}
/**
* @param string $key
* @param string $nonce
* @return self
*/
public static function init($key, $nonce)
{
$state = new self();
$k0 = \ParagonIE_Sodium_Core_Util::substr($key, 0, 16);
$k1 = \ParagonIE_Sodium_Core_Util::substr($key, 16, 16);
$n0 = \ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16);
$n1 = \ParagonIE_Sodium_Core_Util::substr($nonce, 16, 16);
// S0 = k0 ^ n0
// S1 = k1 ^ n1
// S2 = C1
// S3 = C0
// S4 = k0 ^ C0
// S5 = k1 ^ C1
$k0_n0 = $k0 ^ $n0;
$k1_n1 = $k1 ^ $n1;
$state->state[0] = $k0_n0;
$state->state[1] = $k1_n1;
$state->state[2] = \SODIUM_COMPAT_AEGIS_C1;
$state->state[3] = \SODIUM_COMPAT_AEGIS_C0;
$state->state[4] = $k0 ^ \SODIUM_COMPAT_AEGIS_C0;
$state->state[5] = $k1 ^ \SODIUM_COMPAT_AEGIS_C1;
// Repeat(4,
// Update(k0)
// Update(k1)
// Update(k0 ^ n0)
// Update(k1 ^ n1)
// )
for ($i = 0; $i < 4; ++$i) {
$state->update($k0);
$state->update($k1);
$state->update($k0 ^ $n0);
$state->update($k1 ^ $n1);
}
return $state;
}
/**
* @param string $ai
* @return self
* @throws SodiumException
*/
public function absorb($ai)
{
if (\ParagonIE_Sodium_Core_Util::strlen($ai) !== 16) {
throw new \SodiumException('Input must be an AES block in size');
}
return $this->update($ai);
}
/**
* @param string $ci
* @return string
* @throws SodiumException
*/
public function dec($ci)
{
if (\ParagonIE_Sodium_Core_Util::strlen($ci) !== 16) {
throw new \SodiumException('Input must be an AES block in size');
}
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
$z = $this->state[1] ^ $this->state[4] ^ $this->state[5] ^ \ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
$xi = $ci ^ $z;
$this->update($xi);
return $xi;
}
/**
* @param string $cn
* @return string
*/
public function decPartial($cn)
{
$len = \ParagonIE_Sodium_Core_Util::strlen($cn);
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
$z = $this->state[1] ^ $this->state[4] ^ $this->state[5] ^ \ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// t = ZeroPad(cn, 128)
$t = \str_pad($cn, 16, "\x00", \STR_PAD_RIGHT);
// out = t ^ z
$out = $t ^ $z;
// xn = Truncate(out, |cn|)
$xn = \ParagonIE_Sodium_Core_Util::substr($out, 0, $len);
// v = ZeroPad(xn, 128)
$v = \str_pad($xn, 16, "\x00", \STR_PAD_RIGHT);
// Update(v)
$this->update($v);
// return xn
return $xn;
}
/**
* @param string $xi
* @return string
* @throws SodiumException
*/
public function enc($xi)
{
if (\ParagonIE_Sodium_Core_Util::strlen($xi) !== 16) {
throw new \SodiumException('Input must be an AES block in size');
}
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
$z = $this->state[1] ^ $this->state[4] ^ $this->state[5] ^ \ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
$this->update($xi);
return $xi ^ $z;
}
/**
* @param int $ad_len_bits
* @param int $msg_len_bits
* @return string
*/
public function finalize($ad_len_bits, $msg_len_bits)
{
$encoded = \ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) . \ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
$t = $this->state[3] ^ $encoded;
for ($i = 0; $i < 7; ++$i) {
$this->update($t);
}
return ($this->state[0] ^ $this->state[1] ^ $this->state[2]) . ($this->state[3] ^ $this->state[4] ^ $this->state[5]);
}
/**
* @param string $m
* @return self
*/
public function update($m)
{
/*
S'0 = AESRound(S5, S0 ^ M)
S'1 = AESRound(S0, S1)
S'2 = AESRound(S1, S2)
S'3 = AESRound(S2, S3)
S'4 = AESRound(S3, S4)
S'5 = AESRound(S4, S5)
*/
list($s_0, $s_1) = \ParagonIE_Sodium_Core_AES::doubleRound($this->state[5], $this->state[0] ^ $m, $this->state[0], $this->state[1]);
list($s_2, $s_3) = \ParagonIE_Sodium_Core_AES::doubleRound($this->state[1], $this->state[2], $this->state[2], $this->state[3]);
list($s_4, $s_5) = \ParagonIE_Sodium_Core_AES::doubleRound($this->state[3], $this->state[4], $this->state[4], $this->state[5]);
/*
S0 = S'0
S1 = S'1
S2 = S'2
S3 = S'3
S4 = S'4
S5 = S'5
*/
$this->state[0] = $s_0;
$this->state[1] = $s_1;
$this->state[2] = $s_2;
$this->state[3] = $s_3;
$this->state[4] = $s_4;
$this->state[5] = $s_5;
return $this;
}
}

View File

@@ -0,0 +1,107 @@
<?php
if (!\defined('SODIUM_COMPAT_AEGIS_C0')) {
\define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\r\x15\"7Y\x90\xe9yb");
}
if (!\defined('SODIUM_COMPAT_AEGIS_C1')) {
\define('SODIUM_COMPAT_AEGIS_C1', "\xdb=\x18Um\xc2/\xf1 \x111Bs\xb5(\xdd");
}
class ParagonIE_Sodium_Core_AEGIS128L extends \ParagonIE_Sodium_Core_AES
{
/**
* @param string $ct
* @param string $tag
* @param string $ad
* @param string $key
* @param string $nonce
* @return string
* @throws SodiumException
*/
public static function decrypt($ct, $tag, $ad, $key, $nonce)
{
$state = self::init($key, $nonce);
$ad_blocks = self::strlen($ad) + 31 >> 5;
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 5, 32);
if (self::strlen($ai) < 32) {
$ai = \str_pad($ai, 32, "\x00", \STR_PAD_RIGHT);
}
$state->absorb($ai);
}
$msg = '';
$cn = self::strlen($ct) & 31;
$ct_blocks = self::strlen($ct) >> 5;
for ($i = 0; $i < $ct_blocks; ++$i) {
$msg .= $state->dec(self::substr($ct, $i << 5, 32));
}
if ($cn) {
$start = $ct_blocks << 5;
$msg .= $state->decPartial(self::substr($ct, $start, $cn));
}
$expected_tag = $state->finalize(self::strlen($ad) << 3, self::strlen($msg) << 3);
if (!self::hashEquals($expected_tag, $tag)) {
try {
// The RFC says to erase msg, so we shall try:
\ParagonIE_Sodium_Compat::memzero($msg);
} catch (\SodiumException $ex) {
// Do nothing if we cannot memzero
}
throw new \SodiumException('verification failed');
}
return $msg;
}
/**
* @param string $msg
* @param string $ad
* @param string $key
* @param string $nonce
* @return array
*
* @throws SodiumException
*/
public static function encrypt($msg, $ad, $key, $nonce)
{
$state = self::init($key, $nonce);
// ad_blocks = Split(ZeroPad(ad, 256), 256)
// for ai in ad_blocks:
// Absorb(ai)
$ad_len = self::strlen($ad);
$msg_len = self::strlen($msg);
$ad_blocks = $ad_len + 31 >> 5;
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 5, 32);
if (self::strlen($ai) < 32) {
$ai = \str_pad($ai, 32, "\x00", \STR_PAD_RIGHT);
}
$state->absorb($ai);
}
// msg_blocks = Split(ZeroPad(msg, 256), 256)
// for xi in msg_blocks:
// ct = ct || Enc(xi)
$ct = '';
$msg_blocks = $msg_len + 31 >> 5;
for ($i = 0; $i < $msg_blocks; ++$i) {
$xi = self::substr($msg, $i << 5, 32);
if (self::strlen($xi) < 32) {
$xi = \str_pad($xi, 32, "\x00", \STR_PAD_RIGHT);
}
$ct .= $state->enc($xi);
}
// tag = Finalize(|ad|, |msg|)
// ct = Truncate(ct, |msg|)
$tag = $state->finalize($ad_len << 3, $msg_len << 3);
// return ct and tag
return array(self::substr($ct, 0, $msg_len), $tag);
}
/**
* @param string $key
* @param string $nonce
* @return ParagonIE_Sodium_Core_AEGIS_State128L
*/
public static function init($key, $nonce)
{
return \ParagonIE_Sodium_Core_AEGIS_State128L::init($key, $nonce);
}
}

View File

@@ -0,0 +1,104 @@
<?php
if (!\defined('SODIUM_COMPAT_AEGIS_C0')) {
\define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\r\x15\"7Y\x90\xe9yb");
}
if (!\defined('SODIUM_COMPAT_AEGIS_C1')) {
\define('SODIUM_COMPAT_AEGIS_C1', "\xdb=\x18Um\xc2/\xf1 \x111Bs\xb5(\xdd");
}
class ParagonIE_Sodium_Core_AEGIS256 extends \ParagonIE_Sodium_Core_AES
{
/**
* @param string $ct
* @param string $tag
* @param string $ad
* @param string $key
* @param string $nonce
* @return string
* @throws SodiumException
*/
public static function decrypt($ct, $tag, $ad, $key, $nonce)
{
$state = self::init($key, $nonce);
// ad_blocks = Split(ZeroPad(ad, 128), 128)
$ad_blocks = self::strlen($ad) + 15 >> 4;
// for ai in ad_blocks:
// Absorb(ai)
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 4, 16);
if (self::strlen($ai) < 16) {
$ai = \str_pad($ai, 16, "\x00", \STR_PAD_RIGHT);
}
$state->absorb($ai);
}
$msg = '';
$cn = self::strlen($ct) & 15;
$ct_blocks = self::strlen($ct) >> 4;
// ct_blocks = Split(ZeroPad(ct, 128), 128)
// cn = Tail(ct, |ct| mod 128)
for ($i = 0; $i < $ct_blocks; ++$i) {
$msg .= $state->dec(self::substr($ct, $i << 4, 16));
}
// if cn is not empty:
// msg = msg || DecPartial(cn)
if ($cn) {
$start = $ct_blocks << 4;
$msg .= $state->decPartial(self::substr($ct, $start, $cn));
}
$expected_tag = $state->finalize(self::strlen($ad) << 3, self::strlen($msg) << 3);
if (!self::hashEquals($expected_tag, $tag)) {
try {
// The RFC says to erase msg, so we shall try:
\ParagonIE_Sodium_Compat::memzero($msg);
} catch (\SodiumException $ex) {
// Do nothing if we cannot memzero
}
throw new \SodiumException('verification failed');
}
return $msg;
}
/**
* @param string $msg
* @param string $ad
* @param string $key
* @param string $nonce
* @return array
* @throws SodiumException
*/
public static function encrypt($msg, $ad, $key, $nonce)
{
$state = self::init($key, $nonce);
$ad_len = self::strlen($ad);
$msg_len = self::strlen($msg);
$ad_blocks = $ad_len + 15 >> 4;
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 4, 16);
if (self::strlen($ai) < 16) {
$ai = \str_pad($ai, 16, "\x00", \STR_PAD_RIGHT);
}
$state->absorb($ai);
}
$ct = '';
$msg_blocks = $msg_len + 15 >> 4;
for ($i = 0; $i < $msg_blocks; ++$i) {
$xi = self::substr($msg, $i << 4, 16);
if (self::strlen($xi) < 16) {
$xi = \str_pad($xi, 16, "\x00", \STR_PAD_RIGHT);
}
$ct .= $state->enc($xi);
}
$tag = $state->finalize($ad_len << 3, $msg_len << 3);
return array(self::substr($ct, 0, $msg_len), $tag);
}
/**
* @param string $key
* @param string $nonce
* @return ParagonIE_Sodium_Core_AEGIS_State256
*/
public static function init($key, $nonce)
{
return \ParagonIE_Sodium_Core_AEGIS_State256::init($key, $nonce);
}
}

View File

@@ -0,0 +1,472 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_AES', \false)) {
return;
}
/**
* Bitsliced implementation of the AES block cipher.
*
* Based on the implementation provided by BearSSL.
*
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES extends \ParagonIE_Sodium_Core_Util
{
/**
* @var int[] AES round constants
*/
private static $Rcon = array(0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36);
/**
* Mutates the values of $q!
*
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function sbox(\ParagonIE_Sodium_Core_AES_Block $q)
{
/**
* @var int $x0
* @var int $x1
* @var int $x2
* @var int $x3
* @var int $x4
* @var int $x5
* @var int $x6
* @var int $x7
*/
$x0 = $q[7] & self::U32_MAX;
$x1 = $q[6] & self::U32_MAX;
$x2 = $q[5] & self::U32_MAX;
$x3 = $q[4] & self::U32_MAX;
$x4 = $q[3] & self::U32_MAX;
$x5 = $q[2] & self::U32_MAX;
$x6 = $q[1] & self::U32_MAX;
$x7 = $q[0] & self::U32_MAX;
$y14 = $x3 ^ $x5;
$y13 = $x0 ^ $x6;
$y9 = $x0 ^ $x3;
$y8 = $x0 ^ $x5;
$t0 = $x1 ^ $x2;
$y1 = $t0 ^ $x7;
$y4 = $y1 ^ $x3;
$y12 = $y13 ^ $y14;
$y2 = $y1 ^ $x0;
$y5 = $y1 ^ $x6;
$y3 = $y5 ^ $y8;
$t1 = $x4 ^ $y12;
$y15 = $t1 ^ $x5;
$y20 = $t1 ^ $x1;
$y6 = $y15 ^ $x7;
$y10 = $y15 ^ $t0;
$y11 = $y20 ^ $y9;
$y7 = $x7 ^ $y11;
$y17 = $y10 ^ $y11;
$y19 = $y10 ^ $y8;
$y16 = $t0 ^ $y11;
$y21 = $y13 ^ $y16;
$y18 = $x0 ^ $y16;
/*
* Non-linear section.
*/
$t2 = $y12 & $y15;
$t3 = $y3 & $y6;
$t4 = $t3 ^ $t2;
$t5 = $y4 & $x7;
$t6 = $t5 ^ $t2;
$t7 = $y13 & $y16;
$t8 = $y5 & $y1;
$t9 = $t8 ^ $t7;
$t10 = $y2 & $y7;
$t11 = $t10 ^ $t7;
$t12 = $y9 & $y11;
$t13 = $y14 & $y17;
$t14 = $t13 ^ $t12;
$t15 = $y8 & $y10;
$t16 = $t15 ^ $t12;
$t17 = $t4 ^ $t14;
$t18 = $t6 ^ $t16;
$t19 = $t9 ^ $t14;
$t20 = $t11 ^ $t16;
$t21 = $t17 ^ $y20;
$t22 = $t18 ^ $y19;
$t23 = $t19 ^ $y21;
$t24 = $t20 ^ $y18;
$t25 = $t21 ^ $t22;
$t26 = $t21 & $t23;
$t27 = $t24 ^ $t26;
$t28 = $t25 & $t27;
$t29 = $t28 ^ $t22;
$t30 = $t23 ^ $t24;
$t31 = $t22 ^ $t26;
$t32 = $t31 & $t30;
$t33 = $t32 ^ $t24;
$t34 = $t23 ^ $t33;
$t35 = $t27 ^ $t33;
$t36 = $t24 & $t35;
$t37 = $t36 ^ $t34;
$t38 = $t27 ^ $t36;
$t39 = $t29 & $t38;
$t40 = $t25 ^ $t39;
$t41 = $t40 ^ $t37;
$t42 = $t29 ^ $t33;
$t43 = $t29 ^ $t40;
$t44 = $t33 ^ $t37;
$t45 = $t42 ^ $t41;
$z0 = $t44 & $y15;
$z1 = $t37 & $y6;
$z2 = $t33 & $x7;
$z3 = $t43 & $y16;
$z4 = $t40 & $y1;
$z5 = $t29 & $y7;
$z6 = $t42 & $y11;
$z7 = $t45 & $y17;
$z8 = $t41 & $y10;
$z9 = $t44 & $y12;
$z10 = $t37 & $y3;
$z11 = $t33 & $y4;
$z12 = $t43 & $y13;
$z13 = $t40 & $y5;
$z14 = $t29 & $y2;
$z15 = $t42 & $y9;
$z16 = $t45 & $y14;
$z17 = $t41 & $y8;
/*
* Bottom linear transformation.
*/
$t46 = $z15 ^ $z16;
$t47 = $z10 ^ $z11;
$t48 = $z5 ^ $z13;
$t49 = $z9 ^ $z10;
$t50 = $z2 ^ $z12;
$t51 = $z2 ^ $z5;
$t52 = $z7 ^ $z8;
$t53 = $z0 ^ $z3;
$t54 = $z6 ^ $z7;
$t55 = $z16 ^ $z17;
$t56 = $z12 ^ $t48;
$t57 = $t50 ^ $t53;
$t58 = $z4 ^ $t46;
$t59 = $z3 ^ $t54;
$t60 = $t46 ^ $t57;
$t61 = $z14 ^ $t57;
$t62 = $t52 ^ $t58;
$t63 = $t49 ^ $t58;
$t64 = $z4 ^ $t59;
$t65 = $t61 ^ $t62;
$t66 = $z1 ^ $t63;
$s0 = $t59 ^ $t63;
$s6 = $t56 ^ ~$t62;
$s7 = $t48 ^ ~$t60;
$t67 = $t64 ^ $t65;
$s3 = $t53 ^ $t66;
$s4 = $t51 ^ $t66;
$s5 = $t47 ^ $t65;
$s1 = $t64 ^ ~$s3;
$s2 = $t55 ^ ~$t67;
$q[7] = $s0 & self::U32_MAX;
$q[6] = $s1 & self::U32_MAX;
$q[5] = $s2 & self::U32_MAX;
$q[4] = $s3 & self::U32_MAX;
$q[3] = $s4 & self::U32_MAX;
$q[2] = $s5 & self::U32_MAX;
$q[1] = $s6 & self::U32_MAX;
$q[0] = $s7 & self::U32_MAX;
}
/**
* Mutates the values of $q!
*
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function invSbox(\ParagonIE_Sodium_Core_AES_Block $q)
{
self::processInversion($q);
self::sbox($q);
self::processInversion($q);
}
/**
* This is some boilerplate code needed to invert an S-box. Rather than repeat the code
* twice, I moved it to a protected method.
*
* Mutates $q
*
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
protected static function processInversion(\ParagonIE_Sodium_Core_AES_Block $q)
{
$q0 = ~$q[0] & self::U32_MAX;
$q1 = ~$q[1] & self::U32_MAX;
$q2 = $q[2] & self::U32_MAX;
$q3 = $q[3] & self::U32_MAX;
$q4 = $q[4] & self::U32_MAX;
$q5 = ~$q[5] & self::U32_MAX;
$q6 = ~$q[6] & self::U32_MAX;
$q7 = $q[7] & self::U32_MAX;
$q[7] = ($q1 ^ $q4 ^ $q6) & self::U32_MAX;
$q[6] = ($q0 ^ $q3 ^ $q5) & self::U32_MAX;
$q[5] = ($q7 ^ $q2 ^ $q4) & self::U32_MAX;
$q[4] = ($q6 ^ $q1 ^ $q3) & self::U32_MAX;
$q[3] = ($q5 ^ $q0 ^ $q2) & self::U32_MAX;
$q[2] = ($q4 ^ $q7 ^ $q1) & self::U32_MAX;
$q[1] = ($q3 ^ $q6 ^ $q0) & self::U32_MAX;
$q[0] = ($q2 ^ $q5 ^ $q7) & self::U32_MAX;
}
/**
* @param int $x
* @return int
*/
public static function subWord($x)
{
$q = \ParagonIE_Sodium_Core_AES_Block::fromArray(array($x, $x, $x, $x, $x, $x, $x, $x));
$q->orthogonalize();
self::sbox($q);
$q->orthogonalize();
return $q[0] & self::U32_MAX;
}
/**
* Calculate the key schedule from a given random key
*
* @param string $key
* @return ParagonIE_Sodium_Core_AES_KeySchedule
* @throws SodiumException
*/
public static function keySchedule($key)
{
$key_len = self::strlen($key);
switch ($key_len) {
case 16:
$num_rounds = 10;
break;
case 24:
$num_rounds = 12;
break;
case 32:
$num_rounds = 14;
break;
default:
throw new \SodiumException('Invalid key length: ' . $key_len);
}
$skey = array();
$comp_skey = array();
$nk = $key_len >> 2;
$nkf = $num_rounds + 1 << 2;
$tmp = 0;
for ($i = 0; $i < $nk; ++$i) {
$tmp = self::load_4(self::substr($key, $i << 2, 4));
$skey[$i << 1] = $tmp;
$skey[($i << 1) + 1] = $tmp;
}
for ($i = $nk, $j = 0, $k = 0; $i < $nkf; ++$i) {
if ($j === 0) {
$tmp = ($tmp & 0xff) << 24 | $tmp >> 8;
$tmp = (self::subWord($tmp) ^ self::$Rcon[$k]) & self::U32_MAX;
} elseif ($nk > 6 && $j === 4) {
$tmp = self::subWord($tmp);
}
$tmp ^= $skey[$i - $nk << 1];
$skey[$i << 1] = $tmp & self::U32_MAX;
$skey[($i << 1) + 1] = $tmp & self::U32_MAX;
if (++$j === $nk) {
/** @psalm-suppress LoopInvalidation */
$j = 0;
++$k;
}
}
for ($i = 0; $i < $nkf; $i += 4) {
$q = \ParagonIE_Sodium_Core_AES_Block::fromArray(\array_slice($skey, $i << 1, 8));
$q->orthogonalize();
// We have to overwrite $skey since we're not using C pointers like BearSSL did
for ($j = 0; $j < 8; ++$j) {
$skey[($i << 1) + $j] = $q[$j];
}
}
for ($i = 0, $j = 0; $i < $nkf; ++$i, $j += 2) {
$comp_skey[$i] = $skey[$j] & 0x55555555 | $skey[$j + 1] & 0xaaaaaaaa;
}
return new \ParagonIE_Sodium_Core_AES_KeySchedule($comp_skey, $num_rounds);
}
/**
* Mutates $q
*
* @param ParagonIE_Sodium_Core_AES_KeySchedule $skey
* @param ParagonIE_Sodium_Core_AES_Block $q
* @param int $offset
* @return void
*/
public static function addRoundKey(\ParagonIE_Sodium_Core_AES_Block $q, \ParagonIE_Sodium_Core_AES_KeySchedule $skey, $offset = 0)
{
$block = $skey->getRoundKey($offset);
for ($j = 0; $j < 8; ++$j) {
$q[$j] = ($q[$j] ^ $block[$j]) & \ParagonIE_Sodium_Core_Util::U32_MAX;
}
}
/**
* This mainly exists for testing, as we need the round key features for AEGIS.
*
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
*/
public static function decryptBlockECB($message, $key)
{
if (self::strlen($message) !== 16) {
throw new \SodiumException('decryptBlockECB() expects a 16 byte message');
}
$skey = self::keySchedule($key)->expand();
$q = \ParagonIE_Sodium_Core_AES_Block::init();
$q[0] = self::load_4(self::substr($message, 0, 4));
$q[2] = self::load_4(self::substr($message, 4, 4));
$q[4] = self::load_4(self::substr($message, 8, 4));
$q[6] = self::load_4(self::substr($message, 12, 4));
$q->orthogonalize();
self::bitsliceDecryptBlock($skey, $q);
$q->orthogonalize();
return self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]);
}
/**
* This mainly exists for testing, as we need the round key features for AEGIS.
*
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
*/
public static function encryptBlockECB($message, $key)
{
if (self::strlen($message) !== 16) {
throw new \SodiumException('encryptBlockECB() expects a 16 byte message');
}
$comp_skey = self::keySchedule($key);
$skey = $comp_skey->expand();
$q = \ParagonIE_Sodium_Core_AES_Block::init();
$q[0] = self::load_4(self::substr($message, 0, 4));
$q[2] = self::load_4(self::substr($message, 4, 4));
$q[4] = self::load_4(self::substr($message, 8, 4));
$q[6] = self::load_4(self::substr($message, 12, 4));
$q->orthogonalize();
self::bitsliceEncryptBlock($skey, $q);
$q->orthogonalize();
return self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]);
}
/**
* Mutates $q
*
* @param ParagonIE_Sodium_Core_AES_Expanded $skey
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function bitsliceEncryptBlock(\ParagonIE_Sodium_Core_AES_Expanded $skey, \ParagonIE_Sodium_Core_AES_Block $q)
{
self::addRoundKey($q, $skey);
for ($u = 1; $u < $skey->getNumRounds(); ++$u) {
self::sbox($q);
$q->shiftRows();
$q->mixColumns();
self::addRoundKey($q, $skey, $u << 3);
}
self::sbox($q);
$q->shiftRows();
self::addRoundKey($q, $skey, $skey->getNumRounds() << 3);
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function aesRound($x, $y)
{
$q = \ParagonIE_Sodium_Core_AES_Block::init();
$q[0] = self::load_4(self::substr($x, 0, 4));
$q[2] = self::load_4(self::substr($x, 4, 4));
$q[4] = self::load_4(self::substr($x, 8, 4));
$q[6] = self::load_4(self::substr($x, 12, 4));
$rk = \ParagonIE_Sodium_Core_AES_Block::init();
$rk[0] = $rk[1] = self::load_4(self::substr($y, 0, 4));
$rk[2] = $rk[3] = self::load_4(self::substr($y, 4, 4));
$rk[4] = $rk[5] = self::load_4(self::substr($y, 8, 4));
$rk[6] = $rk[7] = self::load_4(self::substr($y, 12, 4));
$q->orthogonalize();
self::sbox($q);
$q->shiftRows();
$q->mixColumns();
$q->orthogonalize();
// add round key without key schedule:
for ($i = 0; $i < 8; ++$i) {
$q[$i] ^= $rk[$i];
}
return self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]);
}
/**
* Process two AES blocks in one shot.
*
* @param string $b0 First AES block
* @param string $rk0 First round key
* @param string $b1 Second AES block
* @param string $rk1 Second round key
* @return string[]
*/
public static function doubleRound($b0, $rk0, $b1, $rk1)
{
$q = \ParagonIE_Sodium_Core_AES_Block::init();
// First block
$q[0] = self::load_4(self::substr($b0, 0, 4));
$q[2] = self::load_4(self::substr($b0, 4, 4));
$q[4] = self::load_4(self::substr($b0, 8, 4));
$q[6] = self::load_4(self::substr($b0, 12, 4));
// Second block
$q[1] = self::load_4(self::substr($b1, 0, 4));
$q[3] = self::load_4(self::substr($b1, 4, 4));
$q[5] = self::load_4(self::substr($b1, 8, 4));
$q[7] = self::load_4(self::substr($b1, 12, 4));
$rk = \ParagonIE_Sodium_Core_AES_Block::init();
// First round key
$rk[0] = self::load_4(self::substr($rk0, 0, 4));
$rk[2] = self::load_4(self::substr($rk0, 4, 4));
$rk[4] = self::load_4(self::substr($rk0, 8, 4));
$rk[6] = self::load_4(self::substr($rk0, 12, 4));
// Second round key
$rk[1] = self::load_4(self::substr($rk1, 0, 4));
$rk[3] = self::load_4(self::substr($rk1, 4, 4));
$rk[5] = self::load_4(self::substr($rk1, 8, 4));
$rk[7] = self::load_4(self::substr($rk1, 12, 4));
$q->orthogonalize();
self::sbox($q);
$q->shiftRows();
$q->mixColumns();
$q->orthogonalize();
// add round key without key schedule:
for ($i = 0; $i < 8; ++$i) {
$q[$i] ^= $rk[$i];
}
return array(self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]), self::store32_le($q[1]) . self::store32_le($q[3]) . self::store32_le($q[5]) . self::store32_le($q[7]));
}
/**
* @param ParagonIE_Sodium_Core_AES_Expanded $skey
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function bitsliceDecryptBlock(\ParagonIE_Sodium_Core_AES_Expanded $skey, \ParagonIE_Sodium_Core_AES_Block $q)
{
self::addRoundKey($q, $skey, $skey->getNumRounds() << 3);
for ($u = $skey->getNumRounds() - 1; $u > 0; --$u) {
$q->inverseShiftRows();
self::invSbox($q);
self::addRoundKey($q, $skey, $u << 3);
$q->inverseMixColumns();
}
$q->inverseShiftRows();
self::invSbox($q);
self::addRoundKey($q, $skey, $u << 3);
}
}
/**
* Bitsliced implementation of the AES block cipher.
*
* Based on the implementation provided by BearSSL.
*
* @internal This should only be used by sodium_compat
*/

View File

@@ -0,0 +1,300 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_AES_Block', \false)) {
return;
}
/**
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES_Block extends \SplFixedArray
{
/**
* @var array<int, int>
*/
protected $values = array();
/**
* @var int
*/
protected $size;
/**
* @param int $size
*/
public function __construct($size = 8)
{
parent::__construct($size);
$this->size = $size;
$this->values = \array_fill(0, $size, 0);
}
/**
* @return self
*/
public static function init()
{
return new self(8);
}
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @param bool $save_indexes
* @return self
*
* @psalm-suppress MethodSignatureMismatch
*/
#[\ReturnTypeWillChange]
public static function fromArray($array, $save_indexes = null)
{
$count = \count($array);
if ($save_indexes) {
$keys = \array_keys($array);
} else {
$keys = \range(0, $count - 1);
}
$array = \array_values($array);
/** @var array<int, int> $keys */
$obj = new \ParagonIE_Sodium_Core_AES_Block();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($keys[$i], $array[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($i, $array[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param int|null $offset
* @param int $value
* @return void
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!\is_int($value)) {
throw new \InvalidArgumentException('Expected an integer');
}
if (\is_null($offset)) {
$this->values[] = $value;
} else {
$this->values[$offset] = $value;
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->values[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->values[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return int
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
if (!isset($this->values[$offset])) {
$this->values[$offset] = 0;
}
return (int) $this->values[$offset];
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
$out = array();
foreach ($this->values as $v) {
$out[] = \str_pad(\dechex($v), 8, '0', \STR_PAD_LEFT);
}
return array(\implode(', ', $out));
/*
return array(implode(', ', $this->values));
*/
}
/**
* @param int $cl low bit mask
* @param int $ch high bit mask
* @param int $s shift
* @param int $x index 1
* @param int $y index 2
* @return self
*/
public function swapN($cl, $ch, $s, $x, $y)
{
static $u32mask = \ParagonIE_Sodium_Core_Util::U32_MAX;
$a = $this->values[$x] & $u32mask;
$b = $this->values[$y] & $u32mask;
// (x) = (a & cl) | ((b & cl) << (s));
$this->values[$x] = $a & $cl | ($b & $cl) << $s & $u32mask;
// (y) = ((a & ch) >> (s)) | (b & ch);
$this->values[$y] = ($a & $ch & $u32mask) >> $s | $b & $ch;
return $this;
}
/**
* @param int $x index 1
* @param int $y index 2
* @return self
*/
public function swap2($x, $y)
{
return $this->swapN(0x55555555, 0xaaaaaaaa, 1, $x, $y);
}
/**
* @param int $x index 1
* @param int $y index 2
* @return self
*/
public function swap4($x, $y)
{
return $this->swapN(0x33333333, 0xcccccccc, 2, $x, $y);
}
/**
* @param int $x index 1
* @param int $y index 2
* @return self
*/
public function swap8($x, $y)
{
return $this->swapN(0xf0f0f0f, 0xf0f0f0f0, 4, $x, $y);
}
/**
* @return self
*/
public function orthogonalize()
{
return $this->swap2(0, 1)->swap2(2, 3)->swap2(4, 5)->swap2(6, 7)->swap4(0, 2)->swap4(1, 3)->swap4(4, 6)->swap4(5, 7)->swap8(0, 4)->swap8(1, 5)->swap8(2, 6)->swap8(3, 7);
}
/**
* @return self
*/
public function shiftRows()
{
for ($i = 0; $i < 8; ++$i) {
$x = $this->values[$i] & \ParagonIE_Sodium_Core_Util::U32_MAX;
$this->values[$i] = ($x & 0xff | ($x & 0xfc00) >> 2 | ($x & 0x300) << 6 | ($x & 0xf00000) >> 4 | ($x & 0xf0000) << 4 | ($x & 0xc0000000) >> 6 | ($x & 0x3f000000) << 2) & \ParagonIE_Sodium_Core_Util::U32_MAX;
}
return $this;
}
/**
* @param int $x
* @return int
*/
public static function rotr16($x)
{
return $x << 16 & \ParagonIE_Sodium_Core_Util::U32_MAX | $x >> 16;
}
/**
* @return self
*/
public function mixColumns()
{
$q0 = $this->values[0];
$q1 = $this->values[1];
$q2 = $this->values[2];
$q3 = $this->values[3];
$q4 = $this->values[4];
$q5 = $this->values[5];
$q6 = $this->values[6];
$q7 = $this->values[7];
$r0 = ($q0 >> 8 | $q0 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r1 = ($q1 >> 8 | $q1 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r2 = ($q2 >> 8 | $q2 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r3 = ($q3 >> 8 | $q3 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r4 = ($q4 >> 8 | $q4 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r5 = ($q5 >> 8 | $q5 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r6 = ($q6 >> 8 | $q6 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r7 = ($q7 >> 8 | $q7 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$this->values[0] = $q7 ^ $r7 ^ $r0 ^ self::rotr16($q0 ^ $r0);
$this->values[1] = $q0 ^ $r0 ^ $q7 ^ $r7 ^ $r1 ^ self::rotr16($q1 ^ $r1);
$this->values[2] = $q1 ^ $r1 ^ $r2 ^ self::rotr16($q2 ^ $r2);
$this->values[3] = $q2 ^ $r2 ^ $q7 ^ $r7 ^ $r3 ^ self::rotr16($q3 ^ $r3);
$this->values[4] = $q3 ^ $r3 ^ $q7 ^ $r7 ^ $r4 ^ self::rotr16($q4 ^ $r4);
$this->values[5] = $q4 ^ $r4 ^ $r5 ^ self::rotr16($q5 ^ $r5);
$this->values[6] = $q5 ^ $r5 ^ $r6 ^ self::rotr16($q6 ^ $r6);
$this->values[7] = $q6 ^ $r6 ^ $r7 ^ self::rotr16($q7 ^ $r7);
return $this;
}
/**
* @return self
*/
public function inverseMixColumns()
{
$q0 = $this->values[0];
$q1 = $this->values[1];
$q2 = $this->values[2];
$q3 = $this->values[3];
$q4 = $this->values[4];
$q5 = $this->values[5];
$q6 = $this->values[6];
$q7 = $this->values[7];
$r0 = ($q0 >> 8 | $q0 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r1 = ($q1 >> 8 | $q1 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r2 = ($q2 >> 8 | $q2 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r3 = ($q3 >> 8 | $q3 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r4 = ($q4 >> 8 | $q4 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r5 = ($q5 >> 8 | $q5 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r6 = ($q6 >> 8 | $q6 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$r7 = ($q7 >> 8 | $q7 << 24) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$this->values[0] = $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r5 ^ $r7 ^ self::rotr16($q0 ^ $q5 ^ $q6 ^ $r0 ^ $r5);
$this->values[1] = $q0 ^ $q5 ^ $r0 ^ $r1 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q5 ^ $q7 ^ $r1 ^ $r5 ^ $r6);
$this->values[2] = $q0 ^ $q1 ^ $q6 ^ $r1 ^ $r2 ^ $r6 ^ $r7 ^ self::rotr16($q0 ^ $q2 ^ $q6 ^ $r2 ^ $r6 ^ $r7);
$this->values[3] = $q0 ^ $q1 ^ $q2 ^ $q5 ^ $q6 ^ $r0 ^ $r2 ^ $r3 ^ $r5 ^ self::rotr16($q0 ^ $q1 ^ $q3 ^ $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r3 ^ $r5 ^ $r7);
$this->values[4] = $q1 ^ $q2 ^ $q3 ^ $q5 ^ $r1 ^ $r3 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q2 ^ $q4 ^ $q5 ^ $q7 ^ $r1 ^ $r4 ^ $r5 ^ $r6);
$this->values[5] = $q2 ^ $q3 ^ $q4 ^ $q6 ^ $r2 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q2 ^ $q3 ^ $q5 ^ $q6 ^ $r2 ^ $r5 ^ $r6 ^ $r7);
$this->values[6] = $q3 ^ $q4 ^ $q5 ^ $q7 ^ $r3 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q3 ^ $q4 ^ $q6 ^ $q7 ^ $r3 ^ $r6 ^ $r7);
$this->values[7] = $q4 ^ $q5 ^ $q6 ^ $r4 ^ $r6 ^ $r7 ^ self::rotr16($q4 ^ $q5 ^ $q7 ^ $r4 ^ $r7);
return $this;
}
/**
* @return self
*/
public function inverseShiftRows()
{
for ($i = 0; $i < 8; ++$i) {
$x = $this->values[$i];
$this->values[$i] = \ParagonIE_Sodium_Core_Util::U32_MAX & ($x & 0xff | ($x & 0x3f00) << 2 | ($x & 0xc000) >> 6 | ($x & 0xf0000) << 4 | ($x & 0xf00000) >> 4 | ($x & 0x3000000) << 6 | ($x & 0xfc000000) >> 2);
}
return $this;
}
}
/**
* @internal This should only be used by sodium_compat
*/

View File

@@ -0,0 +1,18 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_AES_Expanded', \false)) {
return;
}
/**
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES_Expanded extends \ParagonIE_Sodium_Core_AES_KeySchedule
{
/** @var bool $expanded */
protected $expanded = \true;
}
/**
* @internal This should only be used by sodium_compat
*/

View File

@@ -0,0 +1,74 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_AES_KeySchedule', \false)) {
return;
}
/**
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES_KeySchedule
{
/** @var array<int, int> $skey -- has size 120 */
protected $skey;
/** @var bool $expanded */
protected $expanded = \false;
/** @var int $numRounds */
private $numRounds;
/**
* @param array $skey
* @param int $numRounds
*/
public function __construct(array $skey, $numRounds = 10)
{
$this->skey = $skey;
$this->numRounds = $numRounds;
}
/**
* Get a value at an arbitrary index. Mostly used for unit testing.
*
* @param int $i
* @return int
*/
public function get($i)
{
return $this->skey[$i];
}
/**
* @return int
*/
public function getNumRounds()
{
return $this->numRounds;
}
/**
* @param int $offset
* @return ParagonIE_Sodium_Core_AES_Block
*/
public function getRoundKey($offset)
{
return \ParagonIE_Sodium_Core_AES_Block::fromArray(\array_slice($this->skey, $offset, 8));
}
/**
* Return an expanded key schedule
*
* @return ParagonIE_Sodium_Core_AES_Expanded
*/
public function expand()
{
$exp = new \ParagonIE_Sodium_Core_AES_Expanded(\array_fill(0, 120, 0), $this->numRounds);
$n = $exp->numRounds + 1 << 2;
for ($u = 0, $v = 0; $u < $n; ++$u, $v += 2) {
$x = $y = $this->skey[$u];
$x &= 0x55555555;
$exp->skey[$v] = ($x | $x << 1) & \ParagonIE_Sodium_Core_Util::U32_MAX;
$y &= 0xaaaaaaaa;
$exp->skey[$v + 1] = ($y | $y >> 1) & \ParagonIE_Sodium_Core_Util::U32_MAX;
}
return $exp;
}
}
/**
* @internal This should only be used by sodium_compat
*/

View File

@@ -0,0 +1,668 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_BLAKE2b', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_BLAKE2b
*
* Based on the work of Devi Mandiri in devi/salt.
*/
abstract class ParagonIE_Sodium_Core_BLAKE2b extends \ParagonIE_Sodium_Core_Util
{
/**
* @var SplFixedArray
*/
protected static $iv;
/**
* @var array<int, array<int, int>>
*/
protected static $sigma = array(array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3), array(11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4), array(7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8), array(9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13), array(2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9), array(12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11), array(13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10), array(6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5), array(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0), array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3));
const BLOCKBYTES = 128;
const OUTBYTES = 64;
const KEYBYTES = 64;
/**
* Turn two 32-bit integers into a fixed array representing a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $high
* @param int $low
* @return SplFixedArray
* @psalm-suppress MixedAssignment
*/
public static function new64($high, $low)
{
if (\PHP_INT_SIZE === 4) {
throw new \SodiumException("Error, use 32-bit");
}
$i64 = new \SplFixedArray(2);
$i64[0] = $high & 0xffffffff;
$i64[1] = $low & 0xffffffff;
return $i64;
}
/**
* Convert an arbitrary number into an SplFixedArray of two 32-bit integers
* that represents a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $num
* @return SplFixedArray
*/
protected static function to64($num)
{
list($hi, $lo) = self::numericTo64BitInteger($num);
return self::new64($hi, $lo);
}
/**
* Adds two 64-bit integers together, returning their sum as a SplFixedArray
* containing two 32-bit integers (representing a 64-bit integer).
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @return SplFixedArray
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
protected static function add64($x, $y)
{
if (\PHP_INT_SIZE === 4) {
throw new \SodiumException("Error, use 32-bit");
}
$l = $x[1] + $y[1] & 0xffffffff;
return self::new64((int) ($x[0] + $y[0] + ($l < $x[1] ? 1 : 0)), (int) $l);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @param SplFixedArray $z
* @return SplFixedArray
*/
protected static function add364($x, $y, $z)
{
return self::add64($x, self::add64($y, $z));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
*/
protected static function xor64(\SplFixedArray $x, \SplFixedArray $y)
{
if (\PHP_INT_SIZE === 4) {
throw new \SodiumException("Error, use 32-bit");
}
if (!\is_numeric($x[0])) {
throw new \SodiumException('x[0] is not an integer');
}
if (!\is_numeric($x[1])) {
throw new \SodiumException('x[1] is not an integer');
}
if (!\is_numeric($y[0])) {
throw new \SodiumException('y[0] is not an integer');
}
if (!\is_numeric($y[1])) {
throw new \SodiumException('y[1] is not an integer');
}
return self::new64((int) (($x[0] ^ $y[0]) & 0xffffffff), (int) (($x[1] ^ $y[1]) & 0xffffffff));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $c
* @return SplFixedArray
* @psalm-suppress MixedAssignment
*/
public static function rotr64($x, $c)
{
if (\PHP_INT_SIZE === 4) {
throw new \SodiumException("Error, use 32-bit");
}
if ($c >= 64) {
$c %= 64;
}
if ($c >= 32) {
/** @var int $tmp */
$tmp = $x[0];
$x[0] = $x[1];
$x[1] = $tmp;
$c -= 32;
}
if ($c === 0) {
return $x;
}
$l0 = 0;
$c = 64 - $c;
/** @var int $c */
if ($c < 32) {
$h0 = (int) $x[0] << $c | ((int) $x[1] & (1 << $c) - 1 << 32 - $c) >> 32 - $c;
$l0 = (int) $x[1] << $c;
} else {
$h0 = (int) $x[1] << $c - 32;
}
$h1 = 0;
$c1 = 64 - $c;
if ($c1 < 32) {
$h1 = (int) $x[0] >> $c1;
$l1 = (int) $x[1] >> $c1 | ((int) $x[0] & (1 << $c1) - 1) << 32 - $c1;
} else {
$l1 = (int) $x[0] >> $c1 - 32;
}
return self::new64($h0 | $h1, $l0 | $l1);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @return int
* @psalm-suppress MixedOperand
*/
protected static function flatten64($x)
{
return (int) ($x[0] * 4294967296 + $x[1]);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @return SplFixedArray
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayOffset
*/
protected static function load64(\SplFixedArray $x, $i)
{
/** @var int $l */
$l = (int) $x[$i] | (int) $x[$i + 1] << 8 | (int) $x[$i + 2] << 16 | (int) $x[$i + 3] << 24;
/** @var int $h */
$h = (int) $x[$i + 4] | (int) $x[$i + 5] << 8 | (int) $x[$i + 6] << 16 | (int) $x[$i + 7] << 24;
return self::new64($h, $l);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @param SplFixedArray $u
* @return void
* @psalm-suppress MixedAssignment
*/
protected static function store64(\SplFixedArray $x, $i, \SplFixedArray $u)
{
$maxLength = $x->getSize() - 1;
for ($j = 0; $j < 8; ++$j) {
/*
[0, 1, 2, 3, 4, 5, 6, 7]
... becomes ...
[0, 0, 0, 0, 1, 1, 1, 1]
*/
/** @var int $uIdx */
$uIdx = (7 - $j & 4) >> 2;
$x[$i] = (int) $u[$uIdx] & 0xff;
if (++$i > $maxLength) {
return;
}
/** @psalm-suppress MixedOperand */
$u[$uIdx] >>= 8;
}
}
/**
* This just sets the $iv static variable.
*
* @internal You should not use this directly from another application
*
* @return void
*/
public static function pseudoConstructor()
{
static $called = \false;
if ($called) {
return;
}
self::$iv = new \SplFixedArray(8);
self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908);
self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b);
self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b);
self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1);
self::$iv[4] = self::new64(0x510e527f, 0xade682d1);
self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f);
self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b);
self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179);
$called = \true;
}
/**
* Returns a fresh BLAKE2 context.
*
* @internal You should not use this directly from another application
*
* @return SplFixedArray
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
protected static function context()
{
$ctx = new \SplFixedArray(6);
$ctx[0] = new \SplFixedArray(8);
// h
$ctx[1] = new \SplFixedArray(2);
// t
$ctx[2] = new \SplFixedArray(2);
// f
$ctx[3] = new \SplFixedArray(256);
// buf
$ctx[4] = 0;
// buflen
$ctx[5] = 0;
// last_node (uint8_t)
for ($i = 8; $i--;) {
$ctx[0][$i] = self::$iv[$i];
}
for ($i = 256; $i--;) {
$ctx[3][$i] = 0;
}
$zero = self::new64(0, 0);
$ctx[1][0] = $zero;
$ctx[1][1] = $zero;
$ctx[2][0] = $zero;
$ctx[2][1] = $zero;
return $ctx;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $buf
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
protected static function compress(\SplFixedArray $ctx, \SplFixedArray $buf)
{
$m = new \SplFixedArray(16);
$v = new \SplFixedArray(16);
for ($i = 16; $i--;) {
$m[$i] = self::load64($buf, $i << 3);
}
for ($i = 8; $i--;) {
$v[$i] = $ctx[0][$i];
}
$v[8] = self::$iv[0];
$v[9] = self::$iv[1];
$v[10] = self::$iv[2];
$v[11] = self::$iv[3];
$v[12] = self::xor64($ctx[1][0], self::$iv[4]);
$v[13] = self::xor64($ctx[1][1], self::$iv[5]);
$v[14] = self::xor64($ctx[2][0], self::$iv[6]);
$v[15] = self::xor64($ctx[2][1], self::$iv[7]);
for ($r = 0; $r < 12; ++$r) {
$v = self::G($r, 0, 0, 4, 8, 12, $v, $m);
$v = self::G($r, 1, 1, 5, 9, 13, $v, $m);
$v = self::G($r, 2, 2, 6, 10, 14, $v, $m);
$v = self::G($r, 3, 3, 7, 11, 15, $v, $m);
$v = self::G($r, 4, 0, 5, 10, 15, $v, $m);
$v = self::G($r, 5, 1, 6, 11, 12, $v, $m);
$v = self::G($r, 6, 2, 7, 8, 13, $v, $m);
$v = self::G($r, 7, 3, 4, 9, 14, $v, $m);
}
for ($i = 8; $i--;) {
$ctx[0][$i] = self::xor64($ctx[0][$i], self::xor64($v[$i], $v[$i + 8]));
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $r
* @param int $i
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @param SplFixedArray $v
* @param SplFixedArray $m
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayOffset
*/
public static function G($r, $i, $a, $b, $c, $d, \SplFixedArray $v, \SplFixedArray $m)
{
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i << 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24);
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i << 1) + 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param int $inc
* @return void
* @throws SodiumException
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
public static function increment_counter($ctx, $inc)
{
if ($inc < 0) {
throw new \SodiumException('Increasing by a negative number makes no sense.');
}
$t = self::to64($inc);
# S->t is $ctx[1] in our implementation
# S->t[0] = ( uint64_t )( t >> 0 );
$ctx[1][0] = self::add64($ctx[1][0], $t);
# S->t[1] += ( S->t[0] < inc );
if (self::flatten64($ctx[1][0]) < $inc) {
$ctx[1][1] = self::add64($ctx[1][1], self::to64(1));
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $p
* @param int $plen
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedOperand
*/
public static function update(\SplFixedArray $ctx, \SplFixedArray $p, $plen)
{
self::pseudoConstructor();
$offset = 0;
while ($plen > 0) {
$left = $ctx[4];
$fill = 256 - $left;
if ($plen > $fill) {
# memcpy( S->buf + left, in, fill ); /* Fill buffer */
for ($i = $fill; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
# S->buflen += fill;
$ctx[4] += $fill;
# blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
self::increment_counter($ctx, 128);
# blake2b_compress( S, S->buf ); /* Compress */
self::compress($ctx, $ctx[3]);
# memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */
for ($i = 128; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
# S->buflen -= BLAKE2B_BLOCKBYTES;
$ctx[4] -= 128;
# in += fill;
$offset += $fill;
# inlen -= fill;
$plen -= $fill;
} else {
for ($i = $plen; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
$ctx[4] += $plen;
$offset += $plen;
$plen -= $plen;
}
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $out
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedOperand
*/
public static function finish(\SplFixedArray $ctx, \SplFixedArray $out)
{
self::pseudoConstructor();
if ($ctx[4] > 128) {
self::increment_counter($ctx, 128);
self::compress($ctx, $ctx[3]);
$ctx[4] -= 128;
if ($ctx[4] > 128) {
throw new \SodiumException('Failed to assert that buflen <= 128 bytes');
}
for ($i = $ctx[4]; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
}
self::increment_counter($ctx, $ctx[4]);
$ctx[2][0] = self::new64(0xffffffff, 0xffffffff);
for ($i = 256 - $ctx[4]; $i--;) {
$ctx[3][$i + $ctx[4]] = 0;
}
self::compress($ctx, $ctx[3]);
$i = (int) (($out->getSize() - 1) / 8);
for (; $i >= 0; --$i) {
self::store64($out, $i << 3, $ctx[0][$i]);
}
return $out;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray|null $key
* @param int $outlen
* @param SplFixedArray|null $salt
* @param SplFixedArray|null $personal
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
public static function init($key = null, $outlen = 64, $salt = null, $personal = null)
{
self::pseudoConstructor();
$klen = 0;
if ($key !== null) {
if (\count($key) > 64) {
throw new \SodiumException('Invalid key size');
}
$klen = \count($key);
}
if ($outlen > 64) {
throw new \SodiumException('Invalid output size');
}
$ctx = self::context();
$p = new \SplFixedArray(64);
// Zero our param buffer...
for ($i = 64; --$i;) {
$p[$i] = 0;
}
$p[0] = $outlen;
// digest_length
$p[1] = $klen;
// key_length
$p[2] = 1;
// fanout
$p[3] = 1;
// depth
if ($salt instanceof \SplFixedArray) {
// salt: [32] through [47]
for ($i = 0; $i < 16; ++$i) {
$p[32 + $i] = (int) $salt[$i];
}
}
if ($personal instanceof \SplFixedArray) {
// personal: [48] through [63]
for ($i = 0; $i < 16; ++$i) {
$p[48 + $i] = (int) $personal[$i];
}
}
$ctx[0][0] = self::xor64($ctx[0][0], self::load64($p, 0));
if ($salt instanceof \SplFixedArray || $personal instanceof \SplFixedArray) {
// We need to do what blake2b_init_param() does:
for ($i = 1; $i < 8; ++$i) {
$ctx[0][$i] = self::xor64($ctx[0][$i], self::load64($p, $i << 3));
}
}
if ($klen > 0 && $key instanceof \SplFixedArray) {
$block = new \SplFixedArray(128);
for ($i = 128; $i--;) {
$block[$i] = 0;
}
for ($i = $klen; $i--;) {
$block[$i] = $key[$i];
}
self::update($ctx, $block, 128);
$ctx[4] = 128;
}
return $ctx;
}
/**
* Convert a string into an SplFixedArray of integers
*
* @internal You should not use this directly from another application
*
* @param string $str
* @return SplFixedArray
* @psalm-suppress MixedArgumentTypeCoercion
*/
public static function stringToSplFixedArray($str = '')
{
$values = \unpack('C*', $str);
return \SplFixedArray::fromArray(\array_values($values));
}
/**
* Convert an SplFixedArray of integers into a string
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $a
* @return string
* @throws TypeError
*/
public static function SplFixedArrayToString(\SplFixedArray $a)
{
/**
* @var array<int, int|string> $arr
*/
$arr = $a->toArray();
$c = $a->count();
\array_unshift($arr, \str_repeat('C', $c));
return (string) \call_user_func_array('pack', $arr);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @return string
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedMethodCall
*/
public static function contextToString(\SplFixedArray $ctx)
{
$str = '';
/** @var array<int, array<int, int>> $ctxA */
$ctxA = $ctx[0]->toArray();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$str .= self::store32_le($ctxA[$i][1]);
$str .= self::store32_le($ctxA[$i][0]);
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctxA = $ctx[$i]->toArray();
$str .= self::store32_le($ctxA[0][1]);
$str .= self::store32_le($ctxA[0][0]);
$str .= self::store32_le($ctxA[1][1]);
$str .= self::store32_le($ctxA[1][0]);
}
# uint8_t buf[2 * 128];
$str .= self::SplFixedArrayToString($ctx[3]);
/** @var int $ctx4 */
$ctx4 = (int) $ctx[4];
# size_t buflen;
$str .= \implode('', array(self::intToChr($ctx4 & 0xff), self::intToChr($ctx4 >> 8 & 0xff), self::intToChr($ctx4 >> 16 & 0xff), self::intToChr($ctx4 >> 24 & 0xff), self::intToChr($ctx4 >> 32 & 0xff), self::intToChr($ctx4 >> 40 & 0xff), self::intToChr($ctx4 >> 48 & 0xff), self::intToChr($ctx4 >> 56 & 0xff)));
# uint8_t last_node;
return $str . self::intToChr($ctx[5]) . \str_repeat("\x00", 23);
}
/**
* Creates an SplFixedArray containing other SplFixedArray elements, from
* a string (compatible with \Sodium\crypto_generichash_{init, update, final})
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAssignment
*/
public static function stringToContext($string)
{
$ctx = self::context();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$ctx[0][$i] = \SplFixedArray::fromArray(array(self::load_4(self::substr($string, ($i << 3) + 4, 4)), self::load_4(self::substr($string, ($i << 3) + 0, 4))));
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctx[$i][1] = \SplFixedArray::fromArray(array(self::load_4(self::substr($string, 76 + ($i - 1 << 4), 4)), self::load_4(self::substr($string, 72 + ($i - 1 << 4), 4))));
$ctx[$i][0] = \SplFixedArray::fromArray(array(self::load_4(self::substr($string, 68 + ($i - 1 << 4), 4)), self::load_4(self::substr($string, 64 + ($i - 1 << 4), 4))));
}
# uint8_t buf[2 * 128];
$ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256));
# uint8_t buf[2 * 128];
$int = 0;
for ($i = 0; $i < 8; ++$i) {
$int |= self::chrToInt($string[352 + $i]) << ($i << 3);
}
$ctx[4] = $int;
return $ctx;
}
}
/**
* Class ParagonIE_Sodium_Core_BLAKE2b
*
* Based on the work of Devi Mandiri in devi/salt.
*/

View File

@@ -0,0 +1,208 @@
<?php
/**
* Class ParagonIE_Sodium_Core_Base64
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*/
class ParagonIE_Sodium_Core_Base64_Original
{
// COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
/**
* Encode into Base64
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encode($src)
{
return self::doEncode($src, \true);
}
/**
* Encode into Base64, no = padding
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encodeUnpadded($src)
{
return self::doEncode($src, \false);
}
/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
* @throws TypeError
*/
protected static function doEncode($src, $pad = \true)
{
$dest = '';
$srcLen = \ParagonIE_Sodium_Core_Util::strlen($src);
// Main loop (no padding):
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C*', \ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits(($b0 << 4 | $b1 >> 4) & 63) . self::encode6Bits(($b1 << 2 | $b2 >> 6) & 63) . self::encode6Bits($b2 & 63);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C*', \ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits(($b0 << 4 | $b1 >> 4) & 63) . self::encode6Bits($b1 << 2 & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits($b0 << 4 & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}
/**
* decode from base64 into binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $src
* @param bool $strictPadding
* @return string
* @throws RangeException
* @throws TypeError
* @psalm-suppress RedundantCondition
*/
public static function decode($src, $strictPadding = \false)
{
// Remove padding
$srcLen = \ParagonIE_Sodium_Core_Util::strlen($src);
if ($srcLen === 0) {
return '';
}
if ($strictPadding) {
if (($srcLen & 3) === 0) {
if ($src[$srcLen - 1] === '=') {
$srcLen--;
if ($src[$srcLen - 1] === '=') {
$srcLen--;
}
}
}
if (($srcLen & 3) === 1) {
throw new \RangeException('Incorrect padding');
}
if ($src[$srcLen - 1] === '=') {
throw new \RangeException('Incorrect padding');
}
} else {
$src = \rtrim($src, '=');
$srcLen = \ParagonIE_Sodium_Core_Util::strlen($src);
}
$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C*', \ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
$c0 = self::decode6Bits($chunk[1]);
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$c3 = self::decode6Bits($chunk[4]);
$dest .= \pack('CCC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff, ($c2 << 6 | $c3) & 0xff);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C*', \ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$c0 = self::decode6Bits($chunk[1]);
if ($i + 2 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$dest .= \pack('CC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$dest .= \pack('C', ($c0 << 2 | $c1 >> 4) & 0xff);
$err |= ($c0 | $c1) >> 8;
} elseif ($i < $srcLen && $strictPadding) {
$err |= 1;
}
}
/** @var bool $check */
$check = $err === 0;
if (!$check) {
throw new \RangeException('Base64::decode() only expects characters in the correct base64 alphabet');
}
return $dest;
}
// COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
$ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 64;
// if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
$ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 70;
// if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
$ret += (0x2f - $src & $src - 0x3a) >> 8 & $src + 5;
// if ($src == 0x2b) $ret += 62 + 1;
$ret += (0x2a - $src & $src - 0x2c) >> 8 & 63;
// if ($src == 0x2f) ret += 63 + 1;
$ret += (0x2e - $src & $src - 0x30) >> 8 & 64;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$diff = 0x41;
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
$diff += 25 - $src >> 8 & 6;
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
$diff -= 51 - $src >> 8 & 75;
// if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15
$diff -= 61 - $src >> 8 & 15;
// if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3
$diff += 62 - $src >> 8 & 3;
return \pack('C', $src + $diff);
}
}
/**
* Class ParagonIE_Sodium_Core_Base64
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*/

View File

@@ -0,0 +1,208 @@
<?php
/**
* Class ParagonIE_Sodium_Core_Base64UrlSafe
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*/
class ParagonIE_Sodium_Core_Base64_UrlSafe
{
// COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
/**
* Encode into Base64
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encode($src)
{
return self::doEncode($src, \true);
}
/**
* Encode into Base64, no = padding
*
* Base64 character set "[A-Z][a-z][0-9]+/"
*
* @param string $src
* @return string
* @throws TypeError
*/
public static function encodeUnpadded($src)
{
return self::doEncode($src, \false);
}
/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
* @throws TypeError
*/
protected static function doEncode($src, $pad = \true)
{
$dest = '';
$srcLen = \ParagonIE_Sodium_Core_Util::strlen($src);
// Main loop (no padding):
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C*', \ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
$b0 = $chunk[1];
$b1 = $chunk[2];
$b2 = $chunk[3];
$dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits(($b0 << 4 | $b1 >> 4) & 63) . self::encode6Bits(($b1 << 2 | $b2 >> 6) & 63) . self::encode6Bits($b2 & 63);
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C*', \ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$b0 = $chunk[1];
if ($i + 1 < $srcLen) {
$b1 = $chunk[2];
$dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits(($b0 << 4 | $b1 >> 4) & 63) . self::encode6Bits($b1 << 2 & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .= self::encode6Bits($b0 >> 2) . self::encode6Bits($b0 << 4 & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}
/**
* decode from base64 into binary
*
* Base64 character set "./[A-Z][a-z][0-9]"
*
* @param string $src
* @param bool $strictPadding
* @return string
* @throws RangeException
* @throws TypeError
* @psalm-suppress RedundantCondition
*/
public static function decode($src, $strictPadding = \false)
{
// Remove padding
$srcLen = \ParagonIE_Sodium_Core_Util::strlen($src);
if ($srcLen === 0) {
return '';
}
if ($strictPadding) {
if (($srcLen & 3) === 0) {
if ($src[$srcLen - 1] === '=') {
$srcLen--;
if ($src[$srcLen - 1] === '=') {
$srcLen--;
}
}
}
if (($srcLen & 3) === 1) {
throw new \RangeException('Incorrect padding');
}
if ($src[$srcLen - 1] === '=') {
throw new \RangeException('Incorrect padding');
}
} else {
$src = \rtrim($src, '=');
$srcLen = \ParagonIE_Sodium_Core_Util::strlen($src);
}
$err = 0;
$dest = '';
// Main loop (no padding):
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C*', \ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
$c0 = self::decode6Bits($chunk[1]);
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$c3 = self::decode6Bits($chunk[4]);
$dest .= \pack('CCC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff, ($c2 << 6 | $c3) & 0xff);
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
}
// The last chunk, which may have padding:
if ($i < $srcLen) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C*', \ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
$c0 = self::decode6Bits($chunk[1]);
if ($i + 2 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$c2 = self::decode6Bits($chunk[3]);
$dest .= \pack('CC', ($c0 << 2 | $c1 >> 4) & 0xff, ($c1 << 4 | $c2 >> 2) & 0xff);
$err |= ($c0 | $c1 | $c2) >> 8;
} elseif ($i + 1 < $srcLen) {
$c1 = self::decode6Bits($chunk[2]);
$dest .= \pack('C', ($c0 << 2 | $c1 >> 4) & 0xff);
$err |= ($c0 | $c1) >> 8;
} elseif ($i < $srcLen && $strictPadding) {
$err |= 1;
}
}
/** @var bool $check */
$check = $err === 0;
if (!$check) {
throw new \RangeException('Base64::decode() only expects characters in the correct base64 alphabet');
}
return $dest;
}
// COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
/**
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
* into 8-bit integers.
*
* Base64 character set:
* [A-Z] [a-z] [0-9] + /
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
*
* @param int $src
* @return int
*/
protected static function decode6Bits($src)
{
$ret = -1;
// if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
$ret += (0x40 - $src & $src - 0x5b) >> 8 & $src - 64;
// if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
$ret += (0x60 - $src & $src - 0x7b) >> 8 & $src - 70;
// if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
$ret += (0x2f - $src & $src - 0x3a) >> 8 & $src + 5;
// if ($src == 0x2c) $ret += 62 + 1;
$ret += (0x2c - $src & $src - 0x2e) >> 8 & 63;
// if ($src == 0x5f) ret += 63 + 1;
$ret += (0x5e - $src & $src - 0x60) >> 8 & 64;
return $ret;
}
/**
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
* into 6-bit integers.
*
* @param int $src
* @return string
*/
protected static function encode6Bits($src)
{
$diff = 0x41;
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
$diff += 25 - $src >> 8 & 6;
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
$diff -= 51 - $src >> 8 & 75;
// if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
$diff -= 61 - $src >> 8 & 13;
// if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
$diff += 62 - $src >> 8 & 49;
return \pack('C', $src + $diff);
}
}
/**
* Class ParagonIE_Sodium_Core_Base64UrlSafe
*
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
*/

View File

@@ -0,0 +1,338 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_ChaCha20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20
*/
class ParagonIE_Sodium_Core_ChaCha20 extends \ParagonIE_Sodium_Core_Util
{
/**
* Bitwise left rotation
*
* @internal You should not use this directly from another application
*
* @param int $v
* @param int $n
* @return int
*/
public static function rotate($v, $n)
{
$v &= 0xffffffff;
$n &= 31;
return (int) (0xffffffff & ($v << $n | $v >> 32 - $n));
}
/**
* The ChaCha20 quarter round function. Works on four 32-bit integers.
*
* @internal You should not use this directly from another application
*
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @return array<int, int>
*/
protected static function quarterRound($a, $b, $c, $d)
{
# a = PLUS(a,b); d = ROTATE(XOR(d,a),16);
/** @var int $a */
$a = $a + $b & 0xffffffff;
$d = self::rotate($d ^ $a, 16);
# c = PLUS(c,d); b = ROTATE(XOR(b,c),12);
/** @var int $c */
$c = $c + $d & 0xffffffff;
$b = self::rotate($b ^ $c, 12);
# a = PLUS(a,b); d = ROTATE(XOR(d,a), 8);
/** @var int $a */
$a = $a + $b & 0xffffffff;
$d = self::rotate($d ^ $a, 8);
# c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
/** @var int $c */
$c = $c + $d & 0xffffffff;
$b = self::rotate($b ^ $c, 7);
return array((int) $a, (int) $b, (int) $c, (int) $d);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx
* @param string $message
*
* @return string
* @throws TypeError
* @throws SodiumException
*/
public static function encryptBytes(\ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx, $message = '')
{
$bytes = self::strlen($message);
/*
j0 = ctx->input[0];
j1 = ctx->input[1];
j2 = ctx->input[2];
j3 = ctx->input[3];
j4 = ctx->input[4];
j5 = ctx->input[5];
j6 = ctx->input[6];
j7 = ctx->input[7];
j8 = ctx->input[8];
j9 = ctx->input[9];
j10 = ctx->input[10];
j11 = ctx->input[11];
j12 = ctx->input[12];
j13 = ctx->input[13];
j14 = ctx->input[14];
j15 = ctx->input[15];
*/
$j0 = (int) $ctx[0];
$j1 = (int) $ctx[1];
$j2 = (int) $ctx[2];
$j3 = (int) $ctx[3];
$j4 = (int) $ctx[4];
$j5 = (int) $ctx[5];
$j6 = (int) $ctx[6];
$j7 = (int) $ctx[7];
$j8 = (int) $ctx[8];
$j9 = (int) $ctx[9];
$j10 = (int) $ctx[10];
$j11 = (int) $ctx[11];
$j12 = (int) $ctx[12];
$j13 = (int) $ctx[13];
$j14 = (int) $ctx[14];
$j15 = (int) $ctx[15];
$c = '';
for (;;) {
if ($bytes < 64) {
$message .= \str_repeat("\x00", 64 - $bytes);
}
$x0 = (int) $j0;
$x1 = (int) $j1;
$x2 = (int) $j2;
$x3 = (int) $j3;
$x4 = (int) $j4;
$x5 = (int) $j5;
$x6 = (int) $j6;
$x7 = (int) $j7;
$x8 = (int) $j8;
$x9 = (int) $j9;
$x10 = (int) $j10;
$x11 = (int) $j11;
$x12 = (int) $j12;
$x13 = (int) $j13;
$x14 = (int) $j14;
$x15 = (int) $j15;
# for (i = 20; i > 0; i -= 2) {
for ($i = 20; $i > 0; $i -= 2) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
}
/*
x0 = PLUS(x0, j0);
x1 = PLUS(x1, j1);
x2 = PLUS(x2, j2);
x3 = PLUS(x3, j3);
x4 = PLUS(x4, j4);
x5 = PLUS(x5, j5);
x6 = PLUS(x6, j6);
x7 = PLUS(x7, j7);
x8 = PLUS(x8, j8);
x9 = PLUS(x9, j9);
x10 = PLUS(x10, j10);
x11 = PLUS(x11, j11);
x12 = PLUS(x12, j12);
x13 = PLUS(x13, j13);
x14 = PLUS(x14, j14);
x15 = PLUS(x15, j15);
*/
/** @var int $x0 */
$x0 = ($x0 & 0xffffffff) + $j0;
/** @var int $x1 */
$x1 = ($x1 & 0xffffffff) + $j1;
/** @var int $x2 */
$x2 = ($x2 & 0xffffffff) + $j2;
/** @var int $x3 */
$x3 = ($x3 & 0xffffffff) + $j3;
/** @var int $x4 */
$x4 = ($x4 & 0xffffffff) + $j4;
/** @var int $x5 */
$x5 = ($x5 & 0xffffffff) + $j5;
/** @var int $x6 */
$x6 = ($x6 & 0xffffffff) + $j6;
/** @var int $x7 */
$x7 = ($x7 & 0xffffffff) + $j7;
/** @var int $x8 */
$x8 = ($x8 & 0xffffffff) + $j8;
/** @var int $x9 */
$x9 = ($x9 & 0xffffffff) + $j9;
/** @var int $x10 */
$x10 = ($x10 & 0xffffffff) + $j10;
/** @var int $x11 */
$x11 = ($x11 & 0xffffffff) + $j11;
/** @var int $x12 */
$x12 = ($x12 & 0xffffffff) + $j12;
/** @var int $x13 */
$x13 = ($x13 & 0xffffffff) + $j13;
/** @var int $x14 */
$x14 = ($x14 & 0xffffffff) + $j14;
/** @var int $x15 */
$x15 = ($x15 & 0xffffffff) + $j15;
/*
x0 = XOR(x0, LOAD32_LE(m + 0));
x1 = XOR(x1, LOAD32_LE(m + 4));
x2 = XOR(x2, LOAD32_LE(m + 8));
x3 = XOR(x3, LOAD32_LE(m + 12));
x4 = XOR(x4, LOAD32_LE(m + 16));
x5 = XOR(x5, LOAD32_LE(m + 20));
x6 = XOR(x6, LOAD32_LE(m + 24));
x7 = XOR(x7, LOAD32_LE(m + 28));
x8 = XOR(x8, LOAD32_LE(m + 32));
x9 = XOR(x9, LOAD32_LE(m + 36));
x10 = XOR(x10, LOAD32_LE(m + 40));
x11 = XOR(x11, LOAD32_LE(m + 44));
x12 = XOR(x12, LOAD32_LE(m + 48));
x13 = XOR(x13, LOAD32_LE(m + 52));
x14 = XOR(x14, LOAD32_LE(m + 56));
x15 = XOR(x15, LOAD32_LE(m + 60));
*/
$x0 ^= self::load_4(self::substr($message, 0, 4));
$x1 ^= self::load_4(self::substr($message, 4, 4));
$x2 ^= self::load_4(self::substr($message, 8, 4));
$x3 ^= self::load_4(self::substr($message, 12, 4));
$x4 ^= self::load_4(self::substr($message, 16, 4));
$x5 ^= self::load_4(self::substr($message, 20, 4));
$x6 ^= self::load_4(self::substr($message, 24, 4));
$x7 ^= self::load_4(self::substr($message, 28, 4));
$x8 ^= self::load_4(self::substr($message, 32, 4));
$x9 ^= self::load_4(self::substr($message, 36, 4));
$x10 ^= self::load_4(self::substr($message, 40, 4));
$x11 ^= self::load_4(self::substr($message, 44, 4));
$x12 ^= self::load_4(self::substr($message, 48, 4));
$x13 ^= self::load_4(self::substr($message, 52, 4));
$x14 ^= self::load_4(self::substr($message, 56, 4));
$x15 ^= self::load_4(self::substr($message, 60, 4));
/*
j12 = PLUSONE(j12);
if (!j12) {
j13 = PLUSONE(j13);
}
*/
++$j12;
if ($j12 & 0xf0000000) {
throw new \SodiumException('Overflow');
}
/*
STORE32_LE(c + 0, x0);
STORE32_LE(c + 4, x1);
STORE32_LE(c + 8, x2);
STORE32_LE(c + 12, x3);
STORE32_LE(c + 16, x4);
STORE32_LE(c + 20, x5);
STORE32_LE(c + 24, x6);
STORE32_LE(c + 28, x7);
STORE32_LE(c + 32, x8);
STORE32_LE(c + 36, x9);
STORE32_LE(c + 40, x10);
STORE32_LE(c + 44, x11);
STORE32_LE(c + 48, x12);
STORE32_LE(c + 52, x13);
STORE32_LE(c + 56, x14);
STORE32_LE(c + 60, x15);
*/
$block = self::store32_le((int) ($x0 & 0xffffffff)) . self::store32_le((int) ($x1 & 0xffffffff)) . self::store32_le((int) ($x2 & 0xffffffff)) . self::store32_le((int) ($x3 & 0xffffffff)) . self::store32_le((int) ($x4 & 0xffffffff)) . self::store32_le((int) ($x5 & 0xffffffff)) . self::store32_le((int) ($x6 & 0xffffffff)) . self::store32_le((int) ($x7 & 0xffffffff)) . self::store32_le((int) ($x8 & 0xffffffff)) . self::store32_le((int) ($x9 & 0xffffffff)) . self::store32_le((int) ($x10 & 0xffffffff)) . self::store32_le((int) ($x11 & 0xffffffff)) . self::store32_le((int) ($x12 & 0xffffffff)) . self::store32_le((int) ($x13 & 0xffffffff)) . self::store32_le((int) ($x14 & 0xffffffff)) . self::store32_le((int) ($x15 & 0xffffffff));
/* Partial block */
if ($bytes < 64) {
$c .= self::substr($block, 0, $bytes);
break;
}
/* Full block */
$c .= $block;
$bytes -= 64;
if ($bytes <= 0) {
break;
}
$message = self::substr($message, 64);
}
/* end for(;;) loop */
$ctx[12] = $j12;
$ctx[13] = $j13;
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key = '')
{
return self::encryptBytes(new \ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce), \str_repeat("\x00", $len));
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStream($len, $nonce = '', $key = '')
{
return self::encryptBytes(new \ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce), \str_repeat("\x00", $len));
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(new \ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce, $ic), $message);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(new \ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce, $ic), $message);
}
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20
*/

View File

@@ -0,0 +1,118 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_Ctx
*/
class ParagonIE_Sodium_Core_ChaCha20_Ctx extends \ParagonIE_Sodium_Core_Util implements \ArrayAccess
{
/**
* @var SplFixedArray internally, <int, int>
*/
protected $container;
/**
* ParagonIE_Sodium_Core_ChaCha20_Ctx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 8 0x00 bytes.
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '', $iv = '', $counter = '')
{
if (self::strlen($key) !== 32) {
throw new \InvalidArgumentException('ChaCha20 expects a 256-bit key.');
}
if (self::strlen($iv) !== 8) {
throw new \InvalidArgumentException('ChaCha20 expects a 64-bit nonce.');
}
$this->container = new \SplFixedArray(16);
/* "expand 32-byte k" as per ChaCha20 spec */
$this->container[0] = 0x61707865;
$this->container[1] = 0x3320646e;
$this->container[2] = 0x79622d32;
$this->container[3] = 0x6b206574;
$this->container[4] = self::load_4(self::substr($key, 0, 4));
$this->container[5] = self::load_4(self::substr($key, 4, 4));
$this->container[6] = self::load_4(self::substr($key, 8, 4));
$this->container[7] = self::load_4(self::substr($key, 12, 4));
$this->container[8] = self::load_4(self::substr($key, 16, 4));
$this->container[9] = self::load_4(self::substr($key, 20, 4));
$this->container[10] = self::load_4(self::substr($key, 24, 4));
$this->container[11] = self::load_4(self::substr($key, 28, 4));
if (empty($counter)) {
$this->container[12] = 0;
$this->container[13] = 0;
} else {
$this->container[12] = self::load_4(self::substr($counter, 0, 4));
$this->container[13] = self::load_4(self::substr($counter, 4, 4));
}
$this->container[14] = self::load_4(self::substr($iv, 0, 4));
$this->container[15] = self::load_4(self::substr($iv, 4, 4));
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @param int $value
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!\is_int($offset)) {
throw new \InvalidArgumentException('Expected an integer');
}
if (!\is_int($value)) {
throw new \InvalidArgumentException('Expected an integer');
}
$this->container[$offset] = $value;
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return mixed|null
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_Ctx
*/

View File

@@ -0,0 +1,41 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_IetfCtx
*/
class ParagonIE_Sodium_Core_ChaCha20_IetfCtx extends \ParagonIE_Sodium_Core_ChaCha20_Ctx
{
/**
* ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 4 0x00 bytes.
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '', $iv = '', $counter = '')
{
if (self::strlen($iv) !== 12) {
throw new \InvalidArgumentException('ChaCha20 expects a 96-bit nonce in IETF mode.');
}
parent::__construct($key, self::substr($iv, 0, 8), $counter);
if (!empty($counter)) {
$this->container[12] = self::load_4(self::substr($counter, 0, 4));
}
$this->container[13] = self::load_4(self::substr($iv, 0, 4));
$this->container[14] = self::load_4(self::substr($iv, 4, 4));
$this->container[15] = self::load_4(self::substr($iv, 8, 4));
}
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_IetfCtx
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,125 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Curve25519_Fe', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Fe
*
* This represents a Field Element
*/
class ParagonIE_Sodium_Core_Curve25519_Fe implements \ArrayAccess
{
/**
* @var array<int, int>
*/
protected $container = array();
/**
* @var int
*/
protected $size = 10;
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @param bool $save_indexes
* @return self
*/
public static function fromArray($array, $save_indexes = null)
{
$count = \count($array);
if ($save_indexes) {
$keys = \array_keys($array);
} else {
$keys = \range(0, $count - 1);
}
$array = \array_values($array);
/** @var array<int, int> $keys */
$obj = new \ParagonIE_Sodium_Core_Curve25519_Fe();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($keys[$i], $array[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($i, $array[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param int|null $offset
* @param int $value
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!\is_int($value)) {
throw new \InvalidArgumentException('Expected an integer');
}
if (\is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return int
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
if (!isset($this->container[$offset])) {
$this->container[$offset] = 0;
}
return (int) $this->container[$offset];
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
return array(\implode(', ', $this->container));
}
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Fe
*
* This represents a Field Element
*/

View File

@@ -0,0 +1,73 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Cached', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Cached
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_Cached
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $YplusX;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $YminusX;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $T2d;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_Cached constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YplusX
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $YminusX
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $Z
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $T2d
*/
public function __construct($YplusX = null, $YminusX = null, $Z = null, $T2d = null)
{
if ($YplusX === null) {
$YplusX = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$YplusX instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->YplusX = $YplusX;
if ($YminusX === null) {
$YminusX = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$YminusX instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->YminusX = $YminusX;
if ($Z === null) {
$Z = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$Z instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Z = $Z;
if ($T2d === null) {
$T2d = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$T2d instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->T2d = $T2d;
}
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Cached
*/

View File

@@ -0,0 +1,73 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P1p1', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t
*/
public function __construct($x = null, $y = null, $z = null, $t = null)
{
if ($x === null) {
$x = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$x instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->X = $x;
if ($y === null) {
$y = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$y instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Y = $y;
if ($z === null) {
$z = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$z instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Z = $z;
if ($t === null) {
$t = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$t instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->T = $t;
}
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/

View File

@@ -0,0 +1,61 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P2', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P2
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P2 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z
*/
public function __construct($x = null, $y = null, $z = null)
{
if ($x === null) {
$x = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$x instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->X = $x;
if ($y === null) {
$y = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$y instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Y = $y;
if ($z === null) {
$z = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$z instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Z = $z;
}
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/

View File

@@ -0,0 +1,73 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P3', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P3
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P3 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core_Curve25519_Fe|null $t
*/
public function __construct($x = null, $y = null, $z = null, $t = null)
{
if ($x === null) {
$x = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$x instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->X = $x;
if ($y === null) {
$y = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$y instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Y = $y;
if ($z === null) {
$z = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$z instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->Z = $z;
if ($t === null) {
$t = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$t instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 4 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->T = $t;
}
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/

View File

@@ -0,0 +1,61 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Precomp', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
{
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $yplusx;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $yminusx;
/**
* @var ParagonIE_Sodium_Core_Curve25519_Fe
*/
public $xy2d;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_Precomp constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $yplusx
* @param ParagonIE_Sodium_Core_Curve25519_Fe $yminusx
* @param ParagonIE_Sodium_Core_Curve25519_Fe $xy2d
*/
public function __construct($yplusx = null, $yminusx = null, $xy2d = null)
{
if ($yplusx === null) {
$yplusx = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$yplusx instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 1 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->yplusx = $yplusx;
if ($yminusx === null) {
$yminusx = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$yminusx instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 2 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->yminusx = $yminusx;
if ($xy2d === null) {
$xy2d = new \ParagonIE_Sodium_Core_Curve25519_Fe();
}
if (!$xy2d instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Argument 3 must be an instance of ParagonIE_Sodium_Core_Curve25519_Fe');
}
$this->xy2d = $xy2d;
}
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
*/

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
# Curve25519 Data Structures
These are PHP implementation of the [structs used in the ref10 curve25519 code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h).

View File

@@ -0,0 +1,414 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Ed25519', \false)) {
return;
}
if (!\class_exists('ParagonIE_Sodium_Core_Curve25519', \false)) {
require_once \dirname(__FILE__) . '/Curve25519.php';
}
/**
* Class ParagonIE_Sodium_Core_Ed25519
*/
abstract class ParagonIE_Sodium_Core_Ed25519 extends \ParagonIE_Sodium_Core_Curve25519
{
const KEYPAIR_BYTES = 96;
const SEED_BYTES = 32;
const SCALAR_BYTES = 32;
/**
* @internal You should not use this directly from another application
*
* @return string (96 bytes)
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function keypair()
{
$seed = \random_bytes(self::SEED_BYTES);
$pk = '';
$sk = '';
self::seed_keypair($pk, $sk, $seed);
return $sk . $pk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $pk
* @param string $sk
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function seed_keypair(&$pk, &$sk, $seed)
{
if (self::strlen($seed) !== self::SEED_BYTES) {
throw new \RangeException('crypto_sign keypair seed must be 32 bytes long');
}
/** @var string $pk */
$pk = self::publickey_from_secretkey($seed);
$sk = $seed . $pk;
return $sk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function secretkey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new \RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 0, 64);
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function publickey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new \RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 64, 32);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function publickey_from_secretkey($sk)
{
/** @var string $sk */
$sk = \hash('sha512', self::substr($sk, 0, 32), \true);
$sk[0] = self::intToChr(self::chrToInt($sk[0]) & 248);
$sk[31] = self::intToChr(self::chrToInt($sk[31]) & 63 | 64);
return self::sk_to_pk($sk);
}
/**
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function pk_to_curve25519($pk)
{
if (self::small_order($pk)) {
throw new \SodiumException('Public key is on a small order');
}
$A = self::ge_frombytes_negate_vartime(self::substr($pk, 0, 32));
$p1 = self::ge_mul_l($A);
if (!self::fe_isnonzero($p1->X)) {
throw new \SodiumException('Unexpected zero result');
}
# fe_1(one_minus_y);
# fe_sub(one_minus_y, one_minus_y, A.Y);
# fe_invert(one_minus_y, one_minus_y);
$one_minux_y = self::fe_invert(self::fe_sub(self::fe_1(), $A->Y));
# fe_1(x);
# fe_add(x, x, A.Y);
# fe_mul(x, x, one_minus_y);
$x = self::fe_mul(self::fe_add(self::fe_1(), $A->Y), $one_minux_y);
# fe_tobytes(curve25519_pk, x);
return self::fe_tobytes($x);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sk_to_pk($sk)
{
return self::ge_p3_tobytes(self::ge_scalarmult_base(self::substr($sk, 0, 32)));
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
/** @var string $signature */
$signature = self::sign_detached($message, $sk);
return $signature . $message;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message A signed message
* @param string $pk Public key
* @return string Message (without signature)
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($message, $pk)
{
/** @var string $signature */
$signature = self::substr($message, 0, 64);
/** @var string $message */
$message = self::substr($message, 64);
if (self::verify_detached($signature, $message, $pk)) {
return $message;
}
throw new \SodiumException('Invalid signature');
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_detached($message, $sk)
{
# crypto_hash_sha512(az, sk, 32);
$az = \hash('sha512', self::substr($sk, 0, 32), \true);
# az[0] &= 248;
# az[31] &= 63;
# az[31] |= 64;
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr(self::chrToInt($az[31]) & 63 | 64);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, az + 32, 32);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, nonce);
$hs = \hash_init('sha512');
\hash_update($hs, self::substr($az, 32, 32));
\hash_update($hs, $message);
$nonceHash = \hash_final($hs, \true);
# memmove(sig + 32, sk + 32, 32);
$pk = self::substr($sk, 32, 32);
# sc_reduce(nonce);
# ge_scalarmult_base(&R, nonce);
# ge_p3_tobytes(sig, &R);
$nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32);
$sig = self::ge_p3_tobytes(self::ge_scalarmult_base($nonce));
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, sig, 64);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, hram);
$hs = \hash_init('sha512');
\hash_update($hs, self::substr($sig, 0, 32));
\hash_update($hs, self::substr($pk, 0, 32));
\hash_update($hs, $message);
$hramHash = \hash_final($hs, \true);
# sc_reduce(hram);
# sc_muladd(sig + 32, hram, az, nonce);
$hram = self::sc_reduce($hramHash);
$sigAfter = self::sc_muladd($hram, $az, $nonce);
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
\ParagonIE_Sodium_Compat::memzero($az);
} catch (\SodiumException $ex) {
$az = null;
}
return $sig;
}
/**
* @internal You should not use this directly from another application
*
* @param string $sig
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_detached($sig, $message, $pk)
{
if (self::strlen($sig) < 64) {
throw new \SodiumException('Signature is too short');
}
if (self::chrToInt($sig[63]) & 240 && self::check_S_lt_L(self::substr($sig, 32, 32))) {
throw new \SodiumException('S < L - Invalid signature');
}
if (self::small_order($sig)) {
throw new \SodiumException('Signature is on too small of an order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new \SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($pk[$i]);
}
if ($d === 0) {
throw new \SodiumException('All zero public key');
}
/** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */
$orig = \ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
\ParagonIE_Sodium_Compat::$fastMult = \true;
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */
$A = self::ge_frombytes_negate_vartime($pk);
/** @var string $hDigest */
$hDigest = \hash('sha512', self::substr($sig, 0, 32) . self::substr($pk, 0, 32) . $message, \true);
/** @var string $h */
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */
$R = self::ge_double_scalarmult_vartime($h, $A, self::substr($sig, 32));
/** @var string $rcheck */
$rcheck = self::ge_tobytes($R);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
\ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* @internal You should not use this directly from another application
*
* @param string $S
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function check_S_lt_L($S)
{
if (self::strlen($S) < 32) {
throw new \SodiumException('Signature must be 32 bytes');
}
$L = array(0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10);
$c = 0;
$n = 1;
$i = 32;
/** @var array<int, int> $L */
do {
--$i;
$x = self::chrToInt($S[$i]);
$c |= $x - $L[$i] >> 8 & $n;
$n &= ($x ^ $L[$i]) - 1 >> 8;
} while ($i !== 0);
return $c === 0;
}
/**
* @param string $R
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function small_order($R)
{
/** @var array<int, array<int, int>> $blocklist */
$blocklist = array(
/* 0 (order 4) */
array(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0),
/* 1 (order 1) */
array(0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0),
/* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x5, 0xd3, 0xc6, 0x33, 0x39, 0xb1, 0x38, 0x2, 0x88, 0x6d, 0x53, 0xfc, 0x5),
/* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0xb, 0x76, 0xd, 0x10, 0x67, 0xf, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x3, 0x7a),
/* p-1 (order 2) */
array(0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x5, 0xd3, 0xc6, 0x33, 0x39, 0xb1, 0x38, 0x2, 0x88, 0x6d, 0x53, 0xfc, 0x85),
/* p (order 4) */
array(0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0xb, 0x76, 0xd, 0x10, 0x67, 0xf, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x3, 0xfa),
/* p+1 (order 1) */
array(0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f),
/* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f),
/* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f),
/* 2p-1 (order 2) */
array(0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
/* 2p (order 4) */
array(0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
/* 2p+1 (order 1) */
array(0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
);
/** @var int $countBlocklist */
$countBlocklist = \count($blocklist);
for ($i = 0; $i < $countBlocklist; ++$i) {
$c = 0;
for ($j = 0; $j < 32; ++$j) {
$c |= self::chrToInt($R[$j]) ^ (int) $blocklist[$i][$j];
}
if ($c === 0) {
return \true;
}
}
return \false;
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function scalar_complement($s)
{
$t_ = self::L . \str_repeat("\x00", 32);
\sodium_increment($t_);
$s_ = $s . \str_repeat("\x00", 32);
\ParagonIE_Sodium_Compat::sub($t_, $s_);
return self::sc_reduce($t_);
}
/**
* @return string
* @throws SodiumException
*/
public static function scalar_random()
{
do {
$r = \ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES);
$r[self::SCALAR_BYTES - 1] = self::intToChr(self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f);
} while (!self::check_S_lt_L($r) || \ParagonIE_Sodium_Compat::is_zero($r));
return $r;
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function scalar_negate($s)
{
$t_ = self::L . \str_repeat("\x00", 32);
$s_ = $s . \str_repeat("\x00", 32);
\ParagonIE_Sodium_Compat::sub($t_, $s_);
return self::sc_reduce($t_);
}
/**
* @param string $a
* @param string $b
* @return string
* @throws SodiumException
*/
public static function scalar_add($a, $b)
{
$a_ = $a . \str_repeat("\x00", 32);
$b_ = $b . \str_repeat("\x00", 32);
\ParagonIE_Sodium_Compat::add($a_, $b_);
return self::sc_reduce($a_);
}
/**
* @param string $x
* @param string $y
* @return string
* @throws SodiumException
*/
public static function scalar_sub($x, $y)
{
$yn = self::scalar_negate($y);
return self::scalar_add($x, $yn);
}
}
/**
* Class ParagonIE_Sodium_Core_Ed25519
*/

View File

@@ -0,0 +1,94 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_HChaCha20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HChaCha20
*/
class ParagonIE_Sodium_Core_HChaCha20 extends \ParagonIE_Sodium_Core_ChaCha20
{
/**
* @param string $in
* @param string $key
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function hChaCha20($in = '', $key = '', $c = null)
{
$ctx = array();
if ($c === null) {
$ctx[0] = 0x61707865;
$ctx[1] = 0x3320646e;
$ctx[2] = 0x79622d32;
$ctx[3] = 0x6b206574;
} else {
$ctx[0] = self::load_4(self::substr($c, 0, 4));
$ctx[1] = self::load_4(self::substr($c, 4, 4));
$ctx[2] = self::load_4(self::substr($c, 8, 4));
$ctx[3] = self::load_4(self::substr($c, 12, 4));
}
$ctx[4] = self::load_4(self::substr($key, 0, 4));
$ctx[5] = self::load_4(self::substr($key, 4, 4));
$ctx[6] = self::load_4(self::substr($key, 8, 4));
$ctx[7] = self::load_4(self::substr($key, 12, 4));
$ctx[8] = self::load_4(self::substr($key, 16, 4));
$ctx[9] = self::load_4(self::substr($key, 20, 4));
$ctx[10] = self::load_4(self::substr($key, 24, 4));
$ctx[11] = self::load_4(self::substr($key, 28, 4));
$ctx[12] = self::load_4(self::substr($in, 0, 4));
$ctx[13] = self::load_4(self::substr($in, 4, 4));
$ctx[14] = self::load_4(self::substr($in, 8, 4));
$ctx[15] = self::load_4(self::substr($in, 12, 4));
return self::hChaCha20Bytes($ctx);
}
/**
* @param array $ctx
* @return string
* @throws TypeError
*/
protected static function hChaCha20Bytes(array $ctx)
{
$x0 = (int) $ctx[0];
$x1 = (int) $ctx[1];
$x2 = (int) $ctx[2];
$x3 = (int) $ctx[3];
$x4 = (int) $ctx[4];
$x5 = (int) $ctx[5];
$x6 = (int) $ctx[6];
$x7 = (int) $ctx[7];
$x8 = (int) $ctx[8];
$x9 = (int) $ctx[9];
$x10 = (int) $ctx[10];
$x11 = (int) $ctx[11];
$x12 = (int) $ctx[12];
$x13 = (int) $ctx[13];
$x14 = (int) $ctx[14];
$x15 = (int) $ctx[15];
for ($i = 0; $i < 10; ++$i) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
}
return self::store32_le((int) ($x0 & 0xffffffff)) . self::store32_le((int) ($x1 & 0xffffffff)) . self::store32_le((int) ($x2 & 0xffffffff)) . self::store32_le((int) ($x3 & 0xffffffff)) . self::store32_le((int) ($x12 & 0xffffffff)) . self::store32_le((int) ($x13 & 0xffffffff)) . self::store32_le((int) ($x14 & 0xffffffff)) . self::store32_le((int) ($x15 & 0xffffffff));
}
}
/**
* Class ParagonIE_Sodium_Core_HChaCha20
*/

View File

@@ -0,0 +1,91 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_HSalsa20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HSalsa20
*/
abstract class ParagonIE_Sodium_Core_HSalsa20 extends \ParagonIE_Sodium_Core_Salsa20
{
/**
* Calculate an hsalsa20 hash of a single block
*
* HSalsa20 doesn't have a counter and will never be used for more than
* one block (used to derive a subkey for xsalsa20).
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function hsalsa20($in, $k, $c = null)
{
if ($c === null) {
$x0 = 0x61707865;
$x5 = 0x3320646e;
$x10 = 0x79622d32;
$x15 = 0x6b206574;
} else {
$x0 = self::load_4(self::substr($c, 0, 4));
$x5 = self::load_4(self::substr($c, 4, 4));
$x10 = self::load_4(self::substr($c, 8, 4));
$x15 = self::load_4(self::substr($c, 12, 4));
}
$x1 = self::load_4(self::substr($k, 0, 4));
$x2 = self::load_4(self::substr($k, 4, 4));
$x3 = self::load_4(self::substr($k, 8, 4));
$x4 = self::load_4(self::substr($k, 12, 4));
$x11 = self::load_4(self::substr($k, 16, 4));
$x12 = self::load_4(self::substr($k, 20, 4));
$x13 = self::load_4(self::substr($k, 24, 4));
$x14 = self::load_4(self::substr($k, 28, 4));
$x6 = self::load_4(self::substr($in, 0, 4));
$x7 = self::load_4(self::substr($in, 4, 4));
$x8 = self::load_4(self::substr($in, 8, 4));
$x9 = self::load_4(self::substr($in, 12, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 ^= self::rotate($x0 + $x12, 7);
$x8 ^= self::rotate($x4 + $x0, 9);
$x12 ^= self::rotate($x8 + $x4, 13);
$x0 ^= self::rotate($x12 + $x8, 18);
$x9 ^= self::rotate($x5 + $x1, 7);
$x13 ^= self::rotate($x9 + $x5, 9);
$x1 ^= self::rotate($x13 + $x9, 13);
$x5 ^= self::rotate($x1 + $x13, 18);
$x14 ^= self::rotate($x10 + $x6, 7);
$x2 ^= self::rotate($x14 + $x10, 9);
$x6 ^= self::rotate($x2 + $x14, 13);
$x10 ^= self::rotate($x6 + $x2, 18);
$x3 ^= self::rotate($x15 + $x11, 7);
$x7 ^= self::rotate($x3 + $x15, 9);
$x11 ^= self::rotate($x7 + $x3, 13);
$x15 ^= self::rotate($x11 + $x7, 18);
$x1 ^= self::rotate($x0 + $x3, 7);
$x2 ^= self::rotate($x1 + $x0, 9);
$x3 ^= self::rotate($x2 + $x1, 13);
$x0 ^= self::rotate($x3 + $x2, 18);
$x6 ^= self::rotate($x5 + $x4, 7);
$x7 ^= self::rotate($x6 + $x5, 9);
$x4 ^= self::rotate($x7 + $x6, 13);
$x5 ^= self::rotate($x4 + $x7, 18);
$x11 ^= self::rotate($x10 + $x9, 7);
$x8 ^= self::rotate($x11 + $x10, 9);
$x9 ^= self::rotate($x8 + $x11, 13);
$x10 ^= self::rotate($x9 + $x8, 18);
$x12 ^= self::rotate($x15 + $x14, 7);
$x13 ^= self::rotate($x12 + $x15, 9);
$x14 ^= self::rotate($x13 + $x12, 13);
$x15 ^= self::rotate($x14 + $x13, 18);
}
return self::store32_le($x0) . self::store32_le($x5) . self::store32_le($x10) . self::store32_le($x15) . self::store32_le($x6) . self::store32_le($x7) . self::store32_le($x8) . self::store32_le($x9);
}
}
/**
* Class ParagonIE_Sodium_Core_HSalsa20
*/

View File

@@ -0,0 +1,53 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Poly1305', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Poly1305
*/
abstract class ParagonIE_Sodium_Core_Poly1305 extends \ParagonIE_Sodium_Core_Util
{
const BLOCK_SIZE = 16;
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth($m, $key)
{
if (self::strlen($key) < 32) {
throw new \InvalidArgumentException('Key must be 32 bytes long.');
}
$state = new \ParagonIE_Sodium_Core_Poly1305_State(self::substr($key, 0, 32));
return $state->update($m)->finish();
}
/**
* @internal You should not use this directly from another application
*
* @param string $mac
* @param string $m
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth_verify($mac, $m, $key)
{
if (self::strlen($key) < 32) {
throw new \InvalidArgumentException('Key must be 32 bytes long.');
}
$state = new \ParagonIE_Sodium_Core_Poly1305_State(self::substr($key, 0, 32));
$calc = $state->update($m)->finish();
return self::verify_16($calc, $mac);
}
}
/**
* Class ParagonIE_Sodium_Core_Poly1305
*/

View File

@@ -0,0 +1,339 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Poly1305_State', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Poly1305_State
*/
class ParagonIE_Sodium_Core_Poly1305_State extends \ParagonIE_Sodium_Core_Util
{
/**
* @var array<int, int>
*/
protected $buffer = array();
/**
* @var bool
*/
protected $final = \false;
/**
* @var array<int, int>
*/
public $h;
/**
* @var int
*/
protected $leftover = 0;
/**
* @var int[]
*/
public $r;
/**
* @var int[]
*/
public $pad;
/**
* ParagonIE_Sodium_Core_Poly1305_State constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct($key = '')
{
if (self::strlen($key) < 32) {
throw new \InvalidArgumentException('Poly1305 requires a 32-byte key');
}
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
$this->r = array((int) (self::load_4(self::substr($key, 0, 4)) & 0x3ffffff), (int) (self::load_4(self::substr($key, 3, 4)) >> 2 & 0x3ffff03), (int) (self::load_4(self::substr($key, 6, 4)) >> 4 & 0x3ffc0ff), (int) (self::load_4(self::substr($key, 9, 4)) >> 6 & 0x3f03fff), (int) (self::load_4(self::substr($key, 12, 4)) >> 8 & 0xfffff));
/* h = 0 */
$this->h = array(0, 0, 0, 0, 0);
/* save pad for later */
$this->pad = array(self::load_4(self::substr($key, 16, 4)), self::load_4(self::substr($key, 20, 4)), self::load_4(self::substr($key, 24, 4)), self::load_4(self::substr($key, 28, 4)));
$this->leftover = 0;
$this->final = \false;
}
/**
* Zero internal buffer upon destruction
*/
public function __destruct()
{
$this->r[0] ^= $this->r[0];
$this->r[1] ^= $this->r[1];
$this->r[2] ^= $this->r[2];
$this->r[3] ^= $this->r[3];
$this->r[4] ^= $this->r[4];
$this->h[0] ^= $this->h[0];
$this->h[1] ^= $this->h[1];
$this->h[2] ^= $this->h[2];
$this->h[3] ^= $this->h[3];
$this->h[4] ^= $this->h[4];
$this->pad[0] ^= $this->pad[0];
$this->pad[1] ^= $this->pad[1];
$this->pad[2] ^= $this->pad[2];
$this->pad[3] ^= $this->pad[3];
$this->leftover = 0;
$this->final = \true;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function update($message = '')
{
$bytes = self::strlen($message);
if ($bytes < 1) {
return $this;
}
/* handle leftover */
if ($this->leftover) {
$want = \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - $this->leftover;
if ($want > $bytes) {
$want = $bytes;
}
for ($i = 0; $i < $want; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
// We snip off the leftmost bytes.
$message = self::substr($message, $want);
$bytes = self::strlen($message);
$this->leftover += $want;
if ($this->leftover < \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
// We still don't have enough to run $this->blocks()
return $this;
}
$this->blocks(self::intArrayToString($this->buffer), \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE);
$this->leftover = 0;
}
/* process full blocks */
if ($bytes >= \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/** @var int $want */
$want = $bytes & ~(\ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - 1);
if ($want >= \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$block = self::substr($message, 0, $want);
if (self::strlen($block) >= \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$this->blocks($block, $want);
$message = self::substr($message, $want);
$bytes = self::strlen($message);
}
}
}
/* store leftover */
if ($bytes) {
for ($i = 0; $i < $bytes; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
$this->leftover = (int) $this->leftover + $bytes;
}
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param int $bytes
* @return self
* @throws TypeError
*/
public function blocks($message, $bytes)
{
if (self::strlen($message) < 16) {
$message = \str_pad($message, 16, "\x00", \STR_PAD_RIGHT);
}
/** @var int $hibit */
$hibit = $this->final ? 0 : 1 << 24;
/* 1 << 128 */
$r0 = (int) $this->r[0];
$r1 = (int) $this->r[1];
$r2 = (int) $this->r[2];
$r3 = (int) $this->r[3];
$r4 = (int) $this->r[4];
$s1 = self::mul($r1, 5, 3);
$s2 = self::mul($r2, 5, 3);
$s3 = self::mul($r3, 5, 3);
$s4 = self::mul($r4, 5, 3);
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
while ($bytes >= \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/* h += m[i] */
$h0 += self::load_4(self::substr($message, 0, 4)) & 0x3ffffff;
$h1 += self::load_4(self::substr($message, 3, 4)) >> 2 & 0x3ffffff;
$h2 += self::load_4(self::substr($message, 6, 4)) >> 4 & 0x3ffffff;
$h3 += self::load_4(self::substr($message, 9, 4)) >> 6 & 0x3ffffff;
$h4 += self::load_4(self::substr($message, 12, 4)) >> 8 | $hibit;
/* h *= r */
$d0 = self::mul($h0, $r0, 27) + self::mul($s4, $h1, 27) + self::mul($s3, $h2, 27) + self::mul($s2, $h3, 27) + self::mul($s1, $h4, 27);
$d1 = self::mul($h0, $r1, 27) + self::mul($h1, $r0, 27) + self::mul($s4, $h2, 27) + self::mul($s3, $h3, 27) + self::mul($s2, $h4, 27);
$d2 = self::mul($h0, $r2, 27) + self::mul($h1, $r1, 27) + self::mul($h2, $r0, 27) + self::mul($s4, $h3, 27) + self::mul($s3, $h4, 27);
$d3 = self::mul($h0, $r3, 27) + self::mul($h1, $r2, 27) + self::mul($h2, $r1, 27) + self::mul($h3, $r0, 27) + self::mul($s4, $h4, 27);
$d4 = self::mul($h0, $r4, 27) + self::mul($h1, $r3, 27) + self::mul($h2, $r2, 27) + self::mul($h3, $r1, 27) + self::mul($h4, $r0, 27);
/* (partial) h %= p */
/** @var int $c */
$c = $d0 >> 26;
/** @var int $h0 */
$h0 = $d0 & 0x3ffffff;
$d1 += $c;
/** @var int $c */
$c = $d1 >> 26;
/** @var int $h1 */
$h1 = $d1 & 0x3ffffff;
$d2 += $c;
/** @var int $c */
$c = $d2 >> 26;
/** @var int $h2 */
$h2 = $d2 & 0x3ffffff;
$d3 += $c;
/** @var int $c */
$c = $d3 >> 26;
/** @var int $h3 */
$h3 = $d3 & 0x3ffffff;
$d4 += $c;
/** @var int $c */
$c = $d4 >> 26;
/** @var int $h4 */
$h4 = $d4 & 0x3ffffff;
$h0 += (int) self::mul($c, 5, 3);
/** @var int $c */
$c = $h0 >> 26;
/** @var int $h0 */
$h0 &= 0x3ffffff;
$h1 += $c;
// Chop off the left 32 bytes.
$message = self::substr($message, \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE);
$bytes -= \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE;
}
$this->h = array((int) ($h0 & 0xffffffff), (int) ($h1 & 0xffffffff), (int) ($h2 & 0xffffffff), (int) ($h3 & 0xffffffff), (int) ($h4 & 0xffffffff));
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @return string
* @throws TypeError
*/
public function finish()
{
/* process the remaining block */
if ($this->leftover) {
$i = $this->leftover;
$this->buffer[$i++] = 1;
for (; $i < \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; ++$i) {
$this->buffer[$i] = 0;
}
$this->final = \true;
$this->blocks(self::substr(self::intArrayToString($this->buffer), 0, \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE), \ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE);
}
$h0 = (int) $this->h[0];
$h1 = (int) $this->h[1];
$h2 = (int) $this->h[2];
$h3 = (int) $this->h[3];
$h4 = (int) $this->h[4];
/** @var int $c */
$c = $h1 >> 26;
/** @var int $h1 */
$h1 &= 0x3ffffff;
/** @var int $h2 */
$h2 += $c;
/** @var int $c */
$c = $h2 >> 26;
/** @var int $h2 */
$h2 &= 0x3ffffff;
$h3 += $c;
/** @var int $c */
$c = $h3 >> 26;
$h3 &= 0x3ffffff;
$h4 += $c;
/** @var int $c */
$c = $h4 >> 26;
$h4 &= 0x3ffffff;
/** @var int $h0 */
$h0 += self::mul($c, 5, 3);
/** @var int $c */
$c = $h0 >> 26;
/** @var int $h0 */
$h0 &= 0x3ffffff;
/** @var int $h1 */
$h1 += $c;
/* compute h + -p */
/** @var int $g0 */
$g0 = $h0 + 5;
/** @var int $c */
$c = $g0 >> 26;
/** @var int $g0 */
$g0 &= 0x3ffffff;
/** @var int $g1 */
$g1 = $h1 + $c;
/** @var int $c */
$c = $g1 >> 26;
$g1 &= 0x3ffffff;
/** @var int $g2 */
$g2 = $h2 + $c;
/** @var int $c */
$c = $g2 >> 26;
/** @var int $g2 */
$g2 &= 0x3ffffff;
/** @var int $g3 */
$g3 = $h3 + $c;
/** @var int $c */
$c = $g3 >> 26;
/** @var int $g3 */
$g3 &= 0x3ffffff;
/** @var int $g4 */
$g4 = $h4 + $c - (1 << 26) & 0xffffffff;
/* select h if h < p, or h + -p if h >= p */
/** @var int $mask */
$mask = ($g4 >> 31) - 1;
$g0 &= $mask;
$g1 &= $mask;
$g2 &= $mask;
$g3 &= $mask;
$g4 &= $mask;
/** @var int $mask */
$mask = ~$mask & 0xffffffff;
/** @var int $h0 */
$h0 = $h0 & $mask | $g0;
/** @var int $h1 */
$h1 = $h1 & $mask | $g1;
/** @var int $h2 */
$h2 = $h2 & $mask | $g2;
/** @var int $h3 */
$h3 = $h3 & $mask | $g3;
/** @var int $h4 */
$h4 = $h4 & $mask | $g4;
/* h = h % (2^128) */
/** @var int $h0 */
$h0 = ($h0 | $h1 << 26) & 0xffffffff;
/** @var int $h1 */
$h1 = ($h1 >> 6 | $h2 << 20) & 0xffffffff;
/** @var int $h2 */
$h2 = ($h2 >> 12 | $h3 << 14) & 0xffffffff;
/** @var int $h3 */
$h3 = ($h3 >> 18 | $h4 << 8) & 0xffffffff;
/* mac = (h + pad) % (2^128) */
$f = (int) ($h0 + $this->pad[0]);
$h0 = (int) $f;
$f = (int) ($h1 + $this->pad[1] + ($f >> 32));
$h1 = (int) $f;
$f = (int) ($h2 + $this->pad[2] + ($f >> 32));
$h2 = (int) $f;
$f = (int) ($h3 + $this->pad[3] + ($f >> 32));
$h3 = (int) $f;
return self::store32_le($h0 & 0xffffffff) . self::store32_le($h1 & 0xffffffff) . self::store32_le($h2 & 0xffffffff) . self::store32_le($h3 & 0xffffffff);
}
}
/**
* Class ParagonIE_Sodium_Core_Poly1305_State
*/

View File

@@ -0,0 +1,603 @@
<?php
/**
* Class ParagonIE_Sodium_Core_Ristretto255
*/
class ParagonIE_Sodium_Core_Ristretto255 extends \ParagonIE_Sodium_Core_Ed25519
{
const crypto_core_ristretto255_HASHBYTES = 64;
const HASH_SC_L = 48;
const CORE_H2C_SHA256 = 1;
const CORE_H2C_SHA512 = 2;
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_cneg(\ParagonIE_Sodium_Core_Curve25519_Fe $f, $b)
{
$negf = self::fe_neg($f);
return self::fe_cmov($f, $negf, $b);
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @throws SodiumException
*/
public static function fe_abs(\ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
return self::fe_cneg($f, self::fe_isnegative($f));
}
/**
* Returns 0 if this field element results in all NUL bytes.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return int
* @throws SodiumException
*/
public static function fe_iszero(\ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
static $zero;
if ($zero === null) {
$zero = \str_repeat("\x00", 32);
}
/** @var string $zero */
$str = self::fe_tobytes($f);
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($str[$i]);
}
return $d - 1 >> 31 & 1;
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $u
* @param ParagonIE_Sodium_Core_Curve25519_Fe $v
* @return array{x: ParagonIE_Sodium_Core_Curve25519_Fe, nonsquare: int}
*
* @throws SodiumException
*/
public static function ristretto255_sqrt_ratio_m1(\ParagonIE_Sodium_Core_Curve25519_Fe $u, \ParagonIE_Sodium_Core_Curve25519_Fe $v)
{
$sqrtm1 = \ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
$v3 = self::fe_mul(self::fe_sq($v), $v);
/* v3 = v^3 */
$x = self::fe_mul(self::fe_mul(self::fe_sq($v3), $u), $v);
/* x = uv^7 */
$x = self::fe_mul(self::fe_mul(
self::fe_pow22523($x),
/* x = (uv^7)^((q-5)/8) */
$v3
), $u);
/* x = uv^3(uv^7)^((q-5)/8) */
$vxx = self::fe_mul(self::fe_sq($x), $v);
/* vx^2 */
$m_root_check = self::fe_sub($vxx, $u);
/* vx^2-u */
$p_root_check = self::fe_add($vxx, $u);
/* vx^2+u */
$f_root_check = self::fe_mul($u, $sqrtm1);
/* u*sqrt(-1) */
$f_root_check = self::fe_add($vxx, $f_root_check);
/* vx^2+u*sqrt(-1) */
$has_m_root = self::fe_iszero($m_root_check);
$has_p_root = self::fe_iszero($p_root_check);
$has_f_root = self::fe_iszero($f_root_check);
$x_sqrtm1 = self::fe_mul($x, $sqrtm1);
/* x*sqrt(-1) */
$x = self::fe_abs(self::fe_cmov($x, $x_sqrtm1, $has_p_root | $has_f_root));
return array('x' => $x, 'nonsquare' => $has_m_root | $has_p_root);
}
/**
* @param string $s
* @return int
* @throws SodiumException
*/
public static function ristretto255_point_is_canonical($s)
{
$c = self::chrToInt($s[31]) & 0x7f ^ 0x7f;
for ($i = 30; $i > 0; --$i) {
$c |= self::chrToInt($s[$i]) ^ 0xff;
}
$c = $c - 1 >> 8;
$d = 0xed - 1 - self::chrToInt($s[0]) >> 8;
$e = self::chrToInt($s[31]) >> 7;
return 1 - (($c & $d | $e | self::chrToInt($s[0])) & 1);
}
/**
* @param string $s
* @param bool $skipCanonicalCheck
* @return array{h: ParagonIE_Sodium_Core_Curve25519_Ge_P3, res: int}
* @throws SodiumException
*/
public static function ristretto255_frombytes($s, $skipCanonicalCheck = \false)
{
if (!$skipCanonicalCheck) {
if (!self::ristretto255_point_is_canonical($s)) {
throw new \SodiumException('S is not canonical');
}
}
$s_ = self::fe_frombytes($s);
$ss = self::fe_sq($s_);
/* ss = s^2 */
$u1 = self::fe_sub(self::fe_1(), $ss);
/* u1 = 1-ss */
$u1u1 = self::fe_sq($u1);
/* u1u1 = u1^2 */
$u2 = self::fe_add(self::fe_1(), $ss);
/* u2 = 1+ss */
$u2u2 = self::fe_sq($u2);
/* u2u2 = u2^2 */
$v = self::fe_mul(\ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d), $u1u1);
/* v = d*u1^2 */
$v = self::fe_neg($v);
/* v = -d*u1^2 */
$v = self::fe_sub($v, $u2u2);
/* v = -(d*u1^2)-u2^2 */
$v_u2u2 = self::fe_mul($v, $u2u2);
/* v_u2u2 = v*u2^2 */
// fe25519_1(one);
// notsquare = ristretto255_sqrt_ratio_m1(inv_sqrt, one, v_u2u2);
$one = self::fe_1();
$result = self::ristretto255_sqrt_ratio_m1($one, $v_u2u2);
$inv_sqrt = $result['x'];
$notsquare = $result['nonsquare'];
$h = new \ParagonIE_Sodium_Core_Curve25519_Ge_P3();
$h->X = self::fe_mul($inv_sqrt, $u2);
$h->Y = self::fe_mul(self::fe_mul($inv_sqrt, $h->X), $v);
$h->X = self::fe_mul($h->X, $s_);
$h->X = self::fe_abs(self::fe_add($h->X, $h->X));
$h->Y = self::fe_mul($u1, $h->Y);
$h->Z = self::fe_1();
$h->T = self::fe_mul($h->X, $h->Y);
$res = -(1 - $notsquare | self::fe_isnegative($h->T) | self::fe_iszero($h->Y));
return array('h' => $h, 'res' => $res);
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
* @return string
* @throws SodiumException
*/
public static function ristretto255_p3_tobytes(\ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
{
$sqrtm1 = \ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
$invsqrtamd = \ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$invsqrtamd);
$u1 = self::fe_add($h->Z, $h->Y);
/* u1 = Z+Y */
$zmy = self::fe_sub($h->Z, $h->Y);
/* zmy = Z-Y */
$u1 = self::fe_mul($u1, $zmy);
/* u1 = (Z+Y)*(Z-Y) */
$u2 = self::fe_mul($h->X, $h->Y);
/* u2 = X*Y */
$u1_u2u2 = self::fe_mul(self::fe_sq($u2), $u1);
/* u1_u2u2 = u1*u2^2 */
$one = self::fe_1();
// fe25519_1(one);
// (void) ristretto255_sqrt_ratio_m1(inv_sqrt, one, u1_u2u2);
$result = self::ristretto255_sqrt_ratio_m1($one, $u1_u2u2);
$inv_sqrt = $result['x'];
$den1 = self::fe_mul($inv_sqrt, $u1);
/* den1 = inv_sqrt*u1 */
$den2 = self::fe_mul($inv_sqrt, $u2);
/* den2 = inv_sqrt*u2 */
$z_inv = self::fe_mul($h->T, self::fe_mul($den1, $den2));
/* z_inv = den1*den2*T */
$ix = self::fe_mul($h->X, $sqrtm1);
/* ix = X*sqrt(-1) */
$iy = self::fe_mul($h->Y, $sqrtm1);
/* iy = Y*sqrt(-1) */
$eden = self::fe_mul($den1, $invsqrtamd);
$t_z_inv = self::fe_mul($h->T, $z_inv);
/* t_z_inv = T*z_inv */
$rotate = self::fe_isnegative($t_z_inv);
$x_ = self::fe_copy($h->X);
$y_ = self::fe_copy($h->Y);
$den_inv = self::fe_copy($den2);
$x_ = self::fe_cmov($x_, $iy, $rotate);
$y_ = self::fe_cmov($y_, $ix, $rotate);
$den_inv = self::fe_cmov($den_inv, $eden, $rotate);
$x_z_inv = self::fe_mul($x_, $z_inv);
$y_ = self::fe_cneg($y_, self::fe_isnegative($x_z_inv));
// fe25519_sub(s_, h->Z, y_);
// fe25519_mul(s_, den_inv, s_);
// fe25519_abs(s_, s_);
// fe25519_tobytes(s, s_);
return self::fe_tobytes(self::fe_abs(self::fe_mul($den_inv, self::fe_sub($h->Z, $y_))));
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $t
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
*
* @throws SodiumException
*/
public static function ristretto255_elligator(\ParagonIE_Sodium_Core_Curve25519_Fe $t)
{
$sqrtm1 = \ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
$onemsqd = \ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$onemsqd);
$d = \ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
$sqdmone = \ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqdmone);
$sqrtadm1 = \ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtadm1);
$one = self::fe_1();
$r = self::fe_mul($sqrtm1, self::fe_sq($t));
/* r = sqrt(-1)*t^2 */
$u = self::fe_mul(self::fe_add($r, $one), $onemsqd);
/* u = (r+1)*(1-d^2) */
$c = self::fe_neg(self::fe_1());
/* c = -1 */
$rpd = self::fe_add($r, $d);
/* rpd = r+d */
$v = self::fe_mul(self::fe_sub($c, self::fe_mul($r, $d)), $rpd);
/* v = (c-r*d)*(r+d) */
$result = self::ristretto255_sqrt_ratio_m1($u, $v);
$s = $result['x'];
$wasnt_square = 1 - $result['nonsquare'];
$s_prime = self::fe_neg(self::fe_abs(self::fe_mul($s, $t)));
/* s_prime = -|s*t| */
$s = self::fe_cmov($s, $s_prime, $wasnt_square);
$c = self::fe_cmov($c, $r, $wasnt_square);
// fe25519_sub(n, r, one); /* n = r-1 */
// fe25519_mul(n, n, c); /* n = c*(r-1) */
// fe25519_mul(n, n, ed25519_sqdmone); /* n = c*(r-1)*(d-1)^2 */
// fe25519_sub(n, n, v); /* n = c*(r-1)*(d-1)^2-v */
$n = self::fe_sub(self::fe_mul(self::fe_mul(self::fe_sub($r, $one), $c), $sqdmone), $v);
/* n = c*(r-1)*(d-1)^2-v */
$w0 = self::fe_mul(self::fe_add($s, $s), $v);
/* w0 = 2s*v */
$w1 = self::fe_mul($n, $sqrtadm1);
/* w1 = n*sqrt(ad-1) */
$ss = self::fe_sq($s);
/* ss = s^2 */
$w2 = self::fe_sub($one, $ss);
/* w2 = 1-s^2 */
$w3 = self::fe_add($one, $ss);
/* w3 = 1+s^2 */
return new \ParagonIE_Sodium_Core_Curve25519_Ge_P3(self::fe_mul($w0, $w3), self::fe_mul($w2, $w1), self::fe_mul($w1, $w3), self::fe_mul($w0, $w2));
}
/**
* @param string $h
* @return string
* @throws SodiumException
*/
public static function ristretto255_from_hash($h)
{
if (self::strlen($h) !== 64) {
throw new \SodiumException('Hash must be 64 bytes');
}
//fe25519_frombytes(r0, h);
//fe25519_frombytes(r1, h + 32);
$r0 = self::fe_frombytes(self::substr($h, 0, 32));
$r1 = self::fe_frombytes(self::substr($h, 32, 32));
//ristretto255_elligator(&p0, r0);
//ristretto255_elligator(&p1, r1);
$p0 = self::ristretto255_elligator($r0);
$p1 = self::ristretto255_elligator($r1);
//ge25519_p3_to_cached(&p1_cached, &p1);
//ge25519_add_cached(&p_p1p1, &p0, &p1_cached);
$p_p1p1 = self::ge_add($p0, self::ge_p3_to_cached($p1));
//ge25519_p1p1_to_p3(&p, &p_p1p1);
//ristretto255_p3_tobytes(s, &p);
return self::ristretto255_p3_tobytes(self::ge_p1p1_to_p3($p_p1p1));
}
/**
* @param string $p
* @return int
* @throws SodiumException
*/
public static function is_valid_point($p)
{
$result = self::ristretto255_frombytes($p);
if ($result['res'] !== 0) {
return 0;
}
return 1;
}
/**
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
public static function ristretto255_add($p, $q)
{
$p_res = self::ristretto255_frombytes($p);
$q_res = self::ristretto255_frombytes($q);
if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
throw new \SodiumException('Could not add points');
}
$p_p3 = $p_res['h'];
$q_p3 = $q_res['h'];
$q_cached = self::ge_p3_to_cached($q_p3);
$r_p1p1 = self::ge_add($p_p3, $q_cached);
$r_p3 = self::ge_p1p1_to_p3($r_p1p1);
return self::ristretto255_p3_tobytes($r_p3);
}
/**
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
public static function ristretto255_sub($p, $q)
{
$p_res = self::ristretto255_frombytes($p);
$q_res = self::ristretto255_frombytes($q);
if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
throw new \SodiumException('Could not add points');
}
$p_p3 = $p_res['h'];
$q_p3 = $q_res['h'];
$q_cached = self::ge_p3_to_cached($q_p3);
$r_p1p1 = self::ge_sub($p_p3, $q_cached);
$r_p3 = self::ge_p1p1_to_p3($r_p1p1);
return self::ristretto255_p3_tobytes($r_p3);
}
/**
* @param int $hLen
* @param ?string $ctx
* @param string $msg
* @return string
* @throws SodiumException
* @psalm-suppress PossiblyInvalidArgument hash API
*/
protected static function h2c_string_to_hash_sha256($hLen, $ctx, $msg)
{
$h = \array_fill(0, $hLen, 0);
$ctx_len = !\is_null($ctx) ? self::strlen($ctx) : 0;
if ($hLen > 0xff) {
throw new \SodiumException('Hash must be less than 256 bytes');
}
if ($ctx_len > 0xff) {
$st = \hash_init('sha256');
self::hash_update($st, "H2C-OVERSIZE-DST-");
self::hash_update($st, $ctx);
$ctx = \hash_final($st, \true);
$ctx_len = 32;
}
$t = array(0, $hLen, 0);
$ux = \str_repeat("\x00", 64);
$st = \hash_init('sha256');
self::hash_update($st, $ux);
self::hash_update($st, $msg);
self::hash_update($st, self::intArrayToString($t));
self::hash_update($st, $ctx);
self::hash_update($st, self::intToChr($ctx_len));
$u0 = \hash_final($st, \true);
for ($i = 0; $i < $hLen; $i += 64) {
$ux = self::xorStrings($ux, $u0);
++$t[2];
$st = \hash_init('sha256');
self::hash_update($st, $ux);
self::hash_update($st, self::intToChr($t[2]));
self::hash_update($st, $ctx);
self::hash_update($st, self::intToChr($ctx_len));
$ux = \hash_final($st, \true);
$amount = \min($hLen - $i, 64);
for ($j = 0; $j < $amount; ++$j) {
$h[$i + $j] = self::chrToInt($ux[$i]);
}
}
return self::intArrayToString(\array_slice($h, 0, $hLen));
}
/**
* @param int $hLen
* @param ?string $ctx
* @param string $msg
* @return string
* @throws SodiumException
* @psalm-suppress PossiblyInvalidArgument hash API
*/
protected static function h2c_string_to_hash_sha512($hLen, $ctx, $msg)
{
$h = \array_fill(0, $hLen, 0);
$ctx_len = !\is_null($ctx) ? self::strlen($ctx) : 0;
if ($hLen > 0xff) {
throw new \SodiumException('Hash must be less than 256 bytes');
}
if ($ctx_len > 0xff) {
$st = \hash_init('sha256');
self::hash_update($st, "H2C-OVERSIZE-DST-");
self::hash_update($st, $ctx);
$ctx = \hash_final($st, \true);
$ctx_len = 32;
}
$t = array(0, $hLen, 0);
$ux = \str_repeat("\x00", 128);
$st = \hash_init('sha512');
self::hash_update($st, $ux);
self::hash_update($st, $msg);
self::hash_update($st, self::intArrayToString($t));
self::hash_update($st, $ctx);
self::hash_update($st, self::intToChr($ctx_len));
$u0 = \hash_final($st, \true);
for ($i = 0; $i < $hLen; $i += 128) {
$ux = self::xorStrings($ux, $u0);
++$t[2];
$st = \hash_init('sha512');
self::hash_update($st, $ux);
self::hash_update($st, self::intToChr($t[2]));
self::hash_update($st, $ctx);
self::hash_update($st, self::intToChr($ctx_len));
$ux = \hash_final($st, \true);
$amount = \min($hLen - $i, 128);
for ($j = 0; $j < $amount; ++$j) {
$h[$i + $j] = self::chrToInt($ux[$i]);
}
}
return self::intArrayToString(\array_slice($h, 0, $hLen));
}
/**
* @param int $hLen
* @param ?string $ctx
* @param string $msg
* @param int $hash_alg
* @return string
* @throws SodiumException
*/
public static function h2c_string_to_hash($hLen, $ctx, $msg, $hash_alg)
{
switch ($hash_alg) {
case self::CORE_H2C_SHA256:
return self::h2c_string_to_hash_sha256($hLen, $ctx, $msg);
case self::CORE_H2C_SHA512:
return self::h2c_string_to_hash_sha512($hLen, $ctx, $msg);
default:
throw new \SodiumException('Invalid H2C hash algorithm');
}
}
/**
* @param ?string $ctx
* @param string $msg
* @param int $hash_alg
* @return string
* @throws SodiumException
*/
protected static function _string_to_element($ctx, $msg, $hash_alg)
{
return self::ristretto255_from_hash(self::h2c_string_to_hash(self::crypto_core_ristretto255_HASHBYTES, $ctx, $msg, $hash_alg));
}
/**
* @return string
* @throws SodiumException
* @throws Exception
*/
public static function ristretto255_random()
{
return self::ristretto255_from_hash(\ParagonIE_Sodium_Compat::randombytes_buf(self::crypto_core_ristretto255_HASHBYTES));
}
/**
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_random()
{
return self::scalar_random();
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_complement($s)
{
return self::scalar_complement($s);
}
/**
* @param string $s
* @return string
*/
public static function ristretto255_scalar_invert($s)
{
return self::sc25519_invert($s);
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_negate($s)
{
return self::scalar_negate($s);
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function ristretto255_scalar_add($x, $y)
{
return self::scalar_add($x, $y);
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function ristretto255_scalar_sub($x, $y)
{
return self::scalar_sub($x, $y);
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function ristretto255_scalar_mul($x, $y)
{
return self::sc25519_mul($x, $y);
}
/**
* @param string $ctx
* @param string $msg
* @param int $hash_alg
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_from_string($ctx, $msg, $hash_alg)
{
$h = \array_fill(0, 64, 0);
$h_be = self::stringToIntArray(self::h2c_string_to_hash(self::HASH_SC_L, $ctx, $msg, $hash_alg));
for ($i = 0; $i < self::HASH_SC_L; ++$i) {
$h[$i] = $h_be[self::HASH_SC_L - 1 - $i];
}
return self::ristretto255_scalar_reduce(self::intArrayToString($h));
}
/**
* @param string $s
* @return string
*/
public static function ristretto255_scalar_reduce($s)
{
return self::sc_reduce($s);
}
/**
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
*/
public static function scalarmult_ristretto255($n, $p)
{
if (self::strlen($n) !== 32) {
throw new \SodiumException('Scalar must be 32 bytes, ' . self::strlen($p) . ' given.');
}
if (self::strlen($p) !== 32) {
throw new \SodiumException('Point must be 32 bytes, ' . self::strlen($p) . ' given.');
}
$result = self::ristretto255_frombytes($p);
if ($result['res'] !== 0) {
throw new \SodiumException('Could not multiply points');
}
$P = $result['h'];
$t = self::stringToIntArray($n);
$t[31] &= 0x7f;
$Q = self::ge_scalarmult(self::intArrayToString($t), $P);
$q = self::ristretto255_p3_tobytes($Q);
if (\ParagonIE_Sodium_Compat::is_zero($q)) {
throw new \SodiumException('An unknown error has occurred');
}
return $q;
}
/**
* @param string $n
* @return string
* @throws SodiumException
*/
public static function scalarmult_ristretto255_base($n)
{
$t = self::stringToIntArray($n);
$t[31] &= 0x7f;
$Q = self::ge_scalarmult_base(self::intArrayToString($t));
$q = self::ristretto255_p3_tobytes($Q);
if (\ParagonIE_Sodium_Compat::is_zero($q)) {
throw new \SodiumException('An unknown error has occurred');
}
return $q;
}
}
/**
* Class ParagonIE_Sodium_Core_Ristretto255
*/

View File

@@ -0,0 +1,221 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Salsa20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Salsa20
*/
abstract class ParagonIE_Sodium_Core_Salsa20 extends \ParagonIE_Sodium_Core_Util
{
const ROUNDS = 20;
/**
* Calculate an salsa20 hash of a single block
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function core_salsa20($in, $k, $c = null)
{
if (self::strlen($k) < 32) {
throw new \RangeException('Key must be 32 bytes long');
}
if ($c === null) {
$j0 = $x0 = 0x61707865;
$j5 = $x5 = 0x3320646e;
$j10 = $x10 = 0x79622d32;
$j15 = $x15 = 0x6b206574;
} else {
$j0 = $x0 = self::load_4(self::substr($c, 0, 4));
$j5 = $x5 = self::load_4(self::substr($c, 4, 4));
$j10 = $x10 = self::load_4(self::substr($c, 8, 4));
$j15 = $x15 = self::load_4(self::substr($c, 12, 4));
}
$j1 = $x1 = self::load_4(self::substr($k, 0, 4));
$j2 = $x2 = self::load_4(self::substr($k, 4, 4));
$j3 = $x3 = self::load_4(self::substr($k, 8, 4));
$j4 = $x4 = self::load_4(self::substr($k, 12, 4));
$j6 = $x6 = self::load_4(self::substr($in, 0, 4));
$j7 = $x7 = self::load_4(self::substr($in, 4, 4));
$j8 = $x8 = self::load_4(self::substr($in, 8, 4));
$j9 = $x9 = self::load_4(self::substr($in, 12, 4));
$j11 = $x11 = self::load_4(self::substr($k, 16, 4));
$j12 = $x12 = self::load_4(self::substr($k, 20, 4));
$j13 = $x13 = self::load_4(self::substr($k, 24, 4));
$j14 = $x14 = self::load_4(self::substr($k, 28, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 ^= self::rotate($x0 + $x12, 7);
$x8 ^= self::rotate($x4 + $x0, 9);
$x12 ^= self::rotate($x8 + $x4, 13);
$x0 ^= self::rotate($x12 + $x8, 18);
$x9 ^= self::rotate($x5 + $x1, 7);
$x13 ^= self::rotate($x9 + $x5, 9);
$x1 ^= self::rotate($x13 + $x9, 13);
$x5 ^= self::rotate($x1 + $x13, 18);
$x14 ^= self::rotate($x10 + $x6, 7);
$x2 ^= self::rotate($x14 + $x10, 9);
$x6 ^= self::rotate($x2 + $x14, 13);
$x10 ^= self::rotate($x6 + $x2, 18);
$x3 ^= self::rotate($x15 + $x11, 7);
$x7 ^= self::rotate($x3 + $x15, 9);
$x11 ^= self::rotate($x7 + $x3, 13);
$x15 ^= self::rotate($x11 + $x7, 18);
$x1 ^= self::rotate($x0 + $x3, 7);
$x2 ^= self::rotate($x1 + $x0, 9);
$x3 ^= self::rotate($x2 + $x1, 13);
$x0 ^= self::rotate($x3 + $x2, 18);
$x6 ^= self::rotate($x5 + $x4, 7);
$x7 ^= self::rotate($x6 + $x5, 9);
$x4 ^= self::rotate($x7 + $x6, 13);
$x5 ^= self::rotate($x4 + $x7, 18);
$x11 ^= self::rotate($x10 + $x9, 7);
$x8 ^= self::rotate($x11 + $x10, 9);
$x9 ^= self::rotate($x8 + $x11, 13);
$x10 ^= self::rotate($x9 + $x8, 18);
$x12 ^= self::rotate($x15 + $x14, 7);
$x13 ^= self::rotate($x12 + $x15, 9);
$x14 ^= self::rotate($x13 + $x12, 13);
$x15 ^= self::rotate($x14 + $x13, 18);
}
$x0 += $j0;
$x1 += $j1;
$x2 += $j2;
$x3 += $j3;
$x4 += $j4;
$x5 += $j5;
$x6 += $j6;
$x7 += $j7;
$x8 += $j8;
$x9 += $j9;
$x10 += $j10;
$x11 += $j11;
$x12 += $j12;
$x13 += $j13;
$x14 += $j14;
$x15 += $j15;
return self::store32_le($x0) . self::store32_le($x1) . self::store32_le($x2) . self::store32_le($x3) . self::store32_le($x4) . self::store32_le($x5) . self::store32_le($x6) . self::store32_le($x7) . self::store32_le($x8) . self::store32_le($x9) . self::store32_le($x10) . self::store32_le($x11) . self::store32_le($x12) . self::store32_le($x13) . self::store32_le($x14) . self::store32_le($x15);
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20($len, $nonce, $key)
{
if (self::strlen($key) !== 32) {
throw new \RangeException('Key must be 32 bytes long');
}
$kcopy = '' . $key;
$in = self::substr($nonce, 0, 8) . \str_repeat("\x00", 8);
$c = '';
while ($len >= 64) {
$c .= self::core_salsa20($in, $kcopy, null);
$u = 1;
// Internal counter.
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$len -= 64;
}
if ($len > 0) {
$c .= self::substr(self::core_salsa20($in, $kcopy, null), 0, $len);
}
try {
\ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (\SodiumException $ex) {
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $n
* @param int $ic
* @param string $k
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor_ic($m, $n, $ic, $k)
{
$mlen = self::strlen($m);
if ($mlen < 1) {
return '';
}
$kcopy = self::substr($k, 0, 32);
$in = self::substr($n, 0, 8);
// Initialize the counter
$in .= \ParagonIE_Sodium_Core_Util::store64_le($ic);
$c = '';
while ($mlen >= 64) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(self::substr($m, 0, 64), self::substr($block, 0, 64));
$u = 1;
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$mlen -= 64;
$m = self::substr($m, 64);
}
if ($mlen) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(self::substr($m, 0, $mlen), self::substr($block, 0, $mlen));
}
try {
\ParagonIE_Sodium_Compat::memzero($block);
\ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (\SodiumException $ex) {
$block = null;
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor($message, $nonce, $key)
{
return self::xorStrings($message, self::salsa20(self::strlen($message), $nonce, $key));
}
/**
* @internal You should not use this directly from another application
*
* @param int $u
* @param int $c
* @return int
*/
public static function rotate($u, $c)
{
$u &= 0xffffffff;
$c %= 32;
return (int) (0xffffffff & ($u << $c | $u >> 32 - $c));
}
}
/**
* Class ParagonIE_Sodium_Core_Salsa20
*/

View File

@@ -0,0 +1,132 @@
<?php
/**
* Class ParagonIE_Sodium_Core_SecretStream_State
*/
class ParagonIE_Sodium_Core_SecretStream_State
{
/** @var string $key */
protected $key;
/** @var int $counter */
protected $counter;
/** @var string $nonce */
protected $nonce;
/** @var string $_pad */
protected $_pad;
/**
* ParagonIE_Sodium_Core_SecretStream_State constructor.
* @param string $key
* @param string|null $nonce
*/
public function __construct($key, $nonce = null)
{
$this->key = $key;
$this->counter = 1;
if (\is_null($nonce)) {
$nonce = \str_repeat("\x00", 12);
}
$this->nonce = \str_pad($nonce, 12, "\x00", \STR_PAD_RIGHT);
$this->_pad = \str_repeat("\x00", 4);
}
/**
* @return self
*/
public function counterReset()
{
$this->counter = 1;
$this->_pad = \str_repeat("\x00", 4);
return $this;
}
/**
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* @return string
*/
public function getCounter()
{
return \ParagonIE_Sodium_Core_Util::store32_le($this->counter);
}
/**
* @return string
*/
public function getNonce()
{
if (!\is_string($this->nonce)) {
$this->nonce = \str_repeat("\x00", 12);
}
if (\ParagonIE_Sodium_Core_Util::strlen($this->nonce) !== 12) {
$this->nonce = \str_pad($this->nonce, 12, "\x00", \STR_PAD_RIGHT);
}
return $this->nonce;
}
/**
* @return string
*/
public function getCombinedNonce()
{
return $this->getCounter() . \ParagonIE_Sodium_Core_Util::substr($this->getNonce(), 0, 8);
}
/**
* @return self
*/
public function incrementCounter()
{
++$this->counter;
return $this;
}
/**
* @return bool
*/
public function needsRekey()
{
return ($this->counter & 0xffff) === 0;
}
/**
* @param string $newKeyAndNonce
* @return self
*/
public function rekey($newKeyAndNonce)
{
$this->key = \ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 0, 32);
$this->nonce = \str_pad(\ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 32), 12, "\x00", \STR_PAD_RIGHT);
return $this;
}
/**
* @param string $str
* @return self
*/
public function xorNonce($str)
{
$this->nonce = \ParagonIE_Sodium_Core_Util::xorStrings($this->getNonce(), \str_pad(\ParagonIE_Sodium_Core_Util::substr($str, 0, 8), 12, "\x00", \STR_PAD_RIGHT));
return $this;
}
/**
* @param string $string
* @return self
*/
public static function fromString($string)
{
$state = new \ParagonIE_Sodium_Core_SecretStream_State(\ParagonIE_Sodium_Core_Util::substr($string, 0, 32));
$state->counter = \ParagonIE_Sodium_Core_Util::load_4(\ParagonIE_Sodium_Core_Util::substr($string, 32, 4));
$state->nonce = \ParagonIE_Sodium_Core_Util::substr($string, 36, 12);
$state->_pad = \ParagonIE_Sodium_Core_Util::substr($string, 48, 8);
return $state;
}
/**
* @return string
*/
public function toString()
{
return $this->key . $this->getCounter() . $this->nonce . $this->_pad;
}
}
/**
* Class ParagonIE_Sodium_Core_SecretStream_State
*/

View File

@@ -0,0 +1,249 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_SipHash', \false)) {
return;
}
/**
* Class ParagonIE_SodiumCompat_Core_SipHash
*
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers
*/
class ParagonIE_Sodium_Core_SipHash extends \ParagonIE_Sodium_Core_Util
{
/**
* @internal You should not use this directly from another application
*
* @param int[] $v
* @return int[]
*
*/
public static function sipRound(array $v)
{
# v0 += v1;
list($v[0], $v[1]) = self::add(array($v[0], $v[1]), array($v[2], $v[3]));
# v1=ROTL(v1,13);
list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 13);
# v1 ^= v0;
$v[2] = (int) $v[2] ^ (int) $v[0];
$v[3] = (int) $v[3] ^ (int) $v[1];
# v0=ROTL(v0,32);
list($v[0], $v[1]) = self::rotl_64((int) $v[0], (int) $v[1], 32);
# v2 += v3;
list($v[4], $v[5]) = self::add(array((int) $v[4], (int) $v[5]), array((int) $v[6], (int) $v[7]));
# v3=ROTL(v3,16);
list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 16);
# v3 ^= v2;
$v[6] = (int) $v[6] ^ (int) $v[4];
$v[7] = (int) $v[7] ^ (int) $v[5];
# v0 += v3;
list($v[0], $v[1]) = self::add(array((int) $v[0], (int) $v[1]), array((int) $v[6], (int) $v[7]));
# v3=ROTL(v3,21);
list($v[6], $v[7]) = self::rotl_64((int) $v[6], (int) $v[7], 21);
# v3 ^= v0;
$v[6] = (int) $v[6] ^ (int) $v[0];
$v[7] = (int) $v[7] ^ (int) $v[1];
# v2 += v1;
list($v[4], $v[5]) = self::add(array((int) $v[4], (int) $v[5]), array((int) $v[2], (int) $v[3]));
# v1=ROTL(v1,17);
list($v[2], $v[3]) = self::rotl_64((int) $v[2], (int) $v[3], 17);
# v1 ^= v2;;
$v[2] = (int) $v[2] ^ (int) $v[4];
$v[3] = (int) $v[3] ^ (int) $v[5];
# v2=ROTL(v2,32)
list($v[4], $v[5]) = self::rotl_64((int) $v[4], (int) $v[5], 32);
return $v;
}
/**
* Add two 32 bit integers representing a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int[] $a
* @param int[] $b
* @return array<int, mixed>
*/
public static function add(array $a, array $b)
{
/** @var int $x1 */
$x1 = $a[1] + $b[1];
/** @var int $c */
$c = $x1 >> 32;
// Carry if ($a + $b) > 0xffffffff
/** @var int $x0 */
$x0 = $a[0] + $b[0] + $c;
return array($x0 & 0xffffffff, $x1 & 0xffffffff);
}
/**
* @internal You should not use this directly from another application
*
* @param int $int0
* @param int $int1
* @param int $c
* @return array<int, mixed>
*/
public static function rotl_64($int0, $int1, $c)
{
$int0 &= 0xffffffff;
$int1 &= 0xffffffff;
$c &= 63;
if ($c === 32) {
return array($int1, $int0);
}
if ($c > 31) {
$tmp = $int1;
$int1 = $int0;
$int0 = $tmp;
$c &= 31;
}
if ($c === 0) {
return array($int0, $int1);
}
return array(0xffffffff & ($int0 << $c | $int1 >> 32 - $c), 0xffffffff & ($int1 << $c | $int0 >> 32 - $c));
}
/**
* Implements Siphash-2-4 using only 32-bit numbers.
*
* When we split an int into two, the higher bits go to the lower index.
* e.g. 0xDEADBEEFAB10C92D becomes [
* 0 => 0xDEADBEEF,
* 1 => 0xAB10C92D
* ].
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sipHash24($in, $key)
{
$inlen = self::strlen($in);
# /* "somepseudorandomlygeneratedbytes" */
# u64 v0 = 0x736f6d6570736575ULL;
# u64 v1 = 0x646f72616e646f6dULL;
# u64 v2 = 0x6c7967656e657261ULL;
# u64 v3 = 0x7465646279746573ULL;
$v = array(
0x736f6d65,
// 0
0x70736575,
// 1
0x646f7261,
// 2
0x6e646f6d,
// 3
0x6c796765,
// 4
0x6e657261,
// 5
0x74656462,
// 6
0x79746573,
);
// v0 => $v[0], $v[1]
// v1 => $v[2], $v[3]
// v2 => $v[4], $v[5]
// v3 => $v[6], $v[7]
# u64 k0 = LOAD64_LE( k );
# u64 k1 = LOAD64_LE( k + 8 );
$k = array(self::load_4(self::substr($key, 4, 4)), self::load_4(self::substr($key, 0, 4)), self::load_4(self::substr($key, 12, 4)), self::load_4(self::substr($key, 8, 4)));
// k0 => $k[0], $k[1]
// k1 => $k[2], $k[3]
# b = ( ( u64 )inlen ) << 56;
$b = array($inlen << 24, 0);
// See docblock for why the 0th index gets the higher bits.
# v3 ^= k1;
$v[6] ^= $k[2];
$v[7] ^= $k[3];
# v2 ^= k0;
$v[4] ^= $k[0];
$v[5] ^= $k[1];
# v1 ^= k1;
$v[2] ^= $k[2];
$v[3] ^= $k[3];
# v0 ^= k0;
$v[0] ^= $k[0];
$v[1] ^= $k[1];
$left = $inlen;
# for ( ; in != end; in += 8 )
while ($left >= 8) {
# m = LOAD64_LE( in );
$m = array(self::load_4(self::substr($in, 4, 4)), self::load_4(self::substr($in, 0, 4)));
# v3 ^= m;
$v[6] ^= $m[0];
$v[7] ^= $m[1];
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= m;
$v[0] ^= $m[0];
$v[1] ^= $m[1];
$in = self::substr($in, 8);
$left -= 8;
}
# switch( left )
# {
# case 7: b |= ( ( u64 )in[ 6] ) << 48;
# case 6: b |= ( ( u64 )in[ 5] ) << 40;
# case 5: b |= ( ( u64 )in[ 4] ) << 32;
# case 4: b |= ( ( u64 )in[ 3] ) << 24;
# case 3: b |= ( ( u64 )in[ 2] ) << 16;
# case 2: b |= ( ( u64 )in[ 1] ) << 8;
# case 1: b |= ( ( u64 )in[ 0] ); break;
# case 0: break;
# }
switch ($left) {
case 7:
$b[0] |= self::chrToInt($in[6]) << 16;
case 6:
$b[0] |= self::chrToInt($in[5]) << 8;
case 5:
$b[0] |= self::chrToInt($in[4]);
case 4:
$b[1] |= self::chrToInt($in[3]) << 24;
case 3:
$b[1] |= self::chrToInt($in[2]) << 16;
case 2:
$b[1] |= self::chrToInt($in[1]) << 8;
case 1:
$b[1] |= self::chrToInt($in[0]);
case 0:
break;
}
// See docblock for why the 0th index gets the higher bits.
# v3 ^= b;
$v[6] ^= $b[0];
$v[7] ^= $b[1];
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= b;
$v[0] ^= $b[0];
$v[1] ^= $b[1];
// Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation
# v2 ^= 0xff;
$v[5] ^= 0xff;
# SIPROUND;
# SIPROUND;
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
# b = v0 ^ v1 ^ v2 ^ v3;
# STORE64_LE( out, b );
return self::store32_le($v[1] ^ $v[3] ^ $v[5] ^ $v[7]) . self::store32_le($v[0] ^ $v[2] ^ $v[4] ^ $v[6]);
}
}
/**
* Class ParagonIE_SodiumCompat_Core_SipHash
*
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers
*/

View File

@@ -0,0 +1,865 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_Util', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Util
*/
abstract class ParagonIE_Sodium_Core_Util
{
const U32_MAX = 0xffffffff;
/**
* @param int $integer
* @param int $size (16, 32, 64)
* @return int
*/
public static function abs($integer, $size = 0)
{
/** @var int $realSize */
$realSize = (\PHP_INT_SIZE << 3) - 1;
if ($size) {
--$size;
} else {
/** @var int $size */
$size = $realSize;
}
$negative = -($integer >> $size & 1);
return (int) (($integer ^ $negative) + ($negative >> $realSize & 1));
}
/**
* @param string $a
* @param string $b
* @return string
* @throws SodiumException
*/
public static function andStrings($a, $b)
{
/* Type checks: */
if (!\is_string($a)) {
throw new \TypeError('Argument 1 must be a string');
}
if (!\is_string($b)) {
throw new \TypeError('Argument 2 must be a string');
}
$len = self::strlen($a);
if (self::strlen($b) !== $len) {
throw new \SodiumException('Both strings must be of equal length to combine with bitwise AND');
}
return $a & $b;
}
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks
*
* @internal You should not use this directly from another application
*
* @param string $binaryString (raw binary)
* @return string
* @throws TypeError
*/
public static function bin2hex($binaryString)
{
/* Type checks: */
if (!\is_string($binaryString)) {
throw new \TypeError('Argument 1 must be a string, ' . \gettype($binaryString) . ' given.');
}
$hex = '';
$len = self::strlen($binaryString);
for ($i = 0; $i < $len; ++$i) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C', $binaryString[$i]);
/** @var int $c */
$c = $chunk[1] & 0xf;
/** @var int $b */
$b = $chunk[1] >> 4;
$hex .= \pack('CC', 87 + $b + ($b - 10 >> 8 & ~38), 87 + $c + ($c - 10 >> 8 & ~38));
}
return $hex;
}
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks, returning uppercase letters (as per RFC 4648)
*
* @internal You should not use this directly from another application
*
* @param string $bin_string (raw binary)
* @return string
* @throws TypeError
*/
public static function bin2hexUpper($bin_string)
{
$hex = '';
$len = self::strlen($bin_string);
for ($i = 0; $i < $len; ++$i) {
/** @var array<int, int> $chunk */
$chunk = \unpack('C', $bin_string[$i]);
/**
* Lower 16 bits
*
* @var int $c
*/
$c = $chunk[1] & 0xf;
/**
* Upper 16 bits
* @var int $b
*/
$b = $chunk[1] >> 4;
/**
* Use pack() and binary operators to turn the two integers
* into hexadecimal characters. We don't use chr() here, because
* it uses a lookup table internally and we want to avoid
* cache-timing side-channels.
*/
$hex .= \pack('CC', 55 + $b + ($b - 10 >> 8 & ~6), 55 + $c + ($c - 10 >> 8 & ~6));
}
return $hex;
}
/**
* Cache-timing-safe variant of ord()
*
* @internal You should not use this directly from another application
*
* @param string $chr
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function chrToInt($chr)
{
/* Type checks: */
if (!\is_string($chr)) {
throw new \TypeError('Argument 1 must be a string, ' . \gettype($chr) . ' given.');
}
if (self::strlen($chr) !== 1) {
throw new \SodiumException('chrToInt() expects a string that is exactly 1 character long');
}
/** @var array<int, int> $chunk */
$chunk = \unpack('C', $chr);
return (int) $chunk[1];
}
/**
* Compares two strings.
*
* @internal You should not use this directly from another application
*
* @param string $left
* @param string $right
* @param int $len
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function compare($left, $right, $len = null)
{
$leftLen = self::strlen($left);
$rightLen = self::strlen($right);
if ($len === null) {
$len = \max($leftLen, $rightLen);
$left = \str_pad($left, $len, "\x00", \STR_PAD_RIGHT);
$right = \str_pad($right, $len, "\x00", \STR_PAD_RIGHT);
}
$gt = 0;
$eq = 1;
$i = $len;
while ($i !== 0) {
--$i;
$gt |= self::chrToInt($right[$i]) - self::chrToInt($left[$i]) >> 8 & $eq;
$eq &= (self::chrToInt($right[$i]) ^ self::chrToInt($left[$i])) - 1 >> 8;
}
return $gt + $gt + $eq - 1;
}
/**
* If a variable does not match a given type, throw a TypeError.
*
* @param mixed $mixedVar
* @param string $type
* @param int $argumentIndex
* @throws TypeError
* @throws SodiumException
* @return void
*/
public static function declareScalarType(&$mixedVar = null, $type = 'void', $argumentIndex = 0)
{
if (\func_num_args() === 0) {
/* Tautology, by default */
return;
}
if (\func_num_args() === 1) {
throw new \TypeError('Declared void, but passed a variable');
}
$realType = \strtolower(\gettype($mixedVar));
$type = \strtolower($type);
switch ($type) {
case 'null':
if ($mixedVar !== null) {
throw new \TypeError('Argument ' . $argumentIndex . ' must be null, ' . $realType . ' given.');
}
break;
case 'integer':
case 'int':
$allow = array('int', 'integer');
if (!\in_array($type, $allow)) {
throw new \TypeError('Argument ' . $argumentIndex . ' must be an integer, ' . $realType . ' given.');
}
$mixedVar = (int) $mixedVar;
break;
case 'boolean':
case 'bool':
$allow = array('bool', 'boolean');
if (!\in_array($type, $allow)) {
throw new \TypeError('Argument ' . $argumentIndex . ' must be a boolean, ' . $realType . ' given.');
}
$mixedVar = (bool) $mixedVar;
break;
case 'string':
if (!\is_string($mixedVar)) {
throw new \TypeError('Argument ' . $argumentIndex . ' must be a string, ' . $realType . ' given.');
}
$mixedVar = (string) $mixedVar;
break;
case 'decimal':
case 'double':
case 'float':
$allow = array('decimal', 'double', 'float');
if (!\in_array($type, $allow)) {
throw new \TypeError('Argument ' . $argumentIndex . ' must be a float, ' . $realType . ' given.');
}
$mixedVar = (float) $mixedVar;
break;
case 'object':
if (!\is_object($mixedVar)) {
throw new \TypeError('Argument ' . $argumentIndex . ' must be an object, ' . $realType . ' given.');
}
break;
case 'array':
if (!\is_array($mixedVar)) {
if (\is_object($mixedVar)) {
if ($mixedVar instanceof \ArrayAccess) {
return;
}
}
throw new \TypeError('Argument ' . $argumentIndex . ' must be an array, ' . $realType . ' given.');
}
break;
default:
throw new \SodiumException('Unknown type (' . $realType . ') does not match expect type (' . $type . ')');
}
}
/**
* Evaluate whether or not two strings are equal (in constant-time)
*
* @param string $left
* @param string $right
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function hashEquals($left, $right)
{
/* Type checks: */
if (!\is_string($left)) {
throw new \TypeError('Argument 1 must be a string, ' . \gettype($left) . ' given.');
}
if (!\is_string($right)) {
throw new \TypeError('Argument 2 must be a string, ' . \gettype($right) . ' given.');
}
if (\is_callable('hash_equals')) {
return \hash_equals($left, $right);
}
$d = 0;
/** @var int $len */
$len = self::strlen($left);
if ($len !== self::strlen($right)) {
return \false;
}
for ($i = 0; $i < $len; ++$i) {
$d |= self::chrToInt($left[$i]) ^ self::chrToInt($right[$i]);
}
if ($d !== 0) {
return \false;
}
return $left === $right;
}
/**
* Catch hash_update() failures and throw instead of silently proceeding
*
* @param HashContext|resource &$hs
* @param string $data
* @return void
* @throws SodiumException
* @psalm-suppress PossiblyInvalidArgument
*/
protected static function hash_update(&$hs, $data)
{
if (!\hash_update($hs, $data)) {
throw new \SodiumException('hash_update() failed');
}
}
/**
* Convert a hexadecimal string into a binary string without cache-timing
* leaks
*
* @internal You should not use this directly from another application
*
* @param string $hexString
* @param string $ignore
* @param bool $strictPadding
* @return string (raw binary)
* @throws RangeException
* @throws TypeError
*/
public static function hex2bin($hexString, $ignore = '', $strictPadding = \false)
{
/* Type checks: */
if (!\is_string($hexString)) {
throw new \TypeError('Argument 1 must be a string, ' . \gettype($hexString) . ' given.');
}
if (!\is_string($ignore)) {
throw new \TypeError('Argument 2 must be a string, ' . \gettype($hexString) . ' given.');
}
$hex_pos = 0;
$bin = '';
$c_acc = 0;
$hex_len = self::strlen($hexString);
$state = 0;
if (($hex_len & 1) !== 0) {
if ($strictPadding) {
throw new \RangeException('Expected an even number of hexadecimal characters');
} else {
$hexString = '0' . $hexString;
++$hex_len;
}
}
$chunk = \unpack('C*', $hexString);
while ($hex_pos < $hex_len) {
++$hex_pos;
/** @var int $c */
$c = $chunk[$hex_pos];
$c_num = $c ^ 48;
$c_num0 = $c_num - 10 >> 8;
$c_alpha = ($c & ~32) - 55;
$c_alpha0 = ($c_alpha - 10 ^ $c_alpha - 16) >> 8;
if (($c_num0 | $c_alpha0) === 0) {
if ($ignore && $state === 0 && \strpos($ignore, self::intToChr($c)) !== \false) {
continue;
}
throw new \RangeException('hex2bin() only expects hexadecimal characters');
}
$c_val = $c_num0 & $c_num | $c_alpha & $c_alpha0;
if ($state === 0) {
$c_acc = $c_val * 16;
} else {
$bin .= \pack('C', $c_acc | $c_val);
}
$state ^= 1;
}
return $bin;
}
/**
* Turn an array of integers into a string
*
* @internal You should not use this directly from another application
*
* @param array<int, int> $ints
* @return string
*/
public static function intArrayToString(array $ints)
{
$args = $ints;
foreach ($args as $i => $v) {
$args[$i] = (int) ($v & 0xff);
}
\array_unshift($args, \str_repeat('C', \count($ints)));
return (string) \call_user_func_array('pack', $args);
}
/**
* Cache-timing-safe variant of ord()
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function intToChr($int)
{
return \pack('C', $int);
}
/**
* Load a 3 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws TypeError
*/
public static function load_3($string)
{
/* Type checks: */
if (!\is_string($string)) {
throw new \TypeError('Argument 1 must be a string, ' . \gettype($string) . ' given.');
}
/* Input validation: */
if (self::strlen($string) < 3) {
throw new \RangeException('String must be 3 bytes or more; ' . self::strlen($string) . ' given.');
}
/** @var array<int, int> $unpacked */
$unpacked = \unpack('V', $string . "\x00");
return (int) ($unpacked[1] & 0xffffff);
}
/**
* Load a 4 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws TypeError
*/
public static function load_4($string)
{
/* Type checks: */
if (!\is_string($string)) {
throw new \TypeError('Argument 1 must be a string, ' . \gettype($string) . ' given.');
}
/* Input validation: */
if (self::strlen($string) < 4) {
throw new \RangeException('String must be 4 bytes or more; ' . self::strlen($string) . ' given.');
}
/** @var array<int, int> $unpacked */
$unpacked = \unpack('V', $string);
return (int) $unpacked[1];
}
/**
* Load a 8 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function load64_le($string)
{
/* Type checks: */
if (!\is_string($string)) {
throw new \TypeError('Argument 1 must be a string, ' . \gettype($string) . ' given.');
}
/* Input validation: */
if (self::strlen($string) < 4) {
throw new \RangeException('String must be 4 bytes or more; ' . self::strlen($string) . ' given.');
}
if (\PHP_VERSION_ID >= 50603 && \PHP_INT_SIZE === 8) {
/** @var array<int, int> $unpacked */
$unpacked = \unpack('P', $string);
return (int) $unpacked[1];
}
/** @var int $result */
$result = self::chrToInt($string[0]) & 0xff;
$result |= (self::chrToInt($string[1]) & 0xff) << 8;
$result |= (self::chrToInt($string[2]) & 0xff) << 16;
$result |= (self::chrToInt($string[3]) & 0xff) << 24;
$result |= (self::chrToInt($string[4]) & 0xff) << 32;
$result |= (self::chrToInt($string[5]) & 0xff) << 40;
$result |= (self::chrToInt($string[6]) & 0xff) << 48;
$result |= (self::chrToInt($string[7]) & 0xff) << 56;
return (int) $result;
}
/**
* @internal You should not use this directly from another application
*
* @param string $left
* @param string $right
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function memcmp($left, $right)
{
if (self::hashEquals($left, $right)) {
return 0;
}
return -1;
}
/**
* Multiply two integers in constant-time
*
* Micro-architecture timing side-channels caused by how your CPU
* implements multiplication are best prevented by never using the
* multiplication operators and ensuring that our code always takes
* the same number of operations to complete, regardless of the values
* of $a and $b.
*
* @internal You should not use this directly from another application
*
* @param int $a
* @param int $b
* @param int $size Limits the number of operations (useful for small,
* constant operands)
* @return int
*/
public static function mul($a, $b, $size = 0)
{
if (\ParagonIE_Sodium_Compat::$fastMult) {
return (int) ($a * $b);
}
static $defaultSize = null;
/** @var int $defaultSize */
if (!$defaultSize) {
/** @var int $defaultSize */
$defaultSize = (\PHP_INT_SIZE << 3) - 1;
}
if ($size < 1) {
/** @var int $size */
$size = $defaultSize;
}
/** @var int $size */
$c = 0;
/**
* Mask is either -1 or 0.
*
* -1 in binary looks like 0x1111 ... 1111
* 0 in binary looks like 0x0000 ... 0000
*
* @var int
*/
$mask = -($b >> (int) $defaultSize & 1);
/**
* Ensure $b is a positive integer, without creating
* a branching side-channel
*
* @var int $b
*/
$b = $b & ~$mask | $mask & -$b;
/**
* Unless $size is provided:
*
* This loop always runs 32 times when PHP_INT_SIZE is 4.
* This loop always runs 64 times when PHP_INT_SIZE is 8.
*/
for ($i = $size; $i >= 0; --$i) {
$c += (int) ($a & -($b & 1));
$a <<= 1;
$b >>= 1;
}
$c = (int) @($c & -1);
/**
* If $b was negative, we then apply the same value to $c here.
* It doesn't matter much if $a was negative; the $c += above would
* have produced a negative integer to begin with. But a negative $b
* makes $b >>= 1 never return 0, so we would end up with incorrect
* results.
*
* The end result is what we'd expect from integer multiplication.
*/
return (int) ($c & ~$mask | $mask & -$c);
}
/**
* Convert any arbitrary numbers into two 32-bit integers that represent
* a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int|float $num
* @return array<int, int>
*/
public static function numericTo64BitInteger($num)
{
$high = 0;
/** @var int $low */
if (\PHP_INT_SIZE === 4) {
$low = (int) $num;
} else {
$low = $num & 0xffffffff;
}
if (+\abs($num) >= 1) {
if ($num > 0) {
/** @var int $high */
$high = \min(+\floor($num / 4294967296), 4294967295);
} else {
/** @var int $high */
$high = ~~+\ceil(($num - +~~$num) / 4294967296);
}
}
return array((int) $high, (int) $low);
}
/**
* Store a 24-bit integer into a string, treating it as big-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store_3($int)
{
/* Type checks: */
if (!\is_int($int)) {
if (\is_numeric($int)) {
$int = (int) $int;
} else {
throw new \TypeError('Argument 1 must be an integer, ' . \gettype($int) . ' given.');
}
}
/** @var string $packed */
$packed = \pack('N', $int);
return self::substr($packed, 1, 3);
}
/**
* Store a 32-bit integer into a string, treating it as little-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store32_le($int)
{
/* Type checks: */
if (!\is_int($int)) {
if (\is_numeric($int)) {
$int = (int) $int;
} else {
throw new \TypeError('Argument 1 must be an integer, ' . \gettype($int) . ' given.');
}
}
/** @var string $packed */
$packed = \pack('V', $int);
return $packed;
}
/**
* Store a 32-bit integer into a string, treating it as big-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store_4($int)
{
/* Type checks: */
if (!\is_int($int)) {
if (\is_numeric($int)) {
$int = (int) $int;
} else {
throw new \TypeError('Argument 1 must be an integer, ' . \gettype($int) . ' given.');
}
}
/** @var string $packed */
$packed = \pack('N', $int);
return $packed;
}
/**
* Stores a 64-bit integer as an string, treating it as little-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store64_le($int)
{
/* Type checks: */
if (!\is_int($int)) {
if (\is_numeric($int)) {
$int = (int) $int;
} else {
throw new \TypeError('Argument 1 must be an integer, ' . \gettype($int) . ' given.');
}
}
if (\PHP_INT_SIZE === 8) {
if (\PHP_VERSION_ID >= 50603) {
/** @var string $packed */
$packed = \pack('P', $int);
return $packed;
}
return self::intToChr($int & 0xff) . self::intToChr($int >> 8 & 0xff) . self::intToChr($int >> 16 & 0xff) . self::intToChr($int >> 24 & 0xff) . self::intToChr($int >> 32 & 0xff) . self::intToChr($int >> 40 & 0xff) . self::intToChr($int >> 48 & 0xff) . self::intToChr($int >> 56 & 0xff);
}
if ($int > \PHP_INT_MAX) {
list($hiB, $int) = self::numericTo64BitInteger($int);
} else {
$hiB = 0;
}
return self::intToChr($int & 0xff) . self::intToChr($int >> 8 & 0xff) . self::intToChr($int >> 16 & 0xff) . self::intToChr($int >> 24 & 0xff) . self::intToChr($hiB & 0xff) . self::intToChr($hiB >> 8 & 0xff) . self::intToChr($hiB >> 16 & 0xff) . self::intToChr($hiB >> 24 & 0xff);
}
/**
* Safe string length
*
* @internal You should not use this directly from another application
*
* @ref mbstring.func_overload
*
* @param string $str
* @return int
* @throws TypeError
*/
public static function strlen($str)
{
/* Type checks: */
if (!\is_string($str)) {
throw new \TypeError('String expected');
}
return (int) (self::isMbStringOverride() ? \mb_strlen($str, '8bit') : \strlen($str));
}
/**
* Turn a string into an array of integers
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return array<int, int>
* @throws TypeError
*/
public static function stringToIntArray($string)
{
if (!\is_string($string)) {
throw new \TypeError('String expected');
}
/**
* @var array<int, int>
*/
$values = \array_values(\unpack('C*', $string));
return $values;
}
/**
* Safe substring
*
* @internal You should not use this directly from another application
*
* @ref mbstring.func_overload
*
* @param string $str
* @param int $start
* @param int $length
* @return string
* @throws TypeError
*/
public static function substr($str, $start = 0, $length = null)
{
/* Type checks: */
if (!\is_string($str)) {
throw new \TypeError('String expected');
}
if ($length === 0) {
return '';
}
if (self::isMbStringOverride()) {
if (\PHP_VERSION_ID < 50400 && $length === null) {
$length = self::strlen($str);
}
$sub = (string) \mb_substr($str, $start, $length, '8bit');
} elseif ($length === null) {
$sub = (string) \substr($str, $start);
} else {
$sub = (string) \substr($str, $start, $length);
}
if ($sub !== '') {
return $sub;
}
return '';
}
/**
* Compare a 16-character byte string in constant time.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_16($a, $b)
{
/* Type checks: */
if (!\is_string($a)) {
throw new \TypeError('String expected');
}
if (!\is_string($b)) {
throw new \TypeError('String expected');
}
return self::hashEquals(self::substr($a, 0, 16), self::substr($b, 0, 16));
}
/**
* Compare a 32-character byte string in constant time.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_32($a, $b)
{
/* Type checks: */
if (!\is_string($a)) {
throw new \TypeError('String expected');
}
if (!\is_string($b)) {
throw new \TypeError('String expected');
}
return self::hashEquals(self::substr($a, 0, 32), self::substr($b, 0, 32));
}
/**
* Calculate $a ^ $b for two strings.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return string
* @throws TypeError
*/
public static function xorStrings($a, $b)
{
/* Type checks: */
if (!\is_string($a)) {
throw new \TypeError('Argument 1 must be a string');
}
if (!\is_string($b)) {
throw new \TypeError('Argument 2 must be a string');
}
return (string) ($a ^ $b);
}
/**
* Returns whether or not mbstring.func_overload is in effect.
*
* @internal You should not use this directly from another application
*
* Note: MB_OVERLOAD_STRING === 2, but we don't reference the constant
* (for nuisance-free PHP 8 support)
*
* @return bool
*/
protected static function isMbStringOverride()
{
static $mbstring = null;
if ($mbstring === null) {
if (!\defined('MB_OVERLOAD_STRING')) {
$mbstring = \false;
return $mbstring;
}
$mbstring = \extension_loaded('mbstring') && \defined('MB_OVERLOAD_STRING') && (int) \ini_get('mbstring.func_overload') & 2;
// MB_OVERLOAD_STRING === 2
}
/** @var bool $mbstring */
return $mbstring;
}
}
/**
* Class ParagonIE_Sodium_Core_Util
*/

View File

@@ -0,0 +1,269 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_X25519', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_X25519
*/
abstract class ParagonIE_Sodium_Core_X25519 extends \ParagonIE_Sodium_Core_Curve25519
{
/**
* Alters the objects passed to this method in place.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @param int $b
* @return void
* @psalm-suppress MixedAssignment
*/
public static function fe_cswap(\ParagonIE_Sodium_Core_Curve25519_Fe $f, \ParagonIE_Sodium_Core_Curve25519_Fe $g, $b = 0)
{
$f0 = (int) $f[0];
$f1 = (int) $f[1];
$f2 = (int) $f[2];
$f3 = (int) $f[3];
$f4 = (int) $f[4];
$f5 = (int) $f[5];
$f6 = (int) $f[6];
$f7 = (int) $f[7];
$f8 = (int) $f[8];
$f9 = (int) $f[9];
$g0 = (int) $g[0];
$g1 = (int) $g[1];
$g2 = (int) $g[2];
$g3 = (int) $g[3];
$g4 = (int) $g[4];
$g5 = (int) $g[5];
$g6 = (int) $g[6];
$g7 = (int) $g[7];
$g8 = (int) $g[8];
$g9 = (int) $g[9];
$b = -$b;
$x0 = ($f0 ^ $g0) & $b;
$x1 = ($f1 ^ $g1) & $b;
$x2 = ($f2 ^ $g2) & $b;
$x3 = ($f3 ^ $g3) & $b;
$x4 = ($f4 ^ $g4) & $b;
$x5 = ($f5 ^ $g5) & $b;
$x6 = ($f6 ^ $g6) & $b;
$x7 = ($f7 ^ $g7) & $b;
$x8 = ($f8 ^ $g8) & $b;
$x9 = ($f9 ^ $g9) & $b;
$f[0] = $f0 ^ $x0;
$f[1] = $f1 ^ $x1;
$f[2] = $f2 ^ $x2;
$f[3] = $f3 ^ $x3;
$f[4] = $f4 ^ $x4;
$f[5] = $f5 ^ $x5;
$f[6] = $f6 ^ $x6;
$f[7] = $f7 ^ $x7;
$f[8] = $f8 ^ $x8;
$f[9] = $f9 ^ $x9;
$g[0] = $g0 ^ $x0;
$g[1] = $g1 ^ $x1;
$g[2] = $g2 ^ $x2;
$g[3] = $g3 ^ $x3;
$g[4] = $g4 ^ $x4;
$g[5] = $g5 ^ $x5;
$g[6] = $g6 ^ $x6;
$g[7] = $g7 ^ $x7;
$g[8] = $g8 ^ $x8;
$g[9] = $g9 ^ $x9;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_mul121666(\ParagonIE_Sodium_Core_Curve25519_Fe $f)
{
$h = array(self::mul((int) $f[0], 121666, 17), self::mul((int) $f[1], 121666, 17), self::mul((int) $f[2], 121666, 17), self::mul((int) $f[3], 121666, 17), self::mul((int) $f[4], 121666, 17), self::mul((int) $f[5], 121666, 17), self::mul((int) $f[6], 121666, 17), self::mul((int) $f[7], 121666, 17), self::mul((int) $f[8], 121666, 17), self::mul((int) $f[9], 121666, 17));
/** @var int $carry9 */
$carry9 = $h[9] + (1 << 24) >> 25;
$h[0] += self::mul($carry9, 19, 5);
$h[9] -= $carry9 << 25;
/** @var int $carry1 */
$carry1 = $h[1] + (1 << 24) >> 25;
$h[2] += $carry1;
$h[1] -= $carry1 << 25;
/** @var int $carry3 */
$carry3 = $h[3] + (1 << 24) >> 25;
$h[4] += $carry3;
$h[3] -= $carry3 << 25;
/** @var int $carry5 */
$carry5 = $h[5] + (1 << 24) >> 25;
$h[6] += $carry5;
$h[5] -= $carry5 << 25;
/** @var int $carry7 */
$carry7 = $h[7] + (1 << 24) >> 25;
$h[8] += $carry7;
$h[7] -= $carry7 << 25;
/** @var int $carry0 */
$carry0 = $h[0] + (1 << 25) >> 26;
$h[1] += $carry0;
$h[0] -= $carry0 << 26;
/** @var int $carry2 */
$carry2 = $h[2] + (1 << 25) >> 26;
$h[3] += $carry2;
$h[2] -= $carry2 << 26;
/** @var int $carry4 */
$carry4 = $h[4] + (1 << 25) >> 26;
$h[5] += $carry4;
$h[4] -= $carry4 << 26;
/** @var int $carry6 */
$carry6 = $h[6] + (1 << 25) >> 26;
$h[7] += $carry6;
$h[6] -= $carry6 << 26;
/** @var int $carry8 */
$carry8 = $h[8] + (1 << 25) >> 26;
$h[9] += $carry8;
$h[8] -= $carry8 << 26;
foreach ($h as $i => $value) {
$h[$i] = (int) $value;
}
return \ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h);
}
/**
* @internal You should not use this directly from another application
*
* Inline comments preceded by # are from libsodium's ref10 code.
*
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10($n, $p)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(self::chrToInt($e[0]) & 248);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(self::chrToInt($e[31]) & 127 | 64);
# fe_frombytes(x1,p);
$x1 = self::fe_frombytes($p);
# fe_1(x2);
$x2 = self::fe_1();
# fe_0(z2);
$z2 = self::fe_0();
# fe_copy(x3,x1);
$x3 = self::fe_copy($x1);
# fe_1(z3);
$z3 = self::fe_1();
# swap = 0;
/** @var int $swap */
$swap = 0;
# for (pos = 254;pos >= 0;--pos) {
for ($pos = 254; $pos >= 0; --$pos) {
# b = e[pos / 8] >> (pos & 7);
/** @var int $b */
$b = self::chrToInt($e[(int) \floor($pos / 8)]) >> ($pos & 7);
# b &= 1;
$b &= 1;
# swap ^= b;
$swap ^= $b;
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# swap = b;
$swap = $b;
# fe_sub(tmp0,x3,z3);
$tmp0 = self::fe_sub($x3, $z3);
# fe_sub(tmp1,x2,z2);
$tmp1 = self::fe_sub($x2, $z2);
# fe_add(x2,x2,z2);
$x2 = self::fe_add($x2, $z2);
# fe_add(z2,x3,z3);
$z2 = self::fe_add($x3, $z3);
# fe_mul(z3,tmp0,x2);
$z3 = self::fe_mul($tmp0, $x2);
# fe_mul(z2,z2,tmp1);
$z2 = self::fe_mul($z2, $tmp1);
# fe_sq(tmp0,tmp1);
$tmp0 = self::fe_sq($tmp1);
# fe_sq(tmp1,x2);
$tmp1 = self::fe_sq($x2);
# fe_add(x3,z3,z2);
$x3 = self::fe_add($z3, $z2);
# fe_sub(z2,z3,z2);
$z2 = self::fe_sub($z3, $z2);
# fe_mul(x2,tmp1,tmp0);
$x2 = self::fe_mul($tmp1, $tmp0);
# fe_sub(tmp1,tmp1,tmp0);
$tmp1 = self::fe_sub($tmp1, $tmp0);
# fe_sq(z2,z2);
$z2 = self::fe_sq($z2);
# fe_mul121666(z3,tmp1);
$z3 = self::fe_mul121666($tmp1);
# fe_sq(x3,x3);
$x3 = self::fe_sq($x3);
# fe_add(tmp0,tmp0,z3);
$tmp0 = self::fe_add($tmp0, $z3);
# fe_mul(z3,x1,z2);
$z3 = self::fe_mul($x1, $z2);
# fe_mul(z2,tmp1,tmp0);
$z2 = self::fe_mul($tmp1, $tmp0);
}
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# fe_invert(z2,z2);
$z2 = self::fe_invert($z2);
# fe_mul(x2,x2,z2);
$x2 = self::fe_mul($x2, $z2);
# fe_tobytes(q,x2);
return self::fe_tobytes($x2);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY
* @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function edwards_to_montgomery(\ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY, \ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ)
{
$tempX = self::fe_add($edwardsZ, $edwardsY);
$tempZ = self::fe_sub($edwardsZ, $edwardsY);
$tempZ = self::fe_invert($tempZ);
return self::fe_mul($tempX, $tempZ);
}
/**
* @internal You should not use this directly from another application
*
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10_base($n)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(self::chrToInt($e[0]) & 248);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(self::chrToInt($e[31]) & 127 | 64);
$A = self::ge_scalarmult_base($e);
if (!$A->Y instanceof \ParagonIE_Sodium_Core_Curve25519_Fe || !$A->Z instanceof \ParagonIE_Sodium_Core_Curve25519_Fe) {
throw new \TypeError('Null points encountered');
}
$pk = self::edwards_to_montgomery($A->Y, $A->Z);
return self::fe_tobytes($pk);
}
}
/**
* Class ParagonIE_Sodium_Core_X25519
*/

View File

@@ -0,0 +1,86 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_XChaCha20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_XChaCha20
*/
class ParagonIE_Sodium_Core_XChaCha20 extends \ParagonIE_Sodium_Core_HChaCha20
{
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key = '')
{
if (self::strlen($nonce) !== 24) {
throw new \SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(new \ParagonIE_Sodium_Core_ChaCha20_Ctx(self::hChaCha20(self::substr($nonce, 0, 16), $key), self::substr($nonce, 16, 8)), \str_repeat("\x00", $len));
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStream($len = 64, $nonce = '', $key = '')
{
if (self::strlen($nonce) !== 24) {
throw new \SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(new \ParagonIE_Sodium_Core_ChaCha20_IetfCtx(self::hChaCha20(self::substr($nonce, 0, 16), $key), "\x00\x00\x00\x00" . self::substr($nonce, 16, 8)), \str_repeat("\x00", $len));
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
{
if (self::strlen($nonce) !== 24) {
throw new \SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(new \ParagonIE_Sodium_Core_ChaCha20_Ctx(self::hChaCha20(self::substr($nonce, 0, 16), $key), self::substr($nonce, 16, 8), $ic), $message);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
{
if (self::strlen($nonce) !== 24) {
throw new \SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(new \ParagonIE_Sodium_Core_ChaCha20_IetfCtx(self::hChaCha20(self::substr($nonce, 0, 16), $key), "\x00\x00\x00\x00" . self::substr($nonce, 16, 8), $ic), $message);
}
}
/**
* Class ParagonIE_Sodium_Core_XChaCha20
*/

View File

@@ -0,0 +1,49 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_XSalsa20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_XSalsa20
*/
abstract class ParagonIE_Sodium_Core_XSalsa20 extends \ParagonIE_Sodium_Core_HSalsa20
{
/**
* Expand a key and nonce into an xsalsa20 keystream.
*
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20($len, $nonce, $key)
{
$ret = self::salsa20($len, self::substr($nonce, 16, 8), self::hsalsa20($nonce, $key));
return $ret;
}
/**
* Encrypt a string with XSalsa20. Doesn't provide integrity.
*
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20_xor($message, $nonce, $key)
{
return self::xorStrings($message, self::xsalsa20(self::strlen($message), $nonce, $key));
}
}
/**
* Class ParagonIE_Sodium_Core_XSalsa20
*/

View File

@@ -0,0 +1,618 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_BLAKE2b', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_BLAKE2b
*
* Based on the work of Devi Mandiri in devi/salt.
*/
abstract class ParagonIE_Sodium_Core32_BLAKE2b extends \ParagonIE_Sodium_Core_Util
{
/**
* @var SplFixedArray
*/
public static $iv;
/**
* @var array<int, array<int, int>>
*/
public static $sigma = array(array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3), array(11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4), array(7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8), array(9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13), array(2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9), array(12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11), array(13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10), array(6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5), array(10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0), array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), array(14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3));
const BLOCKBYTES = 128;
const OUTBYTES = 64;
const KEYBYTES = 64;
/**
* Turn two 32-bit integers into a fixed array representing a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $high
* @param int $low
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public static function new64($high, $low)
{
return \ParagonIE_Sodium_Core32_Int64::fromInts($low, $high);
}
/**
* Convert an arbitrary number into an SplFixedArray of two 32-bit integers
* that represents a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $num
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
protected static function to64($num)
{
list($hi, $lo) = self::numericTo64BitInteger($num);
return self::new64($hi, $lo);
}
/**
* Adds two 64-bit integers together, returning their sum as a SplFixedArray
* containing two 32-bit integers (representing a 64-bit integer).
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param ParagonIE_Sodium_Core32_Int64 $y
* @return ParagonIE_Sodium_Core32_Int64
*/
protected static function add64($x, $y)
{
return $x->addInt64($y);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param ParagonIE_Sodium_Core32_Int64 $y
* @param ParagonIE_Sodium_Core32_Int64 $z
* @return ParagonIE_Sodium_Core32_Int64
*/
public static function add364($x, $y, $z)
{
return $x->addInt64($y)->addInt64($z);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param ParagonIE_Sodium_Core32_Int64 $y
* @return ParagonIE_Sodium_Core32_Int64
* @throws TypeError
*/
public static function xor64(\ParagonIE_Sodium_Core32_Int64 $x, \ParagonIE_Sodium_Core32_Int64 $y)
{
return $x->xorInt64($y);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int64 $x
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public static function rotr64(\ParagonIE_Sodium_Core32_Int64 $x, $c)
{
return $x->rotateRight($c);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public static function load64($x, $i)
{
/** @var int $l */
$l = (int) $x[$i] | (int) $x[$i + 1] << 8 | (int) $x[$i + 2] << 16 | (int) $x[$i + 3] << 24;
/** @var int $h */
$h = (int) $x[$i + 4] | (int) $x[$i + 5] << 8 | (int) $x[$i + 6] << 16 | (int) $x[$i + 7] << 24;
return self::new64($h, $l);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @param ParagonIE_Sodium_Core32_Int64 $u
* @return void
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
*/
public static function store64(\SplFixedArray $x, $i, \ParagonIE_Sodium_Core32_Int64 $u)
{
$v = clone $u;
$maxLength = $x->getSize() - 1;
for ($j = 0; $j < 8; ++$j) {
$k = 3 - ($j >> 1);
$x[$i] = $v->limbs[$k] & 0xff;
if (++$i > $maxLength) {
return;
}
$v->limbs[$k] >>= 8;
}
}
/**
* This just sets the $iv static variable.
*
* @internal You should not use this directly from another application
*
* @return void
* @throws SodiumException
* @throws TypeError
*/
public static function pseudoConstructor()
{
static $called = \false;
if ($called) {
return;
}
self::$iv = new \SplFixedArray(8);
self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908);
self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b);
self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b);
self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1);
self::$iv[4] = self::new64(0x510e527f, 0xade682d1);
self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f);
self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b);
self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179);
$called = \true;
}
/**
* Returns a fresh BLAKE2 context.
*
* @internal You should not use this directly from another application
*
* @return SplFixedArray
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @throws SodiumException
* @throws TypeError
*/
protected static function context()
{
$ctx = new \SplFixedArray(6);
$ctx[0] = new \SplFixedArray(8);
// h
$ctx[1] = new \SplFixedArray(2);
// t
$ctx[2] = new \SplFixedArray(2);
// f
$ctx[3] = new \SplFixedArray(256);
// buf
$ctx[4] = 0;
// buflen
$ctx[5] = 0;
// last_node (uint8_t)
for ($i = 8; $i--;) {
$ctx[0][$i] = self::$iv[$i];
}
for ($i = 256; $i--;) {
$ctx[3][$i] = 0;
}
$zero = self::new64(0, 0);
$ctx[1][0] = $zero;
$ctx[1][1] = $zero;
$ctx[2][0] = $zero;
$ctx[2][1] = $zero;
return $ctx;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $buf
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedAssignment
*/
protected static function compress(\SplFixedArray $ctx, \SplFixedArray $buf)
{
$m = new \SplFixedArray(16);
$v = new \SplFixedArray(16);
for ($i = 16; $i--;) {
$m[$i] = self::load64($buf, $i << 3);
}
for ($i = 8; $i--;) {
$v[$i] = $ctx[0][$i];
}
$v[8] = self::$iv[0];
$v[9] = self::$iv[1];
$v[10] = self::$iv[2];
$v[11] = self::$iv[3];
$v[12] = self::xor64($ctx[1][0], self::$iv[4]);
$v[13] = self::xor64($ctx[1][1], self::$iv[5]);
$v[14] = self::xor64($ctx[2][0], self::$iv[6]);
$v[15] = self::xor64($ctx[2][1], self::$iv[7]);
for ($r = 0; $r < 12; ++$r) {
$v = self::G($r, 0, 0, 4, 8, 12, $v, $m);
$v = self::G($r, 1, 1, 5, 9, 13, $v, $m);
$v = self::G($r, 2, 2, 6, 10, 14, $v, $m);
$v = self::G($r, 3, 3, 7, 11, 15, $v, $m);
$v = self::G($r, 4, 0, 5, 10, 15, $v, $m);
$v = self::G($r, 5, 1, 6, 11, 12, $v, $m);
$v = self::G($r, 6, 2, 7, 8, 13, $v, $m);
$v = self::G($r, 7, 3, 4, 9, 14, $v, $m);
}
for ($i = 8; $i--;) {
$ctx[0][$i] = self::xor64($ctx[0][$i], self::xor64($v[$i], $v[$i + 8]));
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $r
* @param int $i
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @param SplFixedArray $v
* @param SplFixedArray $m
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayOffset
*/
public static function G($r, $i, $a, $b, $c, $d, \SplFixedArray $v, \SplFixedArray $m)
{
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i << 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24);
$v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i << 1) + 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param int $inc
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
public static function increment_counter($ctx, $inc)
{
if ($inc < 0) {
throw new \SodiumException('Increasing by a negative number makes no sense.');
}
$t = self::to64($inc);
# S->t is $ctx[1] in our implementation
# S->t[0] = ( uint64_t )( t >> 0 );
$ctx[1][0] = self::add64($ctx[1][0], $t);
# S->t[1] += ( S->t[0] < inc );
if (!$ctx[1][0] instanceof \ParagonIE_Sodium_Core32_Int64) {
throw new \TypeError('Not an int64');
}
/** @var ParagonIE_Sodium_Core32_Int64 $c*/
$c = $ctx[1][0];
if ($c->isLessThanInt($inc)) {
$ctx[1][1] = self::add64($ctx[1][1], self::to64(1));
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $p
* @param int $plen
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedOperand
*/
public static function update(\SplFixedArray $ctx, \SplFixedArray $p, $plen)
{
self::pseudoConstructor();
$offset = 0;
while ($plen > 0) {
$left = $ctx[4];
$fill = 256 - $left;
if ($plen > $fill) {
# memcpy( S->buf + left, in, fill ); /* Fill buffer */
for ($i = $fill; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
# S->buflen += fill;
$ctx[4] += $fill;
# blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
self::increment_counter($ctx, 128);
# blake2b_compress( S, S->buf ); /* Compress */
self::compress($ctx, $ctx[3]);
# memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */
for ($i = 128; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
# S->buflen -= BLAKE2B_BLOCKBYTES;
$ctx[4] -= 128;
# in += fill;
$offset += $fill;
# inlen -= fill;
$plen -= $fill;
} else {
for ($i = $plen; $i--;) {
$ctx[3][$i + $left] = $p[$i + $offset];
}
$ctx[4] += $plen;
$offset += $plen;
$plen -= $plen;
}
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $out
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedArrayOffset
* @psalm-suppress MixedMethodCall
* @psalm-suppress MixedOperand
*/
public static function finish(\SplFixedArray $ctx, \SplFixedArray $out)
{
self::pseudoConstructor();
if ($ctx[4] > 128) {
self::increment_counter($ctx, 128);
self::compress($ctx, $ctx[3]);
$ctx[4] -= 128;
if ($ctx[4] > 128) {
throw new \SodiumException('Failed to assert that buflen <= 128 bytes');
}
for ($i = $ctx[4]; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
}
self::increment_counter($ctx, $ctx[4]);
$ctx[2][0] = self::new64(0xffffffff, 0xffffffff);
for ($i = 256 - $ctx[4]; $i--;) {
/** @var int $i */
$ctx[3][$i + $ctx[4]] = 0;
}
self::compress($ctx, $ctx[3]);
$i = (int) (($out->getSize() - 1) / 8);
for (; $i >= 0; --$i) {
self::store64($out, $i << 3, $ctx[0][$i]);
}
return $out;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray|null $key
* @param int $outlen
* @param SplFixedArray|null $salt
* @param SplFixedArray|null $personal
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedMethodCall
*/
public static function init($key = null, $outlen = 64, $salt = null, $personal = null)
{
self::pseudoConstructor();
$klen = 0;
if ($key !== null) {
if (\count($key) > 64) {
throw new \SodiumException('Invalid key size');
}
$klen = \count($key);
}
if ($outlen > 64) {
throw new \SodiumException('Invalid output size');
}
$ctx = self::context();
$p = new \SplFixedArray(64);
// Zero our param buffer...
for ($i = 64; --$i;) {
$p[$i] = 0;
}
$p[0] = $outlen;
// digest_length
$p[1] = $klen;
// key_length
$p[2] = 1;
// fanout
$p[3] = 1;
// depth
if ($salt instanceof \SplFixedArray) {
// salt: [32] through [47]
for ($i = 0; $i < 16; ++$i) {
$p[32 + $i] = (int) $salt[$i];
}
}
if ($personal instanceof \SplFixedArray) {
// personal: [48] through [63]
for ($i = 0; $i < 16; ++$i) {
$p[48 + $i] = (int) $personal[$i];
}
}
$ctx[0][0] = self::xor64($ctx[0][0], self::load64($p, 0));
if ($salt instanceof \SplFixedArray || $personal instanceof \SplFixedArray) {
// We need to do what blake2b_init_param() does:
for ($i = 1; $i < 8; ++$i) {
$ctx[0][$i] = self::xor64($ctx[0][$i], self::load64($p, $i << 3));
}
}
if ($klen > 0 && $key instanceof \SplFixedArray) {
$block = new \SplFixedArray(128);
for ($i = 128; $i--;) {
$block[$i] = 0;
}
for ($i = $klen; $i--;) {
$block[$i] = $key[$i];
}
self::update($ctx, $block, 128);
$ctx[4] = 128;
}
return $ctx;
}
/**
* Convert a string into an SplFixedArray of integers
*
* @internal You should not use this directly from another application
*
* @param string $str
* @return SplFixedArray
* @psalm-suppress MixedArgumentTypeCoercion
*/
public static function stringToSplFixedArray($str = '')
{
$values = \unpack('C*', $str);
return \SplFixedArray::fromArray(\array_values($values));
}
/**
* Convert an SplFixedArray of integers into a string
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $a
* @return string
*/
public static function SplFixedArrayToString(\SplFixedArray $a)
{
/**
* @var array<int, string|int>
*/
$arr = $a->toArray();
$c = $a->count();
\array_unshift($arr, \str_repeat('C', $c));
return (string) \call_user_func_array('pack', $arr);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @return string
* @throws TypeError
* @psalm-suppress MixedArgument
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
* @psalm-suppress MixedMethodCall
*/
public static function contextToString(\SplFixedArray $ctx)
{
$str = '';
/** @var array<int, ParagonIE_Sodium_Core32_Int64> $ctxA */
$ctxA = $ctx[0]->toArray();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
if (!$ctxA[$i] instanceof \ParagonIE_Sodium_Core32_Int64) {
throw new \TypeError('Not an instance of Int64');
}
/** @var ParagonIE_Sodium_Core32_Int64 $ctxAi */
$ctxAi = $ctxA[$i];
$str .= $ctxAi->toReverseString();
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
/** @var array<int, ParagonIE_Sodium_Core32_Int64> $ctxA */
$ctxA = $ctx[$i]->toArray();
/** @var ParagonIE_Sodium_Core32_Int64 $ctxA1 */
$ctxA1 = $ctxA[0];
/** @var ParagonIE_Sodium_Core32_Int64 $ctxA2 */
$ctxA2 = $ctxA[1];
$str .= $ctxA1->toReverseString();
$str .= $ctxA2->toReverseString();
}
# uint8_t buf[2 * 128];
$str .= self::SplFixedArrayToString($ctx[3]);
/** @var int $ctx4 */
$ctx4 = $ctx[4];
# size_t buflen;
$str .= \implode('', array(self::intToChr($ctx4 & 0xff), self::intToChr($ctx4 >> 8 & 0xff), self::intToChr($ctx4 >> 16 & 0xff), self::intToChr($ctx4 >> 24 & 0xff), "\x00\x00\x00\x00"));
# uint8_t last_node;
return $str . self::intToChr($ctx[5]) . \str_repeat("\x00", 23);
}
/**
* Creates an SplFixedArray containing other SplFixedArray elements, from
* a string (compatible with \Sodium\crypto_generichash_{init, update, final})
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
* @psalm-suppress MixedArrayAssignment
*/
public static function stringToContext($string)
{
$ctx = self::context();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$ctx[0][$i] = \ParagonIE_Sodium_Core32_Int64::fromReverseString(self::substr($string, ($i << 3) + 0, 8));
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctx[$i][1] = \ParagonIE_Sodium_Core32_Int64::fromReverseString(self::substr($string, 72 + ($i - 1 << 4), 8));
$ctx[$i][0] = \ParagonIE_Sodium_Core32_Int64::fromReverseString(self::substr($string, 64 + ($i - 1 << 4), 8));
}
# uint8_t buf[2 * 128];
$ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256));
# uint8_t buf[2 * 128];
$int = 0;
for ($i = 0; $i < 8; ++$i) {
$int |= self::chrToInt($string[352 + $i]) << ($i << 3);
}
$ctx[4] = $int;
return $ctx;
}
}
/**
* Class ParagonIE_Sodium_Core_BLAKE2b
*
* Based on the work of Devi Mandiri in devi/salt.
*/

View File

@@ -0,0 +1,342 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_ChaCha20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20
*/
class ParagonIE_Sodium_Core32_ChaCha20 extends \ParagonIE_Sodium_Core32_Util
{
/**
* The ChaCha20 quarter round function. Works on four 32-bit integers.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Int32 $a
* @param ParagonIE_Sodium_Core32_Int32 $b
* @param ParagonIE_Sodium_Core32_Int32 $c
* @param ParagonIE_Sodium_Core32_Int32 $d
* @return array<int, ParagonIE_Sodium_Core32_Int32>
* @throws SodiumException
* @throws TypeError
*/
protected static function quarterRound(\ParagonIE_Sodium_Core32_Int32 $a, \ParagonIE_Sodium_Core32_Int32 $b, \ParagonIE_Sodium_Core32_Int32 $c, \ParagonIE_Sodium_Core32_Int32 $d)
{
/** @var ParagonIE_Sodium_Core32_Int32 $a */
/** @var ParagonIE_Sodium_Core32_Int32 $b */
/** @var ParagonIE_Sodium_Core32_Int32 $c */
/** @var ParagonIE_Sodium_Core32_Int32 $d */
# a = PLUS(a,b); d = ROTATE(XOR(d,a),16);
$a = $a->addInt32($b);
$d = $d->xorInt32($a)->rotateLeft(16);
# c = PLUS(c,d); b = ROTATE(XOR(b,c),12);
$c = $c->addInt32($d);
$b = $b->xorInt32($c)->rotateLeft(12);
# a = PLUS(a,b); d = ROTATE(XOR(d,a), 8);
$a = $a->addInt32($b);
$d = $d->xorInt32($a)->rotateLeft(8);
# c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
$c = $c->addInt32($d);
$b = $b->xorInt32($c)->rotateLeft(7);
return array($a, $b, $c, $d);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx
* @param string $message
*
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function encryptBytes(\ParagonIE_Sodium_Core32_ChaCha20_Ctx $ctx, $message = '')
{
$bytes = self::strlen($message);
/** @var ParagonIE_Sodium_Core32_Int32 $x0 */
/** @var ParagonIE_Sodium_Core32_Int32 $x1 */
/** @var ParagonIE_Sodium_Core32_Int32 $x2 */
/** @var ParagonIE_Sodium_Core32_Int32 $x3 */
/** @var ParagonIE_Sodium_Core32_Int32 $x4 */
/** @var ParagonIE_Sodium_Core32_Int32 $x5 */
/** @var ParagonIE_Sodium_Core32_Int32 $x6 */
/** @var ParagonIE_Sodium_Core32_Int32 $x7 */
/** @var ParagonIE_Sodium_Core32_Int32 $x8 */
/** @var ParagonIE_Sodium_Core32_Int32 $x9 */
/** @var ParagonIE_Sodium_Core32_Int32 $x10 */
/** @var ParagonIE_Sodium_Core32_Int32 $x11 */
/** @var ParagonIE_Sodium_Core32_Int32 $x12 */
/** @var ParagonIE_Sodium_Core32_Int32 $x13 */
/** @var ParagonIE_Sodium_Core32_Int32 $x14 */
/** @var ParagonIE_Sodium_Core32_Int32 $x15 */
/*
j0 = ctx->input[0];
j1 = ctx->input[1];
j2 = ctx->input[2];
j3 = ctx->input[3];
j4 = ctx->input[4];
j5 = ctx->input[5];
j6 = ctx->input[6];
j7 = ctx->input[7];
j8 = ctx->input[8];
j9 = ctx->input[9];
j10 = ctx->input[10];
j11 = ctx->input[11];
j12 = ctx->input[12];
j13 = ctx->input[13];
j14 = ctx->input[14];
j15 = ctx->input[15];
*/
/** @var ParagonIE_Sodium_Core32_Int32 $j0 */
$j0 = $ctx[0];
/** @var ParagonIE_Sodium_Core32_Int32 $j1 */
$j1 = $ctx[1];
/** @var ParagonIE_Sodium_Core32_Int32 $j2 */
$j2 = $ctx[2];
/** @var ParagonIE_Sodium_Core32_Int32 $j3 */
$j3 = $ctx[3];
/** @var ParagonIE_Sodium_Core32_Int32 $j4 */
$j4 = $ctx[4];
/** @var ParagonIE_Sodium_Core32_Int32 $j5 */
$j5 = $ctx[5];
/** @var ParagonIE_Sodium_Core32_Int32 $j6 */
$j6 = $ctx[6];
/** @var ParagonIE_Sodium_Core32_Int32 $j7 */
$j7 = $ctx[7];
/** @var ParagonIE_Sodium_Core32_Int32 $j8 */
$j8 = $ctx[8];
/** @var ParagonIE_Sodium_Core32_Int32 $j9 */
$j9 = $ctx[9];
/** @var ParagonIE_Sodium_Core32_Int32 $j10 */
$j10 = $ctx[10];
/** @var ParagonIE_Sodium_Core32_Int32 $j11 */
$j11 = $ctx[11];
/** @var ParagonIE_Sodium_Core32_Int32 $j12 */
$j12 = $ctx[12];
/** @var ParagonIE_Sodium_Core32_Int32 $j13 */
$j13 = $ctx[13];
/** @var ParagonIE_Sodium_Core32_Int32 $j14 */
$j14 = $ctx[14];
/** @var ParagonIE_Sodium_Core32_Int32 $j15 */
$j15 = $ctx[15];
$c = '';
for (;;) {
if ($bytes < 64) {
$message .= \str_repeat("\x00", 64 - $bytes);
}
$x0 = clone $j0;
$x1 = clone $j1;
$x2 = clone $j2;
$x3 = clone $j3;
$x4 = clone $j4;
$x5 = clone $j5;
$x6 = clone $j6;
$x7 = clone $j7;
$x8 = clone $j8;
$x9 = clone $j9;
$x10 = clone $j10;
$x11 = clone $j11;
$x12 = clone $j12;
$x13 = clone $j13;
$x14 = clone $j14;
$x15 = clone $j15;
# for (i = 20; i > 0; i -= 2) {
for ($i = 20; $i > 0; $i -= 2) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
}
/*
x0 = PLUS(x0, j0);
x1 = PLUS(x1, j1);
x2 = PLUS(x2, j2);
x3 = PLUS(x3, j3);
x4 = PLUS(x4, j4);
x5 = PLUS(x5, j5);
x6 = PLUS(x6, j6);
x7 = PLUS(x7, j7);
x8 = PLUS(x8, j8);
x9 = PLUS(x9, j9);
x10 = PLUS(x10, j10);
x11 = PLUS(x11, j11);
x12 = PLUS(x12, j12);
x13 = PLUS(x13, j13);
x14 = PLUS(x14, j14);
x15 = PLUS(x15, j15);
*/
$x0 = $x0->addInt32($j0);
$x1 = $x1->addInt32($j1);
$x2 = $x2->addInt32($j2);
$x3 = $x3->addInt32($j3);
$x4 = $x4->addInt32($j4);
$x5 = $x5->addInt32($j5);
$x6 = $x6->addInt32($j6);
$x7 = $x7->addInt32($j7);
$x8 = $x8->addInt32($j8);
$x9 = $x9->addInt32($j9);
$x10 = $x10->addInt32($j10);
$x11 = $x11->addInt32($j11);
$x12 = $x12->addInt32($j12);
$x13 = $x13->addInt32($j13);
$x14 = $x14->addInt32($j14);
$x15 = $x15->addInt32($j15);
/*
x0 = XOR(x0, LOAD32_LE(m + 0));
x1 = XOR(x1, LOAD32_LE(m + 4));
x2 = XOR(x2, LOAD32_LE(m + 8));
x3 = XOR(x3, LOAD32_LE(m + 12));
x4 = XOR(x4, LOAD32_LE(m + 16));
x5 = XOR(x5, LOAD32_LE(m + 20));
x6 = XOR(x6, LOAD32_LE(m + 24));
x7 = XOR(x7, LOAD32_LE(m + 28));
x8 = XOR(x8, LOAD32_LE(m + 32));
x9 = XOR(x9, LOAD32_LE(m + 36));
x10 = XOR(x10, LOAD32_LE(m + 40));
x11 = XOR(x11, LOAD32_LE(m + 44));
x12 = XOR(x12, LOAD32_LE(m + 48));
x13 = XOR(x13, LOAD32_LE(m + 52));
x14 = XOR(x14, LOAD32_LE(m + 56));
x15 = XOR(x15, LOAD32_LE(m + 60));
*/
$x0 = $x0->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 0, 4)));
$x1 = $x1->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 4, 4)));
$x2 = $x2->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 8, 4)));
$x3 = $x3->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 12, 4)));
$x4 = $x4->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 16, 4)));
$x5 = $x5->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 20, 4)));
$x6 = $x6->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 24, 4)));
$x7 = $x7->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 28, 4)));
$x8 = $x8->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 32, 4)));
$x9 = $x9->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 36, 4)));
$x10 = $x10->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 40, 4)));
$x11 = $x11->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 44, 4)));
$x12 = $x12->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 48, 4)));
$x13 = $x13->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 52, 4)));
$x14 = $x14->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 56, 4)));
$x15 = $x15->xorInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 60, 4)));
/*
j12 = PLUSONE(j12);
if (!j12) {
j13 = PLUSONE(j13);
}
*/
/** @var ParagonIE_Sodium_Core32_Int32 $j12 */
$j12 = $j12->addInt(1);
if ($j12->limbs[0] === 0 && $j12->limbs[1] === 0) {
$j13 = $j13->addInt(1);
}
/*
STORE32_LE(c + 0, x0);
STORE32_LE(c + 4, x1);
STORE32_LE(c + 8, x2);
STORE32_LE(c + 12, x3);
STORE32_LE(c + 16, x4);
STORE32_LE(c + 20, x5);
STORE32_LE(c + 24, x6);
STORE32_LE(c + 28, x7);
STORE32_LE(c + 32, x8);
STORE32_LE(c + 36, x9);
STORE32_LE(c + 40, x10);
STORE32_LE(c + 44, x11);
STORE32_LE(c + 48, x12);
STORE32_LE(c + 52, x13);
STORE32_LE(c + 56, x14);
STORE32_LE(c + 60, x15);
*/
$block = $x0->toReverseString() . $x1->toReverseString() . $x2->toReverseString() . $x3->toReverseString() . $x4->toReverseString() . $x5->toReverseString() . $x6->toReverseString() . $x7->toReverseString() . $x8->toReverseString() . $x9->toReverseString() . $x10->toReverseString() . $x11->toReverseString() . $x12->toReverseString() . $x13->toReverseString() . $x14->toReverseString() . $x15->toReverseString();
/* Partial block */
if ($bytes < 64) {
$c .= self::substr($block, 0, $bytes);
break;
}
/* Full block */
$c .= $block;
$bytes -= 64;
if ($bytes <= 0) {
break;
}
$message = self::substr($message, 64);
}
/* end for(;;) loop */
$ctx[12] = $j12;
$ctx[13] = $j13;
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key = '')
{
return self::encryptBytes(new \ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce), \str_repeat("\x00", $len));
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStream($len, $nonce = '', $key = '')
{
return self::encryptBytes(new \ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce), \str_repeat("\x00", $len));
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(new \ParagonIE_Sodium_Core32_ChaCha20_IetfCtx($key, $nonce, $ic), $message);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(new \ParagonIE_Sodium_Core32_ChaCha20_Ctx($key, $nonce, $ic), $message);
}
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20
*/

View File

@@ -0,0 +1,124 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20_Ctx
*/
class ParagonIE_Sodium_Core32_ChaCha20_Ctx extends \ParagonIE_Sodium_Core32_Util implements \ArrayAccess
{
/**
* @var SplFixedArray internally, <int, ParagonIE_Sodium_Core32_Int32>
*/
protected $container;
/**
* ParagonIE_Sodium_Core_ChaCha20_Ctx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 8 0x00 bytes.
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct($key = '', $iv = '', $counter = '')
{
if (self::strlen($key) !== 32) {
throw new \InvalidArgumentException('ChaCha20 expects a 256-bit key.');
}
if (self::strlen($iv) !== 8) {
throw new \InvalidArgumentException('ChaCha20 expects a 64-bit nonce.');
}
$this->container = new \SplFixedArray(16);
/* "expand 32-byte k" as per ChaCha20 spec */
$this->container[0] = new \ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
$this->container[1] = new \ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
$this->container[2] = new \ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
$this->container[3] = new \ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
$this->container[4] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4));
$this->container[5] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 4, 4));
$this->container[6] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 8, 4));
$this->container[7] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4));
$this->container[8] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4));
$this->container[9] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4));
$this->container[10] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4));
$this->container[11] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4));
if (empty($counter)) {
$this->container[12] = new \ParagonIE_Sodium_Core32_Int32();
$this->container[13] = new \ParagonIE_Sodium_Core32_Int32();
} else {
$this->container[12] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 0, 4));
$this->container[13] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 4, 4));
}
$this->container[14] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 0, 4));
$this->container[15] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 4, 4));
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @param int|ParagonIE_Sodium_Core32_Int32 $value
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!\is_int($offset)) {
throw new \InvalidArgumentException('Expected an integer');
}
if ($value instanceof \ParagonIE_Sodium_Core32_Int32) {
/*
} elseif (is_int($value)) {
$value = ParagonIE_Sodium_Core32_Int32::fromInt($value);
*/
} else {
throw new \InvalidArgumentException('Expected an integer');
}
$this->container[$offset] = $value;
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return mixed|null
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20_Ctx
*/

View File

@@ -0,0 +1,42 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20_IetfCtx
*/
class ParagonIE_Sodium_Core32_ChaCha20_IetfCtx extends \ParagonIE_Sodium_Core32_ChaCha20_Ctx
{
/**
* ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 4 0x00 bytes.
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct($key = '', $iv = '', $counter = '')
{
if (self::strlen($iv) !== 12) {
throw new \InvalidArgumentException('ChaCha20 expects a 96-bit nonce in IETF mode.');
}
parent::__construct($key, self::substr($iv, 0, 8), $counter);
if (!empty($counter)) {
$this->container[12] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 0, 4));
}
$this->container[13] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 0, 4));
$this->container[14] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 4, 4));
$this->container[15] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 8, 4));
}
}
/**
* Class ParagonIE_Sodium_Core32_ChaCha20_IetfCtx
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,177 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Curve25519_Fe', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Fe
*
* This represents a Field Element
*/
class ParagonIE_Sodium_Core32_Curve25519_Fe implements \ArrayAccess
{
/**
* @var array<int, ParagonIE_Sodium_Core32_Int32>
*/
protected $container = array();
/**
* @var int
*/
protected $size = 10;
/**
* @internal You should not use this directly from another application
*
* @param array<int, ParagonIE_Sodium_Core32_Int32> $array
* @param bool $save_indexes
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromArray($array, $save_indexes = null)
{
$count = \count($array);
if ($save_indexes) {
$keys = \array_keys($array);
} else {
$keys = \range(0, $count - 1);
}
$array = \array_values($array);
$obj = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$array[$i]->overflow = 0;
$obj->offsetSet($keys[$i], $array[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
if (!$array[$i] instanceof \ParagonIE_Sodium_Core32_Int32) {
throw new \TypeError('Expected ParagonIE_Sodium_Core32_Int32');
}
$array[$i]->overflow = 0;
$obj->offsetSet($i, $array[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @param bool $save_indexes
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromIntArray($array, $save_indexes = null)
{
$count = \count($array);
if ($save_indexes) {
$keys = \array_keys($array);
} else {
$keys = \range(0, $count - 1);
}
$array = \array_values($array);
$set = array();
/** @var int $i */
/** @var int $v */
foreach ($array as $i => $v) {
$set[$i] = \ParagonIE_Sodium_Core32_Int32::fromInt($v);
}
$obj = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$set[$i]->overflow = 0;
$obj->offsetSet($keys[$i], $set[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$set[$i]->overflow = 0;
$obj->offsetSet($i, $set[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @param mixed $value
* @return void
* @throws SodiumException
* @throws TypeError
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
if (!$value instanceof \ParagonIE_Sodium_Core32_Int32) {
throw new \InvalidArgumentException('Expected an instance of ParagonIE_Sodium_Core32_Int32');
}
if (\is_null($offset)) {
$this->container[] = $value;
} else {
\ParagonIE_Sodium_Core32_Util::declareScalarType($offset, 'int', 1);
$this->container[(int) $offset] = $value;
}
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @return bool
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @return void
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
unset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param mixed $offset
* @return ParagonIE_Sodium_Core32_Int32
* @psalm-suppress MixedArrayOffset
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
if (!isset($this->container[$offset])) {
$this->container[(int) $offset] = new \ParagonIE_Sodium_Core32_Int32();
}
/** @var ParagonIE_Sodium_Core32_Int32 $get */
$get = $this->container[$offset];
return $get;
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
if (empty($this->container)) {
return array();
}
$c = array((int) $this->container[0]->toInt(), (int) $this->container[1]->toInt(), (int) $this->container[2]->toInt(), (int) $this->container[3]->toInt(), (int) $this->container[4]->toInt(), (int) $this->container[5]->toInt(), (int) $this->container[6]->toInt(), (int) $this->container[7]->toInt(), (int) $this->container[8]->toInt(), (int) $this->container[9]->toInt());
return array(\implode(', ', $c));
}
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Fe
*
* This represents a Field Element
*/

View File

@@ -0,0 +1,61 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_Cached', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $YplusX;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $YminusX;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $T2d;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_Cached constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $YplusX
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $YminusX
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $Z
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $T2d
*/
public function __construct(\ParagonIE_Sodium_Core32_Curve25519_Fe $YplusX = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $YminusX = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $Z = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $T2d = null)
{
if ($YplusX === null) {
$YplusX = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->YplusX = $YplusX;
if ($YminusX === null) {
$YminusX = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->YminusX = $YminusX;
if ($Z === null) {
$Z = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Z = $Z;
if ($T2d === null) {
$T2d = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->T2d = $T2d;
}
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_Cached
*/

View File

@@ -0,0 +1,64 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $t
*
* @throws SodiumException
* @throws TypeError
*/
public function __construct(\ParagonIE_Sodium_Core32_Curve25519_Fe $x = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $y = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $z = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $t = null)
{
if ($x === null) {
$x = \ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->X = $x;
if ($y === null) {
$y = \ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->Y = $y;
if ($z === null) {
$z = \ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->Z = $z;
if ($t === null) {
$t = \ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->T = $t;
}
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P1p1
*/

View File

@@ -0,0 +1,52 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P2', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P2
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_P2
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_P2 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z
*/
public function __construct(\ParagonIE_Sodium_Core32_Curve25519_Fe $x = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $y = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $z = null)
{
if ($x === null) {
$x = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Z = $z;
}
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P2
*/

View File

@@ -0,0 +1,61 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_P3', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P3
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_P3
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $X;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Y;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $Z;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $T;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_P3 constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $x
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $y
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $z
* @param ParagonIE_Sodium_Core32_Curve25519_Fe|null $t
*/
public function __construct(\ParagonIE_Sodium_Core32_Curve25519_Fe $x = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $y = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $z = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $t = null)
{
if ($x === null) {
$x = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->Z = $z;
if ($t === null) {
$t = new \ParagonIE_Sodium_Core32_Curve25519_Fe();
}
$this->T = $t;
}
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_P3
*/

View File

@@ -0,0 +1,54 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
*/
class ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
{
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $yplusx;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $yminusx;
/**
* @var ParagonIE_Sodium_Core32_Curve25519_Fe
*/
public $xy2d;
/**
* ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp constructor.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $yplusx
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $yminusx
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $xy2d
* @throws SodiumException
* @throws TypeError
*/
public function __construct(\ParagonIE_Sodium_Core32_Curve25519_Fe $yplusx = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $yminusx = null, \ParagonIE_Sodium_Core32_Curve25519_Fe $xy2d = null)
{
if ($yplusx === null) {
$yplusx = \ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->yplusx = $yplusx;
if ($yminusx === null) {
$yminusx = \ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->yminusx = $yminusx;
if ($xy2d === null) {
$xy2d = \ParagonIE_Sodium_Core32_Curve25519::fe_0();
}
$this->xy2d = $xy2d;
}
}
/**
* Class ParagonIE_Sodium_Core32_Curve25519_Ge_Precomp
*/

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
# Curve25519 Data Structures
These are PHP implementation of the [structs used in the ref10 curve25519 code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h).

View File

@@ -0,0 +1,353 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Ed25519', \false)) {
return;
}
if (!\class_exists('ParagonIE_Sodium_Core32_Curve25519')) {
require_once \dirname(__FILE__) . '/Curve25519.php';
}
/**
* Class ParagonIE_Sodium_Core32_Ed25519
*/
abstract class ParagonIE_Sodium_Core32_Ed25519 extends \ParagonIE_Sodium_Core32_Curve25519
{
const KEYPAIR_BYTES = 96;
const SEED_BYTES = 32;
/**
* @internal You should not use this directly from another application
*
* @return string (96 bytes)
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function keypair()
{
$seed = \random_bytes(self::SEED_BYTES);
$pk = '';
$sk = '';
self::seed_keypair($pk, $sk, $seed);
return $sk . $pk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $pk
* @param string $sk
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function seed_keypair(&$pk, &$sk, $seed)
{
if (self::strlen($seed) !== self::SEED_BYTES) {
throw new \RangeException('crypto_sign keypair seed must be 32 bytes long');
}
/** @var string $pk */
$pk = self::publickey_from_secretkey($seed);
$sk = $seed . $pk;
return $sk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function secretkey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new \RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 0, 64);
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws RangeException
* @throws TypeError
*/
public static function publickey($keypair)
{
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new \RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 64, 32);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function publickey_from_secretkey($sk)
{
/** @var string $sk */
$sk = \hash('sha512', self::substr($sk, 0, 32), \true);
$sk[0] = self::intToChr(self::chrToInt($sk[0]) & 248);
$sk[31] = self::intToChr(self::chrToInt($sk[31]) & 63 | 64);
return self::sk_to_pk($sk);
}
/**
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function pk_to_curve25519($pk)
{
if (self::small_order($pk)) {
throw new \SodiumException('Public key is on a small order');
}
$A = self::ge_frombytes_negate_vartime($pk);
$p1 = self::ge_mul_l($A);
if (!self::fe_isnonzero($p1->X)) {
throw new \SodiumException('Unexpected zero result');
}
# fe_1(one_minus_y);
# fe_sub(one_minus_y, one_minus_y, A.Y);
# fe_invert(one_minus_y, one_minus_y);
$one_minux_y = self::fe_invert(self::fe_sub(self::fe_1(), $A->Y));
# fe_1(x);
# fe_add(x, x, A.Y);
# fe_mul(x, x, one_minus_y);
$x = self::fe_mul(self::fe_add(self::fe_1(), $A->Y), $one_minux_y);
# fe_tobytes(curve25519_pk, x);
return self::fe_tobytes($x);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sk_to_pk($sk)
{
return self::ge_p3_tobytes(self::ge_scalarmult_base(self::substr($sk, 0, 32)));
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign($message, $sk)
{
/** @var string $signature */
$signature = self::sign_detached($message, $sk);
return $signature . $message;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message A signed message
* @param string $pk Public key
* @return string Message (without signature)
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open($message, $pk)
{
/** @var string $signature */
$signature = self::substr($message, 0, 64);
/** @var string $message */
$message = self::substr($message, 64);
if (self::verify_detached($signature, $message, $pk)) {
return $message;
}
throw new \SodiumException('Invalid signature');
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
* @psalm-suppress PossiblyInvalidArgument
*/
public static function sign_detached($message, $sk)
{
# crypto_hash_sha512(az, sk, 32);
$az = \hash('sha512', self::substr($sk, 0, 32), \true);
# az[0] &= 248;
# az[31] &= 63;
# az[31] |= 64;
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr(self::chrToInt($az[31]) & 63 | 64);
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, az + 32, 32);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, nonce);
$hs = \hash_init('sha512');
self::hash_update($hs, self::substr($az, 32, 32));
self::hash_update($hs, $message);
$nonceHash = \hash_final($hs, \true);
# memmove(sig + 32, sk + 32, 32);
$pk = self::substr($sk, 32, 32);
# sc_reduce(nonce);
# ge_scalarmult_base(&R, nonce);
# ge_p3_tobytes(sig, &R);
$nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32);
$sig = self::ge_p3_tobytes(self::ge_scalarmult_base($nonce));
# crypto_hash_sha512_init(&hs);
# crypto_hash_sha512_update(&hs, sig, 64);
# crypto_hash_sha512_update(&hs, m, mlen);
# crypto_hash_sha512_final(&hs, hram);
$hs = \hash_init('sha512');
self::hash_update($hs, self::substr($sig, 0, 32));
self::hash_update($hs, self::substr($pk, 0, 32));
self::hash_update($hs, $message);
$hramHash = \hash_final($hs, \true);
# sc_reduce(hram);
# sc_muladd(sig + 32, hram, az, nonce);
$hram = self::sc_reduce($hramHash);
$sigAfter = self::sc_muladd($hram, $az, $nonce);
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
\ParagonIE_Sodium_Compat::memzero($az);
} catch (\SodiumException $ex) {
$az = null;
}
return $sig;
}
/**
* @internal You should not use this directly from another application
*
* @param string $sig
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_detached($sig, $message, $pk)
{
if (self::strlen($sig) < 64) {
throw new \SodiumException('Signature is too short');
}
if (self::chrToInt($sig[63]) & 240 && self::check_S_lt_L(self::substr($sig, 32, 32))) {
throw new \SodiumException('S < L - Invalid signature');
}
if (self::small_order($sig)) {
throw new \SodiumException('Signature is on too small of an order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new \SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($pk[$i]);
}
if ($d === 0) {
throw new \SodiumException('All zero public key');
}
/** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */
$orig = \ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
\ParagonIE_Sodium_Compat::$fastMult = \true;
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */
$A = self::ge_frombytes_negate_vartime($pk);
/** @var string $hDigest */
$hDigest = \hash('sha512', self::substr($sig, 0, 32) . self::substr($pk, 0, 32) . $message, \true);
/** @var string $h */
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
/** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */
$R = self::ge_double_scalarmult_vartime($h, $A, self::substr($sig, 32));
/** @var string $rcheck */
$rcheck = self::ge_tobytes($R);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
\ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* @internal You should not use this directly from another application
*
* @param string $S
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function check_S_lt_L($S)
{
if (self::strlen($S) < 32) {
throw new \SodiumException('Signature must be 32 bytes');
}
static $L = array(0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10);
/** @var array<int, int> $L */
$c = 0;
$n = 1;
$i = 32;
do {
--$i;
$x = self::chrToInt($S[$i]);
$c |= $x - $L[$i] >> 8 & $n;
$n &= ($x ^ $L[$i]) - 1 >> 8;
} while ($i !== 0);
return $c === 0;
}
/**
* @param string $R
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function small_order($R)
{
static $blocklist = array(
/* 0 (order 4) */
array(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0),
/* 1 (order 1) */
array(0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0),
/* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x5, 0xd3, 0xc6, 0x33, 0x39, 0xb1, 0x38, 0x2, 0x88, 0x6d, 0x53, 0xfc, 0x5),
/* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0xb, 0x76, 0xd, 0x10, 0x67, 0xf, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x3, 0x7a),
/* p-1 (order 2) */
array(0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x5, 0xd3, 0xc6, 0x33, 0x39, 0xb1, 0x38, 0x2, 0x88, 0x6d, 0x53, 0xfc, 0x85),
/* p (order 4) */
array(0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0xb, 0x76, 0xd, 0x10, 0x67, 0xf, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x3, 0xfa),
/* p+1 (order 1) */
array(0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f),
/* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f),
/* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f),
/* 2p-1 (order 2) */
array(0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
/* 2p (order 4) */
array(0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
/* 2p+1 (order 1) */
array(0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
);
/** @var array<int, array<int, int>> $blocklist */
$countBlocklist = \count($blocklist);
for ($i = 0; $i < $countBlocklist; ++$i) {
$c = 0;
for ($j = 0; $j < 32; ++$j) {
$c |= self::chrToInt($R[$j]) ^ $blocklist[$i][$j];
}
if ($c === 0) {
return \true;
}
}
return \false;
}
}
/**
* Class ParagonIE_Sodium_Core32_Ed25519
*/

View File

@@ -0,0 +1,112 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_HChaCha20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HChaCha20
*/
class ParagonIE_Sodium_Core32_HChaCha20 extends \ParagonIE_Sodium_Core32_ChaCha20
{
/**
* @param string $in
* @param string $key
* @param string|null $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function hChaCha20($in = '', $key = '', $c = null)
{
$ctx = array();
if ($c === null) {
$ctx[0] = new \ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
$ctx[1] = new \ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
$ctx[2] = new \ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
$ctx[3] = new \ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
} else {
$ctx[0] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4));
$ctx[1] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4));
$ctx[2] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4));
$ctx[3] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4));
}
$ctx[4] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4));
$ctx[5] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 4, 4));
$ctx[6] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 8, 4));
$ctx[7] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4));
$ctx[8] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4));
$ctx[9] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4));
$ctx[10] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4));
$ctx[11] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4));
$ctx[12] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4));
$ctx[13] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4));
$ctx[14] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4));
$ctx[15] = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4));
return self::hChaCha20Bytes($ctx);
}
/**
* @param array $ctx
* @return string
* @throws SodiumException
* @throws TypeError
*/
protected static function hChaCha20Bytes(array $ctx)
{
/** @var ParagonIE_Sodium_Core32_Int32 $x0 */
$x0 = $ctx[0];
/** @var ParagonIE_Sodium_Core32_Int32 $x1 */
$x1 = $ctx[1];
/** @var ParagonIE_Sodium_Core32_Int32 $x2 */
$x2 = $ctx[2];
/** @var ParagonIE_Sodium_Core32_Int32 $x3 */
$x3 = $ctx[3];
/** @var ParagonIE_Sodium_Core32_Int32 $x4 */
$x4 = $ctx[4];
/** @var ParagonIE_Sodium_Core32_Int32 $x5 */
$x5 = $ctx[5];
/** @var ParagonIE_Sodium_Core32_Int32 $x6 */
$x6 = $ctx[6];
/** @var ParagonIE_Sodium_Core32_Int32 $x7 */
$x7 = $ctx[7];
/** @var ParagonIE_Sodium_Core32_Int32 $x8 */
$x8 = $ctx[8];
/** @var ParagonIE_Sodium_Core32_Int32 $x9 */
$x9 = $ctx[9];
/** @var ParagonIE_Sodium_Core32_Int32 $x10 */
$x10 = $ctx[10];
/** @var ParagonIE_Sodium_Core32_Int32 $x11 */
$x11 = $ctx[11];
/** @var ParagonIE_Sodium_Core32_Int32 $x12 */
$x12 = $ctx[12];
/** @var ParagonIE_Sodium_Core32_Int32 $x13 */
$x13 = $ctx[13];
/** @var ParagonIE_Sodium_Core32_Int32 $x14 */
$x14 = $ctx[14];
/** @var ParagonIE_Sodium_Core32_Int32 $x15 */
$x15 = $ctx[15];
for ($i = 0; $i < 10; ++$i) {
# QUARTERROUND( x0, x4, x8, x12)
list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12);
# QUARTERROUND( x1, x5, x9, x13)
list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13);
# QUARTERROUND( x2, x6, x10, x14)
list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14);
# QUARTERROUND( x3, x7, x11, x15)
list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15);
# QUARTERROUND( x0, x5, x10, x15)
list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15);
# QUARTERROUND( x1, x6, x11, x12)
list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12);
# QUARTERROUND( x2, x7, x8, x13)
list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13);
# QUARTERROUND( x3, x4, x9, x14)
list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14);
}
return $x0->toReverseString() . $x1->toReverseString() . $x2->toReverseString() . $x3->toReverseString() . $x12->toReverseString() . $x13->toReverseString() . $x14->toReverseString() . $x15->toReverseString();
}
}
/**
* Class ParagonIE_Sodium_Core_HChaCha20
*/

View File

@@ -0,0 +1,129 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_HSalsa20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_HSalsa20
*/
abstract class ParagonIE_Sodium_Core32_HSalsa20 extends \ParagonIE_Sodium_Core32_Salsa20
{
/**
* Calculate an hsalsa20 hash of a single block
*
* HSalsa20 doesn't have a counter and will never be used for more than
* one block (used to derive a subkey for xsalsa20).
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function hsalsa20($in, $k, $c = null)
{
/**
* @var ParagonIE_Sodium_Core32_Int32 $x0
* @var ParagonIE_Sodium_Core32_Int32 $x1
* @var ParagonIE_Sodium_Core32_Int32 $x2
* @var ParagonIE_Sodium_Core32_Int32 $x3
* @var ParagonIE_Sodium_Core32_Int32 $x4
* @var ParagonIE_Sodium_Core32_Int32 $x5
* @var ParagonIE_Sodium_Core32_Int32 $x6
* @var ParagonIE_Sodium_Core32_Int32 $x7
* @var ParagonIE_Sodium_Core32_Int32 $x8
* @var ParagonIE_Sodium_Core32_Int32 $x9
* @var ParagonIE_Sodium_Core32_Int32 $x10
* @var ParagonIE_Sodium_Core32_Int32 $x11
* @var ParagonIE_Sodium_Core32_Int32 $x12
* @var ParagonIE_Sodium_Core32_Int32 $x13
* @var ParagonIE_Sodium_Core32_Int32 $x14
* @var ParagonIE_Sodium_Core32_Int32 $x15
* @var ParagonIE_Sodium_Core32_Int32 $j0
* @var ParagonIE_Sodium_Core32_Int32 $j1
* @var ParagonIE_Sodium_Core32_Int32 $j2
* @var ParagonIE_Sodium_Core32_Int32 $j3
* @var ParagonIE_Sodium_Core32_Int32 $j4
* @var ParagonIE_Sodium_Core32_Int32 $j5
* @var ParagonIE_Sodium_Core32_Int32 $j6
* @var ParagonIE_Sodium_Core32_Int32 $j7
* @var ParagonIE_Sodium_Core32_Int32 $j8
* @var ParagonIE_Sodium_Core32_Int32 $j9
* @var ParagonIE_Sodium_Core32_Int32 $j10
* @var ParagonIE_Sodium_Core32_Int32 $j11
* @var ParagonIE_Sodium_Core32_Int32 $j12
* @var ParagonIE_Sodium_Core32_Int32 $j13
* @var ParagonIE_Sodium_Core32_Int32 $j14
* @var ParagonIE_Sodium_Core32_Int32 $j15
*/
if (self::strlen($k) < 32) {
throw new \RangeException('Key must be 32 bytes long');
}
if ($c === null) {
$x0 = new \ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
$x5 = new \ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
$x10 = new \ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
$x15 = new \ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
} else {
$x0 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4));
$x5 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4));
$x10 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4));
$x15 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4));
}
$x1 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 0, 4));
$x2 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 4, 4));
$x3 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 8, 4));
$x4 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 12, 4));
$x6 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4));
$x7 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4));
$x8 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4));
$x9 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4));
$x11 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 16, 4));
$x12 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 20, 4));
$x13 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 24, 4));
$x14 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 28, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 = $x4->xorInt32($x0->addInt32($x12)->rotateLeft(7));
$x8 = $x8->xorInt32($x4->addInt32($x0)->rotateLeft(9));
$x12 = $x12->xorInt32($x8->addInt32($x4)->rotateLeft(13));
$x0 = $x0->xorInt32($x12->addInt32($x8)->rotateLeft(18));
$x9 = $x9->xorInt32($x5->addInt32($x1)->rotateLeft(7));
$x13 = $x13->xorInt32($x9->addInt32($x5)->rotateLeft(9));
$x1 = $x1->xorInt32($x13->addInt32($x9)->rotateLeft(13));
$x5 = $x5->xorInt32($x1->addInt32($x13)->rotateLeft(18));
$x14 = $x14->xorInt32($x10->addInt32($x6)->rotateLeft(7));
$x2 = $x2->xorInt32($x14->addInt32($x10)->rotateLeft(9));
$x6 = $x6->xorInt32($x2->addInt32($x14)->rotateLeft(13));
$x10 = $x10->xorInt32($x6->addInt32($x2)->rotateLeft(18));
$x3 = $x3->xorInt32($x15->addInt32($x11)->rotateLeft(7));
$x7 = $x7->xorInt32($x3->addInt32($x15)->rotateLeft(9));
$x11 = $x11->xorInt32($x7->addInt32($x3)->rotateLeft(13));
$x15 = $x15->xorInt32($x11->addInt32($x7)->rotateLeft(18));
$x1 = $x1->xorInt32($x0->addInt32($x3)->rotateLeft(7));
$x2 = $x2->xorInt32($x1->addInt32($x0)->rotateLeft(9));
$x3 = $x3->xorInt32($x2->addInt32($x1)->rotateLeft(13));
$x0 = $x0->xorInt32($x3->addInt32($x2)->rotateLeft(18));
$x6 = $x6->xorInt32($x5->addInt32($x4)->rotateLeft(7));
$x7 = $x7->xorInt32($x6->addInt32($x5)->rotateLeft(9));
$x4 = $x4->xorInt32($x7->addInt32($x6)->rotateLeft(13));
$x5 = $x5->xorInt32($x4->addInt32($x7)->rotateLeft(18));
$x11 = $x11->xorInt32($x10->addInt32($x9)->rotateLeft(7));
$x8 = $x8->xorInt32($x11->addInt32($x10)->rotateLeft(9));
$x9 = $x9->xorInt32($x8->addInt32($x11)->rotateLeft(13));
$x10 = $x10->xorInt32($x9->addInt32($x8)->rotateLeft(18));
$x12 = $x12->xorInt32($x15->addInt32($x14)->rotateLeft(7));
$x13 = $x13->xorInt32($x12->addInt32($x15)->rotateLeft(9));
$x14 = $x14->xorInt32($x13->addInt32($x12)->rotateLeft(13));
$x15 = $x15->xorInt32($x14->addInt32($x13)->rotateLeft(18));
}
return $x0->toReverseString() . $x5->toReverseString() . $x10->toReverseString() . $x15->toReverseString() . $x6->toReverseString() . $x7->toReverseString() . $x8->toReverseString() . $x9->toReverseString();
}
}
/**
* Class ParagonIE_Sodium_Core32_HSalsa20
*/

View File

@@ -0,0 +1,731 @@
<?php
/**
* Class ParagonIE_Sodium_Core32_Int32
*
* Encapsulates a 32-bit integer.
*
* These are immutable. It always returns a new instance.
*/
class ParagonIE_Sodium_Core32_Int32
{
/**
* @var array<int, int> - two 16-bit integers
*
* 0 is the higher 16 bits
* 1 is the lower 16 bits
*/
public $limbs = array(0, 0);
/**
* @var int
*/
public $overflow = 0;
/**
* @var bool
*/
public $unsignedInt = \false;
/**
* ParagonIE_Sodium_Core32_Int32 constructor.
* @param array $array
* @param bool $unsignedInt
*/
public function __construct($array = array(0, 0), $unsignedInt = \false)
{
$this->limbs = array((int) $array[0], (int) $array[1]);
$this->overflow = 0;
$this->unsignedInt = $unsignedInt;
}
/**
* Adds two int32 objects
*
* @param ParagonIE_Sodium_Core32_Int32 $addend
* @return ParagonIE_Sodium_Core32_Int32
*/
public function addInt32(\ParagonIE_Sodium_Core32_Int32 $addend)
{
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$j0 = $addend->limbs[0];
$j1 = $addend->limbs[1];
$r1 = $i1 + ($j1 & 0xffff);
$carry = $r1 >> 16;
$r0 = $i0 + ($j0 & 0xffff) + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$return = new \ParagonIE_Sodium_Core32_Int32(array($r0, $r1));
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* Adds a normal integer to an int32 object
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function addInt($int)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
/** @var int $int */
$int = (int) $int;
$int = (int) $int;
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$r1 = $i1 + ($int & 0xffff);
$carry = $r1 >> 16;
$r0 = $i0 + ($int >> 16 & 0xffff) + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$return = new \ParagonIE_Sodium_Core32_Int32(array($r0, $r1));
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param int $b
* @return int
*/
public function compareInt($b = 0)
{
$gt = 0;
$eq = 1;
$i = 2;
$j = 0;
while ($i > 0) {
--$i;
/** @var int $x1 */
$x1 = $this->limbs[$i];
/** @var int $x2 */
$x2 = $b >> ($j << 4) & 0xffff;
/** @var int $gt */
$gt |= $x2 - $x1 >> 8 & $eq;
/** @var int $eq */
$eq &= ($x2 ^ $x1) - 1 >> 8;
}
return $gt + $gt - $eq + 1;
}
/**
* @param int $m
* @return ParagonIE_Sodium_Core32_Int32
*/
public function mask($m = 0)
{
/** @var int $hi */
$hi = (int) $m >> 16;
$hi &= 0xffff;
/** @var int $lo */
$lo = (int) $m & 0xffff;
return new \ParagonIE_Sodium_Core32_Int32(array((int) ($this->limbs[0] & $hi), (int) ($this->limbs[1] & $lo)), $this->unsignedInt);
}
/**
* @param array<int, int> $a
* @param array<int, int> $b
* @param int $baseLog2
* @return array<int, int>
*/
public function multiplyLong(array $a, array $b, $baseLog2 = 16)
{
$a_l = \count($a);
$b_l = \count($b);
/** @var array<int, int> $r */
$r = \array_fill(0, $a_l + $b_l + 1, 0);
$base = 1 << $baseLog2;
for ($i = 0; $i < $a_l; ++$i) {
$a_i = $a[$i];
for ($j = 0; $j < $a_l; ++$j) {
$b_j = $b[$j];
$product = $a_i * $b_j + $r[$i + $j];
$carry = (int) $product >> $baseLog2 & 0xffff;
$r[$i + $j] = (int) $product - (int) ($carry * $base) & 0xffff;
$r[$i + $j + 1] += $carry;
}
}
return \array_slice($r, 0, 5);
}
/**
* @param int $int
* @return ParagonIE_Sodium_Core32_Int32
*/
public function mulIntFast($int)
{
// Handle negative numbers
$aNeg = $this->limbs[0] >> 15 & 1;
$bNeg = $int >> 31 & 1;
$a = \array_reverse($this->limbs);
$b = array($int & 0xffff, $int >> 16 & 0xffff);
if ($aNeg) {
for ($i = 0; $i < 2; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 2; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
// Multiply
$res = $this->multiplyLong($a, $b);
// Re-apply negation to results
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 2; ++$i) {
$res[$i] = (0xffff ^ $res[$i]) & 0xffff;
}
// Handle integer overflow
$c = 1;
for ($i = 0; $i < 2; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
// Return our values
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->limbs = array($res[1] & 0xffff, $res[0] & 0xffff);
if (\count($res) > 2) {
$return->overflow = $res[2] & 0xffff;
}
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int32 $right
* @return ParagonIE_Sodium_Core32_Int32
*/
public function mulInt32Fast(\ParagonIE_Sodium_Core32_Int32 $right)
{
$aNeg = $this->limbs[0] >> 15 & 1;
$bNeg = $right->limbs[0] >> 15 & 1;
$a = \array_reverse($this->limbs);
$b = \array_reverse($right->limbs);
if ($aNeg) {
for ($i = 0; $i < 2; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 2; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
$res = $this->multiplyLong($a, $b);
if ($aNeg !== $bNeg) {
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 2; ++$i) {
$res[$i] = ($res[$i] ^ 0xffff) & 0xffff;
}
$c = 1;
for ($i = 0; $i < 2; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
}
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->limbs = array($res[1] & 0xffff, $res[0] & 0xffff);
if (\count($res) > 2) {
$return->overflow = $res[2];
}
return $return;
}
/**
* @param int $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function mulInt($int = 0, $size = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
\ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
if (\ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulIntFast((int) $int);
}
/** @var int $int */
$int = (int) $int;
/** @var int $size */
$size = (int) $size;
if (!$size) {
$size = 31;
}
/** @var int $size */
$a = clone $this;
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
/** @var int $size */
/** @var int $i */
for ($i = $size; $i >= 0; --$i) {
$m = (int) -($int & 1);
$x0 = $a0 & $m;
$x1 = $a1 & $m;
$ret1 += $x1;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$a1 = $a1 << 1;
$x1 = $a1 >> 16;
$a0 = $a0 << 1 | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$int >>= 1;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int32 $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function mulInt32(\ParagonIE_Sodium_Core32_Int32 $int, $size = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
if (\ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulInt32Fast($int);
}
if (!$size) {
$size = 31;
}
/** @var int $size */
$a = clone $this;
$b = clone $int;
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
$b0 = $b->limbs[0];
$b1 = $b->limbs[1];
/** @var int $size */
/** @var int $i */
for ($i = $size; $i >= 0; --$i) {
$m = (int) -($b1 & 1);
$x0 = $a0 & $m;
$x1 = $a1 & $m;
$ret1 += $x1;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$a1 = $a1 << 1;
$x1 = $a1 >> 16;
$a0 = $a0 << 1 | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$x0 = ($b0 & 1) << 16;
$b0 = $b0 >> 1;
$b1 = ($b1 | $x0) >> 1;
$b0 &= 0xffff;
$b1 &= 0xffff;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
return $return;
}
/**
* OR this 32-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int32 $b
* @return ParagonIE_Sodium_Core32_Int32
*/
public function orInt32(\ParagonIE_Sodium_Core32_Int32 $b)
{
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array((int) ($this->limbs[0] | $b->limbs[0]), (int) ($this->limbs[1] | $b->limbs[1]));
/** @var int overflow */
$return->overflow = $this->overflow | $b->overflow;
return $return;
}
/**
* @param int $b
* @return bool
*/
public function isGreaterThan($b = 0)
{
return $this->compareInt($b) > 0;
}
/**
* @param int $b
* @return bool
*/
public function isLessThanInt($b = 0)
{
return $this->compareInt($b) < 0;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateLeft($c = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 31;
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var int $c */
/** @var int $idx_shift */
$idx_shift = $c >> 4 & 1;
/** @var int $sub_shift */
$sub_shift = $c & 15;
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
for ($i = 1; $i >= 0; --$i) {
/** @var int $j */
$j = $i + $idx_shift & 1;
/** @var int $k */
$k = $i + $idx_shift + 1 & 1;
$limbs[$i] = (int) (((int) $myLimbs[$j] << $sub_shift | (int) $myLimbs[$k] >> 16 - $sub_shift) & 0xffff);
}
}
return $return;
}
/**
* Rotate to the right
*
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateRight($c = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 31;
/** @var int $c */
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var int $c */
/** @var int $idx_shift */
$idx_shift = $c >> 4 & 1;
/** @var int $sub_shift */
$sub_shift = $c & 15;
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
for ($i = 1; $i >= 0; --$i) {
/** @var int $j */
$j = $i - $idx_shift & 1;
/** @var int $k */
$k = $i - $idx_shift - 1 & 1;
$limbs[$i] = (int) (((int) $myLimbs[$j] >> (int) $sub_shift | (int) $myLimbs[$k] << 16 - (int) $sub_shift) & 0xffff);
}
}
return $return;
}
/**
* @param bool $bool
* @return self
*/
public function setUnsignedInt($bool = \false)
{
$this->unsignedInt = !empty($bool);
return $this;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function shiftLeft($c = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
/** @var int $c */
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
/** @var int $c */
return $this->shiftRight(-$c);
} else {
/** @var int $c */
/** @var int $tmp */
$tmp = $this->limbs[1] << $c;
$return->limbs[1] = (int) ($tmp & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
/** @var int $tmp */
$tmp = $this->limbs[0] << $c | $carry & 0xffff;
$return->limbs[0] = (int) ($tmp & 0xffff);
}
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedOperand
*/
public function shiftRight($c = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
/** @var int $c */
if ($c >= 16) {
$return->limbs = array((int) ($this->overflow & 0xffff), (int) $this->limbs[0]);
$return->overflow = $this->overflow >> 16;
return $return->shiftRight($c & 15);
}
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
/** @var int $c */
return $this->shiftLeft(-$c);
} else {
if (!\is_int($c)) {
throw new \TypeError();
}
/** @var int $c */
// $return->limbs[0] = (int) (($this->limbs[0] >> $c) & 0xffff);
$carryLeft = (int) ($this->overflow & (1 << $c + 1) - 1);
$return->limbs[0] = (int) (($this->limbs[0] >> $c | $carryLeft << 16 - $c) & 0xffff);
$carryRight = (int) ($this->limbs[0] & (1 << $c + 1) - 1);
$return->limbs[1] = (int) (($this->limbs[1] >> $c | $carryRight << 16 - $c) & 0xffff);
$return->overflow >>= $c;
}
return $return;
}
/**
* Subtract a normal integer from an int32 object.
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int32
* @throws SodiumException
* @throws TypeError
*/
public function subInt($int)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
/** @var int $int */
$int = (int) $int;
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
/** @var int $tmp */
$tmp = $this->limbs[1] - ($int & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[1] = (int) ($tmp & 0xffff);
/** @var int $tmp */
$tmp = $this->limbs[0] - ($int >> 16 & 0xffff) + $carry;
$return->limbs[0] = (int) ($tmp & 0xffff);
return $return;
}
/**
* Subtract two int32 objects from each other
*
* @param ParagonIE_Sodium_Core32_Int32 $b
* @return ParagonIE_Sodium_Core32_Int32
*/
public function subInt32(\ParagonIE_Sodium_Core32_Int32 $b)
{
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
/** @var int $tmp */
$tmp = $this->limbs[1] - ($b->limbs[1] & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[1] = (int) ($tmp & 0xffff);
/** @var int $tmp */
$tmp = $this->limbs[0] - ($b->limbs[0] & 0xffff) + $carry;
$return->limbs[0] = (int) ($tmp & 0xffff);
return $return;
}
/**
* XOR this 32-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int32 $b
* @return ParagonIE_Sodium_Core32_Int32
*/
public function xorInt32(\ParagonIE_Sodium_Core32_Int32 $b)
{
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array((int) ($this->limbs[0] ^ $b->limbs[0]), (int) ($this->limbs[1] ^ $b->limbs[1]));
return $return;
}
/**
* @param int $signed
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromInt($signed)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($signed, 'int', 1);
/** @var int $signed */
$signed = (int) $signed;
return new \ParagonIE_Sodium_Core32_Int32(array((int) ($signed >> 16 & 0xffff), (int) ($signed & 0xffff)));
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromString($string)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
$string = (string) $string;
if (\ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) {
throw new \RangeException('String must be 4 bytes; ' . \ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.');
}
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) << 8);
$return->limbs[0] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff;
$return->limbs[1] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) << 8);
$return->limbs[1] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff;
return $return;
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromReverseString($string)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
$string = (string) $string;
if (\ParagonIE_Sodium_Core32_Util::strlen($string) !== 4) {
throw new \RangeException('String must be 4 bytes; ' . \ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.');
}
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) << 8);
$return->limbs[0] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff;
$return->limbs[1] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) << 8);
$return->limbs[1] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff;
return $return;
}
/**
* @return array<int, int>
*/
public function toArray()
{
return array((int) ($this->limbs[0] << 16 | $this->limbs[1]));
}
/**
* @return string
* @throws TypeError
*/
public function toString()
{
return \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff);
}
/**
* @return int
*/
public function toInt()
{
return (int) (($this->limbs[0] & 0xffff) << 16 | $this->limbs[1] & 0xffff);
}
/**
* @return ParagonIE_Sodium_Core32_Int32
*/
public function toInt32()
{
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) ($this->limbs[0] & 0xffff);
$return->limbs[1] = (int) ($this->limbs[1] & 0xffff);
$return->unsignedInt = $this->unsignedInt;
$return->overflow = (int) ($this->overflow & 0x7fffffff);
return $return;
}
/**
* @return ParagonIE_Sodium_Core32_Int64
*/
public function toInt64()
{
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
if ($this->unsignedInt) {
$return->limbs[0] += $this->overflow >> 16 & 0xffff;
$return->limbs[1] += $this->overflow & 0xffff;
} else {
$neg = -($this->limbs[0] >> 15 & 1);
$return->limbs[0] = (int) ($neg & 0xffff);
$return->limbs[1] = (int) ($neg & 0xffff);
}
$return->limbs[2] = (int) ($this->limbs[0] & 0xffff);
$return->limbs[3] = (int) ($this->limbs[1] & 0xffff);
return $return;
}
/**
* @return string
* @throws TypeError
*/
public function toReverseString()
{
return \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] >> 8 & 0xff);
}
/**
* @return string
*/
public function __toString()
{
try {
return $this->toString();
} catch (\TypeError $ex) {
// PHP engine can't handle exceptions from __toString()
return '';
}
}
}
/**
* Class ParagonIE_Sodium_Core32_Int32
*
* Encapsulates a 32-bit integer.
*
* These are immutable. It always returns a new instance.
*/

View File

@@ -0,0 +1,859 @@
<?php
/**
* Class ParagonIE_Sodium_Core32_Int64
*
* Encapsulates a 64-bit integer.
*
* These are immutable. It always returns a new instance.
*/
class ParagonIE_Sodium_Core32_Int64
{
/**
* @var array<int, int> - four 16-bit integers
*/
public $limbs = array(0, 0, 0, 0);
/**
* @var int
*/
public $overflow = 0;
/**
* @var bool
*/
public $unsignedInt = \false;
/**
* ParagonIE_Sodium_Core32_Int64 constructor.
* @param array $array
* @param bool $unsignedInt
*/
public function __construct($array = array(0, 0, 0, 0), $unsignedInt = \false)
{
$this->limbs = array((int) $array[0], (int) $array[1], (int) $array[2], (int) $array[3]);
$this->overflow = 0;
$this->unsignedInt = $unsignedInt;
}
/**
* Adds two int64 objects
*
* @param ParagonIE_Sodium_Core32_Int64 $addend
* @return ParagonIE_Sodium_Core32_Int64
*/
public function addInt64(\ParagonIE_Sodium_Core32_Int64 $addend)
{
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$i2 = $this->limbs[2];
$i3 = $this->limbs[3];
$j0 = $addend->limbs[0];
$j1 = $addend->limbs[1];
$j2 = $addend->limbs[2];
$j3 = $addend->limbs[3];
$r3 = $i3 + ($j3 & 0xffff);
$carry = $r3 >> 16;
$r2 = $i2 + ($j2 & 0xffff) + $carry;
$carry = $r2 >> 16;
$r1 = $i1 + ($j1 & 0xffff) + $carry;
$carry = $r1 >> 16;
$r0 = $i0 + ($j0 & 0xffff) + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$r2 &= 0xffff;
$r3 &= 0xffff;
$return = new \ParagonIE_Sodium_Core32_Int64(array($r0, $r1, $r2, $r3));
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* Adds a normal integer to an int64 object
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function addInt($int)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
/** @var int $int */
$int = (int) $int;
$i0 = $this->limbs[0];
$i1 = $this->limbs[1];
$i2 = $this->limbs[2];
$i3 = $this->limbs[3];
$r3 = $i3 + ($int & 0xffff);
$carry = $r3 >> 16;
$r2 = $i2 + ($int >> 16 & 0xffff) + $carry;
$carry = $r2 >> 16;
$r1 = $i1 + $carry;
$carry = $r1 >> 16;
$r0 = $i0 + $carry;
$carry = $r0 >> 16;
$r0 &= 0xffff;
$r1 &= 0xffff;
$r2 &= 0xffff;
$r3 &= 0xffff;
$return = new \ParagonIE_Sodium_Core32_Int64(array($r0, $r1, $r2, $r3));
$return->overflow = $carry;
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param int $b
* @return int
*/
public function compareInt($b = 0)
{
$gt = 0;
$eq = 1;
$i = 4;
$j = 0;
while ($i > 0) {
--$i;
/** @var int $x1 */
$x1 = $this->limbs[$i];
/** @var int $x2 */
$x2 = $b >> ($j << 4) & 0xffff;
/** int */
$gt |= $x2 - $x1 >> 8 & $eq;
/** int */
$eq &= ($x2 ^ $x1) - 1 >> 8;
}
return $gt + $gt - $eq + 1;
}
/**
* @param int $b
* @return bool
*/
public function isGreaterThan($b = 0)
{
return $this->compareInt($b) > 0;
}
/**
* @param int $b
* @return bool
*/
public function isLessThanInt($b = 0)
{
return $this->compareInt($b) < 0;
}
/**
* @param int $hi
* @param int $lo
* @return ParagonIE_Sodium_Core32_Int64
*/
public function mask64($hi = 0, $lo = 0)
{
/** @var int $a */
$a = $hi >> 16 & 0xffff;
/** @var int $b */
$b = $hi & 0xffff;
/** @var int $c */
$c = $lo >> 16 & 0xffff;
/** @var int $d */
$d = $lo & 0xffff;
return new \ParagonIE_Sodium_Core32_Int64(array($this->limbs[0] & $a, $this->limbs[1] & $b, $this->limbs[2] & $c, $this->limbs[3] & $d), $this->unsignedInt);
}
/**
* @param int $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
*/
public function mulInt($int = 0, $size = 0)
{
if (\ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulIntFast($int);
}
\ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
\ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
/** @var int $int */
$int = (int) $int;
/** @var int $size */
$size = (int) $size;
if (!$size) {
$size = 63;
}
$a = clone $this;
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$ret2 = 0;
$ret3 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
$a2 = $a->limbs[2];
$a3 = $a->limbs[3];
/** @var int $size */
/** @var int $i */
for ($i = $size; $i >= 0; --$i) {
$mask = -($int & 1);
$x0 = $a0 & $mask;
$x1 = $a1 & $mask;
$x2 = $a2 & $mask;
$x3 = $a3 & $mask;
$ret3 += $x3;
$c = $ret3 >> 16;
$ret2 += $x2 + $c;
$c = $ret2 >> 16;
$ret1 += $x1 + $c;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$ret2 &= 0xffff;
$ret3 &= 0xffff;
$a3 = $a3 << 1;
$x3 = $a3 >> 16;
$a2 = $a2 << 1 | $x3;
$x2 = $a2 >> 16;
$a1 = $a1 << 1 | $x2;
$x1 = $a1 >> 16;
$a0 = $a0 << 1 | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$a2 &= 0xffff;
$a3 &= 0xffff;
$int >>= 1;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
$return->limbs[2] = $ret2;
$return->limbs[3] = $ret3;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int64 $A
* @param ParagonIE_Sodium_Core32_Int64 $B
* @return array<int, ParagonIE_Sodium_Core32_Int64>
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedInferredReturnType
*/
public static function ctSelect(\ParagonIE_Sodium_Core32_Int64 $A, \ParagonIE_Sodium_Core32_Int64 $B)
{
$a = clone $A;
$b = clone $B;
/** @var int $aNeg */
$aNeg = $a->limbs[0] >> 15 & 1;
/** @var int $bNeg */
$bNeg = $b->limbs[0] >> 15 & 1;
/** @var int $m */
$m = -($aNeg & $bNeg) | 1;
/** @var int $swap */
$swap = $bNeg & ~$aNeg;
/** @var int $d */
$d = -$swap;
/*
if ($bNeg && !$aNeg) {
$a = clone $int;
$b = clone $this;
} elseif($bNeg && $aNeg) {
$a = $this->mulInt(-1);
$b = $int->mulInt(-1);
}
*/
$x = $a->xorInt64($b)->mask64($d, $d);
return array($a->xorInt64($x)->mulInt($m), $b->xorInt64($x)->mulInt($m));
}
/**
* @param array<int, int> $a
* @param array<int, int> $b
* @param int $baseLog2
* @return array<int, int>
*/
public function multiplyLong(array $a, array $b, $baseLog2 = 16)
{
$a_l = \count($a);
$b_l = \count($b);
/** @var array<int, int> $r */
$r = \array_fill(0, $a_l + $b_l + 1, 0);
$base = 1 << $baseLog2;
for ($i = 0; $i < $a_l; ++$i) {
$a_i = $a[$i];
for ($j = 0; $j < $a_l; ++$j) {
$b_j = $b[$j];
$product = $a_i * $b_j + $r[$i + $j];
$carry = (int) $product >> $baseLog2 & 0xffff;
$r[$i + $j] = (int) $product - (int) ($carry * $base) & 0xffff;
$r[$i + $j + 1] += $carry;
}
}
return \array_slice($r, 0, 5);
}
/**
* @param int $int
* @return ParagonIE_Sodium_Core32_Int64
*/
public function mulIntFast($int)
{
// Handle negative numbers
$aNeg = $this->limbs[0] >> 15 & 1;
$bNeg = $int >> 31 & 1;
$a = \array_reverse($this->limbs);
$b = array($int & 0xffff, $int >> 16 & 0xffff, -$bNeg & 0xffff, -$bNeg & 0xffff);
if ($aNeg) {
for ($i = 0; $i < 4; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 4; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
// Multiply
$res = $this->multiplyLong($a, $b);
// Re-apply negation to results
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 4; ++$i) {
$res[$i] = (0xffff ^ $res[$i]) & 0xffff;
}
// Handle integer overflow
$c = 1;
for ($i = 0; $i < 4; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
// Return our values
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->limbs = array($res[3] & 0xffff, $res[2] & 0xffff, $res[1] & 0xffff, $res[0] & 0xffff);
if (\count($res) > 4) {
$return->overflow = $res[4] & 0xffff;
}
$return->unsignedInt = $this->unsignedInt;
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int64 $right
* @return ParagonIE_Sodium_Core32_Int64
*/
public function mulInt64Fast(\ParagonIE_Sodium_Core32_Int64 $right)
{
$aNeg = $this->limbs[0] >> 15 & 1;
$bNeg = $right->limbs[0] >> 15 & 1;
$a = \array_reverse($this->limbs);
$b = \array_reverse($right->limbs);
if ($aNeg) {
for ($i = 0; $i < 4; ++$i) {
$a[$i] = ($a[$i] ^ 0xffff) & 0xffff;
}
++$a[0];
}
if ($bNeg) {
for ($i = 0; $i < 4; ++$i) {
$b[$i] = ($b[$i] ^ 0xffff) & 0xffff;
}
++$b[0];
}
$res = $this->multiplyLong($a, $b);
if ($aNeg !== $bNeg) {
if ($aNeg !== $bNeg) {
for ($i = 0; $i < 4; ++$i) {
$res[$i] = ($res[$i] ^ 0xffff) & 0xffff;
}
$c = 1;
for ($i = 0; $i < 4; ++$i) {
$res[$i] += $c;
$c = $res[$i] >> 16;
$res[$i] &= 0xffff;
}
}
}
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->limbs = array($res[3] & 0xffff, $res[2] & 0xffff, $res[1] & 0xffff, $res[0] & 0xffff);
if (\count($res) > 4) {
$return->overflow = $res[4];
}
return $return;
}
/**
* @param ParagonIE_Sodium_Core32_Int64 $int
* @param int $size
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
*/
public function mulInt64(\ParagonIE_Sodium_Core32_Int64 $int, $size = 0)
{
if (\ParagonIE_Sodium_Compat::$fastMult) {
return $this->mulInt64Fast($int);
}
\ParagonIE_Sodium_Core32_Util::declareScalarType($size, 'int', 2);
if (!$size) {
$size = 63;
}
list($a, $b) = self::ctSelect($this, $int);
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
// Initialize:
$ret0 = 0;
$ret1 = 0;
$ret2 = 0;
$ret3 = 0;
$a0 = $a->limbs[0];
$a1 = $a->limbs[1];
$a2 = $a->limbs[2];
$a3 = $a->limbs[3];
$b0 = $b->limbs[0];
$b1 = $b->limbs[1];
$b2 = $b->limbs[2];
$b3 = $b->limbs[3];
/** @var int $size */
/** @var int $i */
for ($i = (int) $size; $i >= 0; --$i) {
$mask = -($b3 & 1);
$x0 = $a0 & $mask;
$x1 = $a1 & $mask;
$x2 = $a2 & $mask;
$x3 = $a3 & $mask;
$ret3 += $x3;
$c = $ret3 >> 16;
$ret2 += $x2 + $c;
$c = $ret2 >> 16;
$ret1 += $x1 + $c;
$c = $ret1 >> 16;
$ret0 += $x0 + $c;
$ret0 &= 0xffff;
$ret1 &= 0xffff;
$ret2 &= 0xffff;
$ret3 &= 0xffff;
$a3 = $a3 << 1;
$x3 = $a3 >> 16;
$a2 = $a2 << 1 | $x3;
$x2 = $a2 >> 16;
$a1 = $a1 << 1 | $x2;
$x1 = $a1 >> 16;
$a0 = $a0 << 1 | $x1;
$a0 &= 0xffff;
$a1 &= 0xffff;
$a2 &= 0xffff;
$a3 &= 0xffff;
$x0 = ($b0 & 1) << 16;
$x1 = ($b1 & 1) << 16;
$x2 = ($b2 & 1) << 16;
$b0 = $b0 >> 1;
$b1 = ($b1 | $x0) >> 1;
$b2 = ($b2 | $x1) >> 1;
$b3 = ($b3 | $x2) >> 1;
$b0 &= 0xffff;
$b1 &= 0xffff;
$b2 &= 0xffff;
$b3 &= 0xffff;
}
$return->limbs[0] = $ret0;
$return->limbs[1] = $ret1;
$return->limbs[2] = $ret2;
$return->limbs[3] = $ret3;
return $return;
}
/**
* OR this 64-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int64 $b
* @return ParagonIE_Sodium_Core32_Int64
*/
public function orInt64(\ParagonIE_Sodium_Core32_Int64 $b)
{
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array((int) ($this->limbs[0] | $b->limbs[0]), (int) ($this->limbs[1] | $b->limbs[1]), (int) ($this->limbs[2] | $b->limbs[2]), (int) ($this->limbs[3] | $b->limbs[3]));
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateLeft($c = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
/** @var int $idx_shift */
$idx_shift = $c >> 4 & 3;
/** @var int $sub_shift */
$sub_shift = $c & 15;
for ($i = 3; $i >= 0; --$i) {
/** @var int $j */
$j = $i + $idx_shift & 3;
/** @var int $k */
$k = $i + $idx_shift + 1 & 3;
$limbs[$i] = (int) (((int) $myLimbs[$j] << $sub_shift | (int) $myLimbs[$k] >> 16 - $sub_shift) & 0xffff);
}
}
return $return;
}
/**
* Rotate to the right
*
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedArrayAccess
*/
public function rotateRight($c = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
/** @var ParagonIE_Sodium_Core32_Int64 $return */
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
/** @var int $c */
if ($c === 0) {
// NOP, but we want a copy.
$return->limbs = $this->limbs;
} else {
/** @var array<int, int> $limbs */
$limbs =& $return->limbs;
/** @var array<int, int> $myLimbs */
$myLimbs =& $this->limbs;
/** @var int $idx_shift */
$idx_shift = $c >> 4 & 3;
/** @var int $sub_shift */
$sub_shift = $c & 15;
for ($i = 3; $i >= 0; --$i) {
/** @var int $j */
$j = $i - $idx_shift & 3;
/** @var int $k */
$k = $i - $idx_shift - 1 & 3;
$limbs[$i] = (int) (((int) $myLimbs[$j] >> (int) $sub_shift | (int) $myLimbs[$k] << 16 - (int) $sub_shift) & 0xffff);
}
}
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function shiftLeft($c = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
/** @var int $c */
$c = (int) $c;
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
if ($c >= 16) {
if ($c >= 48) {
$return->limbs = array($this->limbs[3], 0, 0, 0);
} elseif ($c >= 32) {
$return->limbs = array($this->limbs[2], $this->limbs[3], 0, 0);
} else {
$return->limbs = array($this->limbs[1], $this->limbs[2], $this->limbs[3], 0);
}
return $return->shiftLeft($c & 15);
}
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
/** @var int $c */
return $this->shiftRight(-$c);
} else {
if (!\is_int($c)) {
throw new \TypeError();
}
/** @var int $carry */
$carry = 0;
for ($i = 3; $i >= 0; --$i) {
/** @var int $tmp */
$tmp = $this->limbs[$i] << $c | $carry & 0xffff;
$return->limbs[$i] = (int) ($tmp & 0xffff);
/** @var int $carry */
$carry = $tmp >> 16;
}
}
return $return;
}
/**
* @param int $c
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function shiftRight($c = 0)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($c, 'int', 1);
$c = (int) $c;
/** @var int $c */
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$c &= 63;
$negative = -($this->limbs[0] >> 15 & 1);
if ($c >= 16) {
if ($c >= 48) {
$return->limbs = array((int) ($negative & 0xffff), (int) ($negative & 0xffff), (int) ($negative & 0xffff), (int) $this->limbs[0]);
} elseif ($c >= 32) {
$return->limbs = array((int) ($negative & 0xffff), (int) ($negative & 0xffff), (int) $this->limbs[0], (int) $this->limbs[1]);
} else {
$return->limbs = array((int) ($negative & 0xffff), (int) $this->limbs[0], (int) $this->limbs[1], (int) $this->limbs[2]);
}
return $return->shiftRight($c & 15);
}
if ($c === 0) {
$return->limbs = $this->limbs;
} elseif ($c < 0) {
return $this->shiftLeft(-$c);
} else {
if (!\is_int($c)) {
throw new \TypeError();
}
/** @var int $carryRight */
$carryRight = $negative & 0xffff;
$mask = (int) ((1 << $c + 1) - 1 & 0xffff);
for ($i = 0; $i < 4; ++$i) {
$return->limbs[$i] = (int) (($this->limbs[$i] >> $c | $carryRight << 16 - $c) & 0xffff);
$carryRight = (int) ($this->limbs[$i] & $mask);
}
}
return $return;
}
/**
* Subtract a normal integer from an int64 object.
*
* @param int $int
* @return ParagonIE_Sodium_Core32_Int64
* @throws SodiumException
* @throws TypeError
*/
public function subInt($int)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($int, 'int', 1);
$int = (int) $int;
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
/** @var int $carry */
$carry = 0;
for ($i = 3; $i >= 0; --$i) {
/** @var int $tmp */
$tmp = $this->limbs[$i] - ($int >> 16 & 0xffff) + $carry;
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[$i] = (int) ($tmp & 0xffff);
}
return $return;
}
/**
* The difference between two Int64 objects.
*
* @param ParagonIE_Sodium_Core32_Int64 $b
* @return ParagonIE_Sodium_Core32_Int64
*/
public function subInt64(\ParagonIE_Sodium_Core32_Int64 $b)
{
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
/** @var int $carry */
$carry = 0;
for ($i = 3; $i >= 0; --$i) {
/** @var int $tmp */
$tmp = $this->limbs[$i] - $b->limbs[$i] + $carry;
/** @var int $carry */
$carry = $tmp >> 16;
$return->limbs[$i] = (int) ($tmp & 0xffff);
}
return $return;
}
/**
* XOR this 64-bit integer with another.
*
* @param ParagonIE_Sodium_Core32_Int64 $b
* @return ParagonIE_Sodium_Core32_Int64
*/
public function xorInt64(\ParagonIE_Sodium_Core32_Int64 $b)
{
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->unsignedInt = $this->unsignedInt;
$return->limbs = array((int) ($this->limbs[0] ^ $b->limbs[0]), (int) ($this->limbs[1] ^ $b->limbs[1]), (int) ($this->limbs[2] ^ $b->limbs[2]), (int) ($this->limbs[3] ^ $b->limbs[3]));
return $return;
}
/**
* @param int $low
* @param int $high
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromInts($low, $high)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($low, 'int', 1);
\ParagonIE_Sodium_Core32_Util::declareScalarType($high, 'int', 2);
$high = (int) $high;
$low = (int) $low;
return new \ParagonIE_Sodium_Core32_Int64(array((int) ($high >> 16 & 0xffff), (int) ($high & 0xffff), (int) ($low >> 16 & 0xffff), (int) ($low & 0xffff)));
}
/**
* @param int $low
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromInt($low)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($low, 'int', 1);
$low = (int) $low;
return new \ParagonIE_Sodium_Core32_Int64(array(0, 0, (int) ($low >> 16 & 0xffff), (int) ($low & 0xffff)));
}
/**
* @return int
*/
public function toInt()
{
return (int) (($this->limbs[2] & 0xffff) << 16 | $this->limbs[3] & 0xffff);
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromString($string)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
$string = (string) $string;
if (\ParagonIE_Sodium_Core32_Util::strlen($string) !== 8) {
throw new \RangeException('String must be 8 bytes; ' . \ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.');
}
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->limbs[0] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff) << 8);
$return->limbs[0] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff;
$return->limbs[1] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff) << 8);
$return->limbs[1] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff;
$return->limbs[2] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[4]) & 0xff) << 8);
$return->limbs[2] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[5]) & 0xff;
$return->limbs[3] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[6]) & 0xff) << 8);
$return->limbs[3] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[7]) & 0xff;
return $return;
}
/**
* @param string $string
* @return self
* @throws SodiumException
* @throws TypeError
*/
public static function fromReverseString($string)
{
\ParagonIE_Sodium_Core32_Util::declareScalarType($string, 'string', 1);
$string = (string) $string;
if (\ParagonIE_Sodium_Core32_Util::strlen($string) !== 8) {
throw new \RangeException('String must be 8 bytes; ' . \ParagonIE_Sodium_Core32_Util::strlen($string) . ' given.');
}
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->limbs[0] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[7]) & 0xff) << 8);
$return->limbs[0] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[6]) & 0xff;
$return->limbs[1] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[5]) & 0xff) << 8);
$return->limbs[1] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[4]) & 0xff;
$return->limbs[2] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[3]) & 0xff) << 8);
$return->limbs[2] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[2]) & 0xff;
$return->limbs[3] = (int) ((\ParagonIE_Sodium_Core32_Util::chrToInt($string[1]) & 0xff) << 8);
$return->limbs[3] |= \ParagonIE_Sodium_Core32_Util::chrToInt($string[0]) & 0xff;
return $return;
}
/**
* @return array<int, int>
*/
public function toArray()
{
return array((int) (($this->limbs[0] & 0xffff) << 16 | $this->limbs[1] & 0xffff), (int) (($this->limbs[2] & 0xffff) << 16 | $this->limbs[3] & 0xffff));
}
/**
* @return ParagonIE_Sodium_Core32_Int32
*/
public function toInt32()
{
$return = new \ParagonIE_Sodium_Core32_Int32();
$return->limbs[0] = (int) $this->limbs[2];
$return->limbs[1] = (int) $this->limbs[3];
$return->unsignedInt = $this->unsignedInt;
$return->overflow = (int) (\ParagonIE_Sodium_Core32_Util::abs($this->limbs[1], 16) & 0xffff);
return $return;
}
/**
* @return ParagonIE_Sodium_Core32_Int64
*/
public function toInt64()
{
$return = new \ParagonIE_Sodium_Core32_Int64();
$return->limbs[0] = (int) $this->limbs[0];
$return->limbs[1] = (int) $this->limbs[1];
$return->limbs[2] = (int) $this->limbs[2];
$return->limbs[3] = (int) $this->limbs[3];
$return->unsignedInt = $this->unsignedInt;
$return->overflow = \ParagonIE_Sodium_Core32_Util::abs($this->overflow);
return $return;
}
/**
* @param bool $bool
* @return self
*/
public function setUnsignedInt($bool = \false)
{
$this->unsignedInt = !empty($bool);
return $this;
}
/**
* @return string
* @throws TypeError
*/
public function toString()
{
return \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3] & 0xff);
}
/**
* @return string
* @throws TypeError
*/
public function toReverseString()
{
return \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[3] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[2] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[1] >> 8 & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] & 0xff) . \ParagonIE_Sodium_Core32_Util::intToChr($this->limbs[0] >> 8 & 0xff);
}
/**
* @return string
*/
public function __toString()
{
try {
return $this->toString();
} catch (\TypeError $ex) {
// PHP engine can't handle exceptions from __toString()
return '';
}
}
}
/**
* Class ParagonIE_Sodium_Core32_Int64
*
* Encapsulates a 64-bit integer.
*
* These are immutable. It always returns a new instance.
*/

View File

@@ -0,0 +1,53 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Poly1305', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Poly1305
*/
abstract class ParagonIE_Sodium_Core32_Poly1305 extends \ParagonIE_Sodium_Core32_Util
{
const BLOCK_SIZE = 16;
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth($m, $key)
{
if (self::strlen($key) < 32) {
throw new \InvalidArgumentException('Key must be 32 bytes long.');
}
$state = new \ParagonIE_Sodium_Core32_Poly1305_State(self::substr($key, 0, 32));
return $state->update($m)->finish();
}
/**
* @internal You should not use this directly from another application
*
* @param string $mac
* @param string $m
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth_verify($mac, $m, $key)
{
if (self::strlen($key) < 32) {
throw new \InvalidArgumentException('Key must be 32 bytes long.');
}
$state = new \ParagonIE_Sodium_Core32_Poly1305_State(self::substr($key, 0, 32));
$calc = $state->update($m)->finish();
return self::verify_16($calc, $mac);
}
}
/**
* Class ParagonIE_Sodium_Core32_Poly1305
*/

View File

@@ -0,0 +1,334 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Poly1305_State', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Poly1305_State
*/
class ParagonIE_Sodium_Core32_Poly1305_State extends \ParagonIE_Sodium_Core32_Util
{
/**
* @var array<int, int>
*/
protected $buffer = array();
/**
* @var bool
*/
protected $final = \false;
/**
* @var array<int, ParagonIE_Sodium_Core32_Int32>
*/
public $h;
/**
* @var int
*/
protected $leftover = 0;
/**
* @var array<int, ParagonIE_Sodium_Core32_Int32>
*/
public $r;
/**
* @var array<int, ParagonIE_Sodium_Core32_Int64>
*/
public $pad;
/**
* ParagonIE_Sodium_Core32_Poly1305_State constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct($key = '')
{
if (self::strlen($key) < 32) {
throw new \InvalidArgumentException('Poly1305 requires a 32-byte key');
}
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
$this->r = array(
// st->r[0] = ...
\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4))->setUnsignedInt(\true)->mask(0x3ffffff),
// st->r[1] = ...
\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 3, 4))->setUnsignedInt(\true)->shiftRight(2)->mask(0x3ffff03),
// st->r[2] = ...
\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 6, 4))->setUnsignedInt(\true)->shiftRight(4)->mask(0x3ffc0ff),
// st->r[3] = ...
\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 9, 4))->setUnsignedInt(\true)->shiftRight(6)->mask(0x3f03fff),
// st->r[4] = ...
\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4))->setUnsignedInt(\true)->shiftRight(8)->mask(0xfffff),
);
/* h = 0 */
$this->h = array(new \ParagonIE_Sodium_Core32_Int32(array(0, 0), \true), new \ParagonIE_Sodium_Core32_Int32(array(0, 0), \true), new \ParagonIE_Sodium_Core32_Int32(array(0, 0), \true), new \ParagonIE_Sodium_Core32_Int32(array(0, 0), \true), new \ParagonIE_Sodium_Core32_Int32(array(0, 0), \true));
/* save pad for later */
$this->pad = array(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4))->setUnsignedInt(\true)->toInt64(), \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4))->setUnsignedInt(\true)->toInt64(), \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4))->setUnsignedInt(\true)->toInt64(), \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4))->setUnsignedInt(\true)->toInt64());
$this->leftover = 0;
$this->final = \false;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function update($message = '')
{
$bytes = self::strlen($message);
/* handle leftover */
if ($this->leftover) {
/** @var int $want */
$want = \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE - $this->leftover;
if ($want > $bytes) {
$want = $bytes;
}
for ($i = 0; $i < $want; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
// We snip off the leftmost bytes.
$message = self::substr($message, $want);
$bytes = self::strlen($message);
$this->leftover += $want;
if ($this->leftover < \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
// We still don't have enough to run $this->blocks()
return $this;
}
$this->blocks(self::intArrayToString($this->buffer), \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE);
$this->leftover = 0;
}
/* process full blocks */
if ($bytes >= \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
/** @var int $want */
$want = $bytes & ~(\ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE - 1);
if ($want >= \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
/** @var string $block */
$block = self::substr($message, 0, $want);
if (self::strlen($block) >= \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
$this->blocks($block, $want);
$message = self::substr($message, $want);
$bytes = self::strlen($message);
}
}
}
/* store leftover */
if ($bytes) {
for ($i = 0; $i < $bytes; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
$this->leftover = (int) $this->leftover + $bytes;
}
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param int $bytes
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function blocks($message, $bytes)
{
if (self::strlen($message) < 16) {
$message = \str_pad($message, 16, "\x00", \STR_PAD_RIGHT);
}
$hibit = \ParagonIE_Sodium_Core32_Int32::fromInt((int) ($this->final ? 0 : 1 << 24));
/* 1 << 128 */
$hibit->setUnsignedInt(\true);
$zero = new \ParagonIE_Sodium_Core32_Int64(array(0, 0, 0, 0), \true);
/**
* @var ParagonIE_Sodium_Core32_Int64 $d0
* @var ParagonIE_Sodium_Core32_Int64 $d1
* @var ParagonIE_Sodium_Core32_Int64 $d2
* @var ParagonIE_Sodium_Core32_Int64 $d3
* @var ParagonIE_Sodium_Core32_Int64 $d4
* @var ParagonIE_Sodium_Core32_Int64 $r0
* @var ParagonIE_Sodium_Core32_Int64 $r1
* @var ParagonIE_Sodium_Core32_Int64 $r2
* @var ParagonIE_Sodium_Core32_Int64 $r3
* @var ParagonIE_Sodium_Core32_Int64 $r4
*
* @var ParagonIE_Sodium_Core32_Int32 $h0
* @var ParagonIE_Sodium_Core32_Int32 $h1
* @var ParagonIE_Sodium_Core32_Int32 $h2
* @var ParagonIE_Sodium_Core32_Int32 $h3
* @var ParagonIE_Sodium_Core32_Int32 $h4
*/
$r0 = $this->r[0]->toInt64();
$r1 = $this->r[1]->toInt64();
$r2 = $this->r[2]->toInt64();
$r3 = $this->r[3]->toInt64();
$r4 = $this->r[4]->toInt64();
$s1 = $r1->toInt64()->mulInt(5, 3);
$s2 = $r2->toInt64()->mulInt(5, 3);
$s3 = $r3->toInt64()->mulInt(5, 3);
$s4 = $r4->toInt64()->mulInt(5, 3);
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
while ($bytes >= \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE) {
/* h += m[i] */
$h0 = $h0->addInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 0, 4))->mask(0x3ffffff))->toInt64();
$h1 = $h1->addInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 3, 4))->shiftRight(2)->mask(0x3ffffff))->toInt64();
$h2 = $h2->addInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 6, 4))->shiftRight(4)->mask(0x3ffffff))->toInt64();
$h3 = $h3->addInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 9, 4))->shiftRight(6)->mask(0x3ffffff))->toInt64();
$h4 = $h4->addInt32(\ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($message, 12, 4))->shiftRight(8)->orInt32($hibit))->toInt64();
/* h *= r */
$d0 = $zero->addInt64($h0->mulInt64($r0, 27))->addInt64($s4->mulInt64($h1, 27))->addInt64($s3->mulInt64($h2, 27))->addInt64($s2->mulInt64($h3, 27))->addInt64($s1->mulInt64($h4, 27));
$d1 = $zero->addInt64($h0->mulInt64($r1, 27))->addInt64($h1->mulInt64($r0, 27))->addInt64($s4->mulInt64($h2, 27))->addInt64($s3->mulInt64($h3, 27))->addInt64($s2->mulInt64($h4, 27));
$d2 = $zero->addInt64($h0->mulInt64($r2, 27))->addInt64($h1->mulInt64($r1, 27))->addInt64($h2->mulInt64($r0, 27))->addInt64($s4->mulInt64($h3, 27))->addInt64($s3->mulInt64($h4, 27));
$d3 = $zero->addInt64($h0->mulInt64($r3, 27))->addInt64($h1->mulInt64($r2, 27))->addInt64($h2->mulInt64($r1, 27))->addInt64($h3->mulInt64($r0, 27))->addInt64($s4->mulInt64($h4, 27));
$d4 = $zero->addInt64($h0->mulInt64($r4, 27))->addInt64($h1->mulInt64($r3, 27))->addInt64($h2->mulInt64($r2, 27))->addInt64($h3->mulInt64($r1, 27))->addInt64($h4->mulInt64($r0, 27));
/* (partial) h %= p */
$c = $d0->shiftRight(26);
$h0 = $d0->toInt32()->mask(0x3ffffff);
$d1 = $d1->addInt64($c);
$c = $d1->shiftRight(26);
$h1 = $d1->toInt32()->mask(0x3ffffff);
$d2 = $d2->addInt64($c);
$c = $d2->shiftRight(26);
$h2 = $d2->toInt32()->mask(0x3ffffff);
$d3 = $d3->addInt64($c);
$c = $d3->shiftRight(26);
$h3 = $d3->toInt32()->mask(0x3ffffff);
$d4 = $d4->addInt64($c);
$c = $d4->shiftRight(26);
$h4 = $d4->toInt32()->mask(0x3ffffff);
$h0 = $h0->addInt32($c->toInt32()->mulInt(5, 3));
$c = $h0->shiftRight(26);
$h0 = $h0->mask(0x3ffffff);
$h1 = $h1->addInt32($c);
// Chop off the left 32 bytes.
$message = self::substr($message, \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE);
$bytes -= \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE;
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
$this->h = array($h0, $h1, $h2, $h3, $h4);
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @return string
* @throws SodiumException
* @throws TypeError
*/
public function finish()
{
/* process the remaining block */
if ($this->leftover) {
$i = $this->leftover;
$this->buffer[$i++] = 1;
for (; $i < \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE; ++$i) {
$this->buffer[$i] = 0;
}
$this->final = \true;
$this->blocks(self::substr(self::intArrayToString($this->buffer), 0, \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE), $b = \ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE);
}
/**
* @var ParagonIE_Sodium_Core32_Int32 $f
* @var ParagonIE_Sodium_Core32_Int32 $g0
* @var ParagonIE_Sodium_Core32_Int32 $g1
* @var ParagonIE_Sodium_Core32_Int32 $g2
* @var ParagonIE_Sodium_Core32_Int32 $g3
* @var ParagonIE_Sodium_Core32_Int32 $g4
* @var ParagonIE_Sodium_Core32_Int32 $h0
* @var ParagonIE_Sodium_Core32_Int32 $h1
* @var ParagonIE_Sodium_Core32_Int32 $h2
* @var ParagonIE_Sodium_Core32_Int32 $h3
* @var ParagonIE_Sodium_Core32_Int32 $h4
*/
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
$c = $h1->shiftRight(26);
# $c = $h1 >> 26;
$h1 = $h1->mask(0x3ffffff);
# $h1 &= 0x3ffffff;
$h2 = $h2->addInt32($c);
# $h2 += $c;
$c = $h2->shiftRight(26);
# $c = $h2 >> 26;
$h2 = $h2->mask(0x3ffffff);
# $h2 &= 0x3ffffff;
$h3 = $h3->addInt32($c);
# $h3 += $c;
$c = $h3->shiftRight(26);
# $c = $h3 >> 26;
$h3 = $h3->mask(0x3ffffff);
# $h3 &= 0x3ffffff;
$h4 = $h4->addInt32($c);
# $h4 += $c;
$c = $h4->shiftRight(26);
# $c = $h4 >> 26;
$h4 = $h4->mask(0x3ffffff);
# $h4 &= 0x3ffffff;
$h0 = $h0->addInt32($c->mulInt(5, 3));
# $h0 += self::mul($c, 5);
$c = $h0->shiftRight(26);
# $c = $h0 >> 26;
$h0 = $h0->mask(0x3ffffff);
# $h0 &= 0x3ffffff;
$h1 = $h1->addInt32($c);
# $h1 += $c;
/* compute h + -p */
$g0 = $h0->addInt(5);
$c = $g0->shiftRight(26);
$g0 = $g0->mask(0x3ffffff);
$g1 = $h1->addInt32($c);
$c = $g1->shiftRight(26);
$g1 = $g1->mask(0x3ffffff);
$g2 = $h2->addInt32($c);
$c = $g2->shiftRight(26);
$g2 = $g2->mask(0x3ffffff);
$g3 = $h3->addInt32($c);
$c = $g3->shiftRight(26);
$g3 = $g3->mask(0x3ffffff);
$g4 = $h4->addInt32($c)->subInt(1 << 26);
# $mask = ($g4 >> 31) - 1;
/* select h if h < p, or h + -p if h >= p */
$mask = (int) (($g4->toInt() >> 31) + 1);
$g0 = $g0->mask($mask);
$g1 = $g1->mask($mask);
$g2 = $g2->mask($mask);
$g3 = $g3->mask($mask);
$g4 = $g4->mask($mask);
/** @var int $mask */
$mask = ~$mask;
$h0 = $h0->mask($mask)->orInt32($g0);
$h1 = $h1->mask($mask)->orInt32($g1);
$h2 = $h2->mask($mask)->orInt32($g2);
$h3 = $h3->mask($mask)->orInt32($g3);
$h4 = $h4->mask($mask)->orInt32($g4);
/* h = h % (2^128) */
$h0 = $h0->orInt32($h1->shiftLeft(26));
$h1 = $h1->shiftRight(6)->orInt32($h2->shiftLeft(20));
$h2 = $h2->shiftRight(12)->orInt32($h3->shiftLeft(14));
$h3 = $h3->shiftRight(18)->orInt32($h4->shiftLeft(8));
/* mac = (h + pad) % (2^128) */
$f = $h0->toInt64()->addInt64($this->pad[0]);
$h0 = $f->toInt32();
$f = $h1->toInt64()->addInt64($this->pad[1])->addInt($h0->overflow);
$h1 = $f->toInt32();
$f = $h2->toInt64()->addInt64($this->pad[2])->addInt($h1->overflow);
$h2 = $f->toInt32();
$f = $h3->toInt64()->addInt64($this->pad[3])->addInt($h2->overflow);
$h3 = $f->toInt32();
return $h0->toReverseString() . $h1->toReverseString() . $h2->toReverseString() . $h3->toReverseString();
}
}
/**
* Class ParagonIE_Sodium_Core32_Poly1305_State
*/

View File

@@ -0,0 +1,259 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Salsa20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_Salsa20
*/
abstract class ParagonIE_Sodium_Core32_Salsa20 extends \ParagonIE_Sodium_Core32_Util
{
const ROUNDS = 20;
/**
* Calculate an salsa20 hash of a single block
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function core_salsa20($in, $k, $c = null)
{
/**
* @var ParagonIE_Sodium_Core32_Int32 $x0
* @var ParagonIE_Sodium_Core32_Int32 $x1
* @var ParagonIE_Sodium_Core32_Int32 $x2
* @var ParagonIE_Sodium_Core32_Int32 $x3
* @var ParagonIE_Sodium_Core32_Int32 $x4
* @var ParagonIE_Sodium_Core32_Int32 $x5
* @var ParagonIE_Sodium_Core32_Int32 $x6
* @var ParagonIE_Sodium_Core32_Int32 $x7
* @var ParagonIE_Sodium_Core32_Int32 $x8
* @var ParagonIE_Sodium_Core32_Int32 $x9
* @var ParagonIE_Sodium_Core32_Int32 $x10
* @var ParagonIE_Sodium_Core32_Int32 $x11
* @var ParagonIE_Sodium_Core32_Int32 $x12
* @var ParagonIE_Sodium_Core32_Int32 $x13
* @var ParagonIE_Sodium_Core32_Int32 $x14
* @var ParagonIE_Sodium_Core32_Int32 $x15
* @var ParagonIE_Sodium_Core32_Int32 $j0
* @var ParagonIE_Sodium_Core32_Int32 $j1
* @var ParagonIE_Sodium_Core32_Int32 $j2
* @var ParagonIE_Sodium_Core32_Int32 $j3
* @var ParagonIE_Sodium_Core32_Int32 $j4
* @var ParagonIE_Sodium_Core32_Int32 $j5
* @var ParagonIE_Sodium_Core32_Int32 $j6
* @var ParagonIE_Sodium_Core32_Int32 $j7
* @var ParagonIE_Sodium_Core32_Int32 $j8
* @var ParagonIE_Sodium_Core32_Int32 $j9
* @var ParagonIE_Sodium_Core32_Int32 $j10
* @var ParagonIE_Sodium_Core32_Int32 $j11
* @var ParagonIE_Sodium_Core32_Int32 $j12
* @var ParagonIE_Sodium_Core32_Int32 $j13
* @var ParagonIE_Sodium_Core32_Int32 $j14
* @var ParagonIE_Sodium_Core32_Int32 $j15
*/
if (self::strlen($k) < 32) {
throw new \RangeException('Key must be 32 bytes long');
}
if ($c === null) {
$x0 = new \ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
$x5 = new \ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
$x10 = new \ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
$x15 = new \ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
} else {
$x0 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 0, 4));
$x5 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 4, 4));
$x10 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 8, 4));
$x15 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($c, 12, 4));
}
$x1 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 0, 4));
$x2 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 4, 4));
$x3 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 8, 4));
$x4 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 12, 4));
$x6 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 0, 4));
$x7 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 4, 4));
$x8 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 8, 4));
$x9 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($in, 12, 4));
$x11 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 16, 4));
$x12 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 20, 4));
$x13 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 24, 4));
$x14 = \ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($k, 28, 4));
$j0 = clone $x0;
$j1 = clone $x1;
$j2 = clone $x2;
$j3 = clone $x3;
$j4 = clone $x4;
$j5 = clone $x5;
$j6 = clone $x6;
$j7 = clone $x7;
$j8 = clone $x8;
$j9 = clone $x9;
$j10 = clone $x10;
$j11 = clone $x11;
$j12 = clone $x12;
$j13 = clone $x13;
$j14 = clone $x14;
$j15 = clone $x15;
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 = $x4->xorInt32($x0->addInt32($x12)->rotateLeft(7));
$x8 = $x8->xorInt32($x4->addInt32($x0)->rotateLeft(9));
$x12 = $x12->xorInt32($x8->addInt32($x4)->rotateLeft(13));
$x0 = $x0->xorInt32($x12->addInt32($x8)->rotateLeft(18));
$x9 = $x9->xorInt32($x5->addInt32($x1)->rotateLeft(7));
$x13 = $x13->xorInt32($x9->addInt32($x5)->rotateLeft(9));
$x1 = $x1->xorInt32($x13->addInt32($x9)->rotateLeft(13));
$x5 = $x5->xorInt32($x1->addInt32($x13)->rotateLeft(18));
$x14 = $x14->xorInt32($x10->addInt32($x6)->rotateLeft(7));
$x2 = $x2->xorInt32($x14->addInt32($x10)->rotateLeft(9));
$x6 = $x6->xorInt32($x2->addInt32($x14)->rotateLeft(13));
$x10 = $x10->xorInt32($x6->addInt32($x2)->rotateLeft(18));
$x3 = $x3->xorInt32($x15->addInt32($x11)->rotateLeft(7));
$x7 = $x7->xorInt32($x3->addInt32($x15)->rotateLeft(9));
$x11 = $x11->xorInt32($x7->addInt32($x3)->rotateLeft(13));
$x15 = $x15->xorInt32($x11->addInt32($x7)->rotateLeft(18));
$x1 = $x1->xorInt32($x0->addInt32($x3)->rotateLeft(7));
$x2 = $x2->xorInt32($x1->addInt32($x0)->rotateLeft(9));
$x3 = $x3->xorInt32($x2->addInt32($x1)->rotateLeft(13));
$x0 = $x0->xorInt32($x3->addInt32($x2)->rotateLeft(18));
$x6 = $x6->xorInt32($x5->addInt32($x4)->rotateLeft(7));
$x7 = $x7->xorInt32($x6->addInt32($x5)->rotateLeft(9));
$x4 = $x4->xorInt32($x7->addInt32($x6)->rotateLeft(13));
$x5 = $x5->xorInt32($x4->addInt32($x7)->rotateLeft(18));
$x11 = $x11->xorInt32($x10->addInt32($x9)->rotateLeft(7));
$x8 = $x8->xorInt32($x11->addInt32($x10)->rotateLeft(9));
$x9 = $x9->xorInt32($x8->addInt32($x11)->rotateLeft(13));
$x10 = $x10->xorInt32($x9->addInt32($x8)->rotateLeft(18));
$x12 = $x12->xorInt32($x15->addInt32($x14)->rotateLeft(7));
$x13 = $x13->xorInt32($x12->addInt32($x15)->rotateLeft(9));
$x14 = $x14->xorInt32($x13->addInt32($x12)->rotateLeft(13));
$x15 = $x15->xorInt32($x14->addInt32($x13)->rotateLeft(18));
}
$x0 = $x0->addInt32($j0);
$x1 = $x1->addInt32($j1);
$x2 = $x2->addInt32($j2);
$x3 = $x3->addInt32($j3);
$x4 = $x4->addInt32($j4);
$x5 = $x5->addInt32($j5);
$x6 = $x6->addInt32($j6);
$x7 = $x7->addInt32($j7);
$x8 = $x8->addInt32($j8);
$x9 = $x9->addInt32($j9);
$x10 = $x10->addInt32($j10);
$x11 = $x11->addInt32($j11);
$x12 = $x12->addInt32($j12);
$x13 = $x13->addInt32($j13);
$x14 = $x14->addInt32($j14);
$x15 = $x15->addInt32($j15);
return $x0->toReverseString() . $x1->toReverseString() . $x2->toReverseString() . $x3->toReverseString() . $x4->toReverseString() . $x5->toReverseString() . $x6->toReverseString() . $x7->toReverseString() . $x8->toReverseString() . $x9->toReverseString() . $x10->toReverseString() . $x11->toReverseString() . $x12->toReverseString() . $x13->toReverseString() . $x14->toReverseString() . $x15->toReverseString();
}
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20($len, $nonce, $key)
{
if (self::strlen($key) !== 32) {
throw new \RangeException('Key must be 32 bytes long');
}
$kcopy = '' . $key;
$in = self::substr($nonce, 0, 8) . \str_repeat("\x00", 8);
$c = '';
while ($len >= 64) {
$c .= self::core_salsa20($in, $kcopy, null);
$u = 1;
// Internal counter.
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$len -= 64;
}
if ($len > 0) {
$c .= self::substr(self::core_salsa20($in, $kcopy, null), 0, $len);
}
try {
\ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (\SodiumException $ex) {
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $n
* @param int $ic
* @param string $k
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor_ic($m, $n, $ic, $k)
{
$mlen = self::strlen($m);
if ($mlen < 1) {
return '';
}
$kcopy = self::substr($k, 0, 32);
$in = self::substr($n, 0, 8);
// Initialize the counter
$in .= \ParagonIE_Sodium_Core32_Util::store64_le($ic);
$c = '';
while ($mlen >= 64) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(self::substr($m, 0, 64), self::substr($block, 0, 64));
$u = 1;
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$mlen -= 64;
$m = self::substr($m, 64);
}
if ($mlen) {
$block = self::core_salsa20($in, $kcopy, null);
$c .= self::xorStrings(self::substr($m, 0, $mlen), self::substr($block, 0, $mlen));
}
try {
\ParagonIE_Sodium_Compat::memzero($block);
\ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (\SodiumException $ex) {
$block = null;
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor($message, $nonce, $key)
{
return self::xorStrings($message, self::salsa20(self::strlen($message), $nonce, $key));
}
}
/**
* Class ParagonIE_Sodium_Core32_Salsa20
*/

View File

@@ -0,0 +1,132 @@
<?php
/**
* Class ParagonIE_Sodium_Core32_SecretStream_State
*/
class ParagonIE_Sodium_Core32_SecretStream_State
{
/** @var string $key */
protected $key;
/** @var int $counter */
protected $counter;
/** @var string $nonce */
protected $nonce;
/** @var string $_pad */
protected $_pad;
/**
* ParagonIE_Sodium_Core32_SecretStream_State constructor.
* @param string $key
* @param string|null $nonce
*/
public function __construct($key, $nonce = null)
{
$this->key = $key;
$this->counter = 1;
if (\is_null($nonce)) {
$nonce = \str_repeat("\x00", 12);
}
$this->nonce = \str_pad($nonce, 12, "\x00", \STR_PAD_RIGHT);
$this->_pad = \str_repeat("\x00", 4);
}
/**
* @return self
*/
public function counterReset()
{
$this->counter = 1;
$this->_pad = \str_repeat("\x00", 4);
return $this;
}
/**
* @return string
*/
public function getKey()
{
return $this->key;
}
/**
* @return string
*/
public function getCounter()
{
return \ParagonIE_Sodium_Core32_Util::store32_le($this->counter);
}
/**
* @return string
*/
public function getNonce()
{
if (!\is_string($this->nonce)) {
$this->nonce = \str_repeat("\x00", 12);
}
if (\ParagonIE_Sodium_Core32_Util::strlen($this->nonce) !== 12) {
$this->nonce = \str_pad($this->nonce, 12, "\x00", \STR_PAD_RIGHT);
}
return $this->nonce;
}
/**
* @return string
*/
public function getCombinedNonce()
{
return $this->getCounter() . \ParagonIE_Sodium_Core32_Util::substr($this->getNonce(), 0, 8);
}
/**
* @return self
*/
public function incrementCounter()
{
++$this->counter;
return $this;
}
/**
* @return bool
*/
public function needsRekey()
{
return ($this->counter & 0xffff) === 0;
}
/**
* @param string $newKeyAndNonce
* @return self
*/
public function rekey($newKeyAndNonce)
{
$this->key = \ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 0, 32);
$this->nonce = \str_pad(\ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 32), 12, "\x00", \STR_PAD_RIGHT);
return $this;
}
/**
* @param string $str
* @return self
*/
public function xorNonce($str)
{
$this->nonce = \ParagonIE_Sodium_Core32_Util::xorStrings($this->getNonce(), \str_pad(\ParagonIE_Sodium_Core32_Util::substr($str, 0, 8), 12, "\x00", \STR_PAD_RIGHT));
return $this;
}
/**
* @param string $string
* @return self
*/
public static function fromString($string)
{
$state = new \ParagonIE_Sodium_Core32_SecretStream_State(\ParagonIE_Sodium_Core32_Util::substr($string, 0, 32));
$state->counter = \ParagonIE_Sodium_Core32_Util::load_4(\ParagonIE_Sodium_Core32_Util::substr($string, 32, 4));
$state->nonce = \ParagonIE_Sodium_Core32_Util::substr($string, 36, 12);
$state->_pad = \ParagonIE_Sodium_Core32_Util::substr($string, 48, 8);
return $state;
}
/**
* @return string
*/
public function toString()
{
return $this->key . $this->getCounter() . $this->nonce . $this->_pad;
}
}
/**
* Class ParagonIE_Sodium_Core32_SecretStream_State
*/

View File

@@ -0,0 +1,157 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_SipHash', \false)) {
return;
}
/**
* Class ParagonIE_SodiumCompat_Core32_SipHash
*
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers
*/
class ParagonIE_Sodium_Core32_SipHash extends \ParagonIE_Sodium_Core32_Util
{
/**
* @internal You should not use this directly from another application
*
* @param array<int, ParagonIE_Sodium_Core32_Int64> $v
* @return array<int, ParagonIE_Sodium_Core32_Int64>
*/
public static function sipRound(array $v)
{
# v0 += v1;
$v[0] = $v[0]->addInt64($v[1]);
# v1 = ROTL(v1, 13);
$v[1] = $v[1]->rotateLeft(13);
# v1 ^= v0;
$v[1] = $v[1]->xorInt64($v[0]);
# v0=ROTL(v0,32);
$v[0] = $v[0]->rotateLeft(32);
# v2 += v3;
$v[2] = $v[2]->addInt64($v[3]);
# v3=ROTL(v3,16);
$v[3] = $v[3]->rotateLeft(16);
# v3 ^= v2;
$v[3] = $v[3]->xorInt64($v[2]);
# v0 += v3;
$v[0] = $v[0]->addInt64($v[3]);
# v3=ROTL(v3,21);
$v[3] = $v[3]->rotateLeft(21);
# v3 ^= v0;
$v[3] = $v[3]->xorInt64($v[0]);
# v2 += v1;
$v[2] = $v[2]->addInt64($v[1]);
# v1=ROTL(v1,17);
$v[1] = $v[1]->rotateLeft(17);
# v1 ^= v2;
$v[1] = $v[1]->xorInt64($v[2]);
# v2=ROTL(v2,32)
$v[2] = $v[2]->rotateLeft(32);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sipHash24($in, $key)
{
$inlen = self::strlen($in);
# /* "somepseudorandomlygeneratedbytes" */
# u64 v0 = 0x736f6d6570736575ULL;
# u64 v1 = 0x646f72616e646f6dULL;
# u64 v2 = 0x6c7967656e657261ULL;
# u64 v3 = 0x7465646279746573ULL;
$v = array(new \ParagonIE_Sodium_Core32_Int64(array(0x736f, 0x6d65, 0x7073, 0x6575)), new \ParagonIE_Sodium_Core32_Int64(array(0x646f, 0x7261, 0x6e64, 0x6f6d)), new \ParagonIE_Sodium_Core32_Int64(array(0x6c79, 0x6765, 0x6e65, 0x7261)), new \ParagonIE_Sodium_Core32_Int64(array(0x7465, 0x6462, 0x7974, 0x6573)));
# u64 k0 = LOAD64_LE( k );
# u64 k1 = LOAD64_LE( k + 8 );
$k = array(\ParagonIE_Sodium_Core32_Int64::fromReverseString(self::substr($key, 0, 8)), \ParagonIE_Sodium_Core32_Int64::fromReverseString(self::substr($key, 8, 8)));
# b = ( ( u64 )inlen ) << 56;
$b = new \ParagonIE_Sodium_Core32_Int64(array($inlen << 8 & 0xffff, 0, 0, 0));
# v3 ^= k1;
$v[3] = $v[3]->xorInt64($k[1]);
# v2 ^= k0;
$v[2] = $v[2]->xorInt64($k[0]);
# v1 ^= k1;
$v[1] = $v[1]->xorInt64($k[1]);
# v0 ^= k0;
$v[0] = $v[0]->xorInt64($k[0]);
$left = $inlen;
# for ( ; in != end; in += 8 )
while ($left >= 8) {
# m = LOAD64_LE( in );
$m = \ParagonIE_Sodium_Core32_Int64::fromReverseString(self::substr($in, 0, 8));
# v3 ^= m;
$v[3] = $v[3]->xorInt64($m);
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= m;
$v[0] = $v[0]->xorInt64($m);
$in = self::substr($in, 8);
$left -= 8;
}
# switch( left )
# {
# case 7: b |= ( ( u64 )in[ 6] ) << 48;
# case 6: b |= ( ( u64 )in[ 5] ) << 40;
# case 5: b |= ( ( u64 )in[ 4] ) << 32;
# case 4: b |= ( ( u64 )in[ 3] ) << 24;
# case 3: b |= ( ( u64 )in[ 2] ) << 16;
# case 2: b |= ( ( u64 )in[ 1] ) << 8;
# case 1: b |= ( ( u64 )in[ 0] ); break;
# case 0: break;
# }
switch ($left) {
case 7:
$b = $b->orInt64(\ParagonIE_Sodium_Core32_Int64::fromInts(0, self::chrToInt($in[6]) << 16));
case 6:
$b = $b->orInt64(\ParagonIE_Sodium_Core32_Int64::fromInts(0, self::chrToInt($in[5]) << 8));
case 5:
$b = $b->orInt64(\ParagonIE_Sodium_Core32_Int64::fromInts(0, self::chrToInt($in[4])));
case 4:
$b = $b->orInt64(\ParagonIE_Sodium_Core32_Int64::fromInts(self::chrToInt($in[3]) << 24, 0));
case 3:
$b = $b->orInt64(\ParagonIE_Sodium_Core32_Int64::fromInts(self::chrToInt($in[2]) << 16, 0));
case 2:
$b = $b->orInt64(\ParagonIE_Sodium_Core32_Int64::fromInts(self::chrToInt($in[1]) << 8, 0));
case 1:
$b = $b->orInt64(\ParagonIE_Sodium_Core32_Int64::fromInts(self::chrToInt($in[0]), 0));
case 0:
break;
}
# v3 ^= b;
$v[3] = $v[3]->xorInt64($b);
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= b;
$v[0] = $v[0]->xorInt64($b);
// Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation
# v2 ^= 0xff;
$v[2]->limbs[3] ^= 0xff;
# SIPROUND;
# SIPROUND;
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
$v = self::sipRound($v);
# b = v0 ^ v1 ^ v2 ^ v3;
# STORE64_LE( out, b );
return $v[0]->xorInt64($v[1])->xorInt64($v[2])->xorInt64($v[3])->toReverseString();
}
}
/**
* Class ParagonIE_SodiumCompat_Core32_SipHash
*
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers
*/

View File

@@ -0,0 +1,16 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_Util', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Util
*/
abstract class ParagonIE_Sodium_Core32_Util extends \ParagonIE_Sodium_Core_Util
{
}
/**
* Class ParagonIE_Sodium_Core_Util
*/

View File

@@ -0,0 +1,284 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_X25519', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_X25519
*/
abstract class ParagonIE_Sodium_Core32_X25519 extends \ParagonIE_Sodium_Core32_Curve25519
{
/**
* Alters the objects passed to this method in place.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $g
* @param int $b
* @return void
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedMethodCall
*/
public static function fe_cswap(\ParagonIE_Sodium_Core32_Curve25519_Fe $f, \ParagonIE_Sodium_Core32_Curve25519_Fe $g, $b = 0)
{
$f0 = (int) $f[0]->toInt();
$f1 = (int) $f[1]->toInt();
$f2 = (int) $f[2]->toInt();
$f3 = (int) $f[3]->toInt();
$f4 = (int) $f[4]->toInt();
$f5 = (int) $f[5]->toInt();
$f6 = (int) $f[6]->toInt();
$f7 = (int) $f[7]->toInt();
$f8 = (int) $f[8]->toInt();
$f9 = (int) $f[9]->toInt();
$g0 = (int) $g[0]->toInt();
$g1 = (int) $g[1]->toInt();
$g2 = (int) $g[2]->toInt();
$g3 = (int) $g[3]->toInt();
$g4 = (int) $g[4]->toInt();
$g5 = (int) $g[5]->toInt();
$g6 = (int) $g[6]->toInt();
$g7 = (int) $g[7]->toInt();
$g8 = (int) $g[8]->toInt();
$g9 = (int) $g[9]->toInt();
$b = -$b;
/** @var int $x0 */
$x0 = ($f0 ^ $g0) & $b;
/** @var int $x1 */
$x1 = ($f1 ^ $g1) & $b;
/** @var int $x2 */
$x2 = ($f2 ^ $g2) & $b;
/** @var int $x3 */
$x3 = ($f3 ^ $g3) & $b;
/** @var int $x4 */
$x4 = ($f4 ^ $g4) & $b;
/** @var int $x5 */
$x5 = ($f5 ^ $g5) & $b;
/** @var int $x6 */
$x6 = ($f6 ^ $g6) & $b;
/** @var int $x7 */
$x7 = ($f7 ^ $g7) & $b;
/** @var int $x8 */
$x8 = ($f8 ^ $g8) & $b;
/** @var int $x9 */
$x9 = ($f9 ^ $g9) & $b;
$f[0] = \ParagonIE_Sodium_Core32_Int32::fromInt($f0 ^ $x0);
$f[1] = \ParagonIE_Sodium_Core32_Int32::fromInt($f1 ^ $x1);
$f[2] = \ParagonIE_Sodium_Core32_Int32::fromInt($f2 ^ $x2);
$f[3] = \ParagonIE_Sodium_Core32_Int32::fromInt($f3 ^ $x3);
$f[4] = \ParagonIE_Sodium_Core32_Int32::fromInt($f4 ^ $x4);
$f[5] = \ParagonIE_Sodium_Core32_Int32::fromInt($f5 ^ $x5);
$f[6] = \ParagonIE_Sodium_Core32_Int32::fromInt($f6 ^ $x6);
$f[7] = \ParagonIE_Sodium_Core32_Int32::fromInt($f7 ^ $x7);
$f[8] = \ParagonIE_Sodium_Core32_Int32::fromInt($f8 ^ $x8);
$f[9] = \ParagonIE_Sodium_Core32_Int32::fromInt($f9 ^ $x9);
$g[0] = \ParagonIE_Sodium_Core32_Int32::fromInt($g0 ^ $x0);
$g[1] = \ParagonIE_Sodium_Core32_Int32::fromInt($g1 ^ $x1);
$g[2] = \ParagonIE_Sodium_Core32_Int32::fromInt($g2 ^ $x2);
$g[3] = \ParagonIE_Sodium_Core32_Int32::fromInt($g3 ^ $x3);
$g[4] = \ParagonIE_Sodium_Core32_Int32::fromInt($g4 ^ $x4);
$g[5] = \ParagonIE_Sodium_Core32_Int32::fromInt($g5 ^ $x5);
$g[6] = \ParagonIE_Sodium_Core32_Int32::fromInt($g6 ^ $x6);
$g[7] = \ParagonIE_Sodium_Core32_Int32::fromInt($g7 ^ $x7);
$g[8] = \ParagonIE_Sodium_Core32_Int32::fromInt($g8 ^ $x8);
$g[9] = \ParagonIE_Sodium_Core32_Int32::fromInt($g9 ^ $x9);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedMethodCall
*/
public static function fe_mul121666(\ParagonIE_Sodium_Core32_Curve25519_Fe $f)
{
/** @var array<int, ParagonIE_Sodium_Core32_Int64> $h */
$h = array();
for ($i = 0; $i < 10; ++$i) {
$h[$i] = $f[$i]->toInt64()->mulInt(121666, 17);
}
$carry9 = $h[9]->addInt(1 << 24)->shiftRight(25);
$h[0] = $h[0]->addInt64($carry9->mulInt(19, 5));
$h[9] = $h[9]->subInt64($carry9->shiftLeft(25));
$carry1 = $h[1]->addInt(1 << 24)->shiftRight(25);
$h[2] = $h[2]->addInt64($carry1);
$h[1] = $h[1]->subInt64($carry1->shiftLeft(25));
$carry3 = $h[3]->addInt(1 << 24)->shiftRight(25);
$h[4] = $h[4]->addInt64($carry3);
$h[3] = $h[3]->subInt64($carry3->shiftLeft(25));
$carry5 = $h[5]->addInt(1 << 24)->shiftRight(25);
$h[6] = $h[6]->addInt64($carry5);
$h[5] = $h[5]->subInt64($carry5->shiftLeft(25));
$carry7 = $h[7]->addInt(1 << 24)->shiftRight(25);
$h[8] = $h[8]->addInt64($carry7);
$h[7] = $h[7]->subInt64($carry7->shiftLeft(25));
$carry0 = $h[0]->addInt(1 << 25)->shiftRight(26);
$h[1] = $h[1]->addInt64($carry0);
$h[0] = $h[0]->subInt64($carry0->shiftLeft(26));
$carry2 = $h[2]->addInt(1 << 25)->shiftRight(26);
$h[3] = $h[3]->addInt64($carry2);
$h[2] = $h[2]->subInt64($carry2->shiftLeft(26));
$carry4 = $h[4]->addInt(1 << 25)->shiftRight(26);
$h[5] = $h[5]->addInt64($carry4);
$h[4] = $h[4]->subInt64($carry4->shiftLeft(26));
$carry6 = $h[6]->addInt(1 << 25)->shiftRight(26);
$h[7] = $h[7]->addInt64($carry6);
$h[6] = $h[6]->subInt64($carry6->shiftLeft(26));
$carry8 = $h[8]->addInt(1 << 25)->shiftRight(26);
$h[9] = $h[9]->addInt64($carry8);
$h[8] = $h[8]->subInt64($carry8->shiftLeft(26));
for ($i = 0; $i < 10; ++$i) {
$h[$i] = $h[$i]->toInt32();
}
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h2 */
$h2 = $h;
return \ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h2);
}
/**
* @internal You should not use this directly from another application
*
* Inline comments preceded by # are from libsodium's ref10 code.
*
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10($n, $p)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(self::chrToInt($e[0]) & 248);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(self::chrToInt($e[31]) & 127 | 64);
# fe_frombytes(x1,p);
$x1 = self::fe_frombytes($p);
# fe_1(x2);
$x2 = self::fe_1();
# fe_0(z2);
$z2 = self::fe_0();
# fe_copy(x3,x1);
$x3 = self::fe_copy($x1);
# fe_1(z3);
$z3 = self::fe_1();
# swap = 0;
/** @var int $swap */
$swap = 0;
# for (pos = 254;pos >= 0;--pos) {
for ($pos = 254; $pos >= 0; --$pos) {
# b = e[pos / 8] >> (pos & 7);
/** @var int $b */
$b = self::chrToInt($e[(int) \floor($pos / 8)]) >> ($pos & 7);
# b &= 1;
$b &= 1;
# swap ^= b;
$swap ^= $b;
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# swap = b;
/** @var int $swap */
$swap = $b;
# fe_sub(tmp0,x3,z3);
$tmp0 = self::fe_sub($x3, $z3);
# fe_sub(tmp1,x2,z2);
$tmp1 = self::fe_sub($x2, $z2);
# fe_add(x2,x2,z2);
$x2 = self::fe_add($x2, $z2);
# fe_add(z2,x3,z3);
$z2 = self::fe_add($x3, $z3);
# fe_mul(z3,tmp0,x2);
$z3 = self::fe_mul($tmp0, $x2);
# fe_mul(z2,z2,tmp1);
$z2 = self::fe_mul($z2, $tmp1);
# fe_sq(tmp0,tmp1);
$tmp0 = self::fe_sq($tmp1);
# fe_sq(tmp1,x2);
$tmp1 = self::fe_sq($x2);
# fe_add(x3,z3,z2);
$x3 = self::fe_add($z3, $z2);
# fe_sub(z2,z3,z2);
$z2 = self::fe_sub($z3, $z2);
# fe_mul(x2,tmp1,tmp0);
$x2 = self::fe_mul($tmp1, $tmp0);
# fe_sub(tmp1,tmp1,tmp0);
$tmp1 = self::fe_sub($tmp1, $tmp0);
# fe_sq(z2,z2);
$z2 = self::fe_sq($z2);
# fe_mul121666(z3,tmp1);
$z3 = self::fe_mul121666($tmp1);
# fe_sq(x3,x3);
$x3 = self::fe_sq($x3);
# fe_add(tmp0,tmp0,z3);
$tmp0 = self::fe_add($tmp0, $z3);
# fe_mul(z3,x1,z2);
$z3 = self::fe_mul($x1, $z2);
# fe_mul(z2,tmp1,tmp0);
$z2 = self::fe_mul($tmp1, $tmp0);
}
# fe_cswap(x2,x3,swap);
self::fe_cswap($x2, $x3, $swap);
# fe_cswap(z2,z3,swap);
self::fe_cswap($z2, $z3, $swap);
# fe_invert(z2,z2);
$z2 = self::fe_invert($z2);
# fe_mul(x2,x2,z2);
$x2 = self::fe_mul($x2, $z2);
# fe_tobytes(q,x2);
return (string) self::fe_tobytes($x2);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsY
* @param ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsZ
* @return ParagonIE_Sodium_Core32_Curve25519_Fe
* @throws SodiumException
* @throws TypeError
*/
public static function edwards_to_montgomery(\ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsY, \ParagonIE_Sodium_Core32_Curve25519_Fe $edwardsZ)
{
$tempX = self::fe_add($edwardsZ, $edwardsY);
$tempZ = self::fe_sub($edwardsZ, $edwardsY);
$tempZ = self::fe_invert($tempZ);
return self::fe_mul($tempX, $tempZ);
}
/**
* @internal You should not use this directly from another application
*
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10_base($n)
{
# for (i = 0;i < 32;++i) e[i] = n[i];
$e = '' . $n;
# e[0] &= 248;
$e[0] = self::intToChr(self::chrToInt($e[0]) & 248);
# e[31] &= 127;
# e[31] |= 64;
$e[31] = self::intToChr(self::chrToInt($e[31]) & 127 | 64);
$A = self::ge_scalarmult_base($e);
if (!$A->Y instanceof \ParagonIE_Sodium_Core32_Curve25519_Fe || !$A->Z instanceof \ParagonIE_Sodium_Core32_Curve25519_Fe) {
throw new \TypeError('Null points encountered');
}
$pk = self::edwards_to_montgomery($A->Y, $A->Z);
return self::fe_tobytes($pk);
}
}
/**
* Class ParagonIE_Sodium_Core32_X25519
*/

View File

@@ -0,0 +1,66 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_XChaCha20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_XChaCha20
*/
class ParagonIE_Sodium_Core32_XChaCha20 extends \ParagonIE_Sodium_Core32_HChaCha20
{
/**
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function stream($len = 64, $nonce = '', $key = '')
{
if (self::strlen($nonce) !== 24) {
throw new \SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(new \ParagonIE_Sodium_Core32_ChaCha20_Ctx(self::hChaCha20(self::substr($nonce, 0, 16), $key), self::substr($nonce, 16, 8)), \str_repeat("\x00", $len));
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc($message, $nonce = '', $key = '', $ic = '')
{
if (self::strlen($nonce) !== 24) {
throw new \SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(new \ParagonIE_Sodium_Core32_ChaCha20_Ctx(self::hChaCha20(self::substr($nonce, 0, 16), $key), self::substr($nonce, 16, 8), $ic), $message);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
{
return self::encryptBytes(new \ParagonIE_Sodium_Core32_ChaCha20_IetfCtx(self::hChaCha20(self::substr($nonce, 0, 16), $key), "\x00\x00\x00\x00" . self::substr($nonce, 16, 8), $ic), $message);
}
}
/**
* Class ParagonIE_Sodium_Core32_XChaCha20
*/

View File

@@ -0,0 +1,49 @@
<?php
if (\class_exists('ParagonIE_Sodium_Core32_XSalsa20', \false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core32_XSalsa20
*/
abstract class ParagonIE_Sodium_Core32_XSalsa20 extends \ParagonIE_Sodium_Core32_HSalsa20
{
/**
* Expand a key and nonce into an xsalsa20 keystream.
*
* @internal You should not use this directly from another application
*
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20($len, $nonce, $key)
{
$ret = self::salsa20($len, self::substr($nonce, 16, 8), self::hsalsa20($nonce, $key));
return $ret;
}
/**
* Encrypt a string with XSalsa20. Doesn't provide integrity.
*
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20_xor($message, $nonce, $key)
{
return self::xorStrings($message, self::xsalsa20(self::strlen($message), $nonce, $key));
}
}
/**
* Class ParagonIE_Sodium_Core32_XSalsa20
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,180 @@
<?php
if (\class_exists('SplFixedArray')) {
return;
}
/**
* The SplFixedArray class provides the main functionalities of array. The
* main differences between a SplFixedArray and a normal PHP array is that
* the SplFixedArray is of fixed length and allows only integers within
* the range as indexes. The advantage is that it allows a faster array
* implementation.
*/
class SplFixedArray implements \Iterator, \ArrayAccess, \Countable
{
/** @var array<int, mixed> */
private $internalArray = array();
/** @var int $size */
private $size = 0;
/**
* SplFixedArray constructor.
* @param int $size
*/
public function __construct($size = 0)
{
$this->size = $size;
$this->internalArray = array();
}
/**
* @return int
*/
public function count()
{
return \count($this->internalArray);
}
/**
* @return array
*/
public function toArray()
{
\ksort($this->internalArray);
return (array) $this->internalArray;
}
/**
* @param array $array
* @param bool $save_indexes
* @return SplFixedArray
* @psalm-suppress MixedAssignment
*/
public static function fromArray(array $array, $save_indexes = \true)
{
$self = new \SplFixedArray(\count($array));
if ($save_indexes) {
foreach ($array as $key => $value) {
$self[(int) $key] = $value;
}
} else {
$i = 0;
foreach (\array_values($array) as $value) {
$self[$i] = $value;
$i++;
}
}
return $self;
}
/**
* @return int
*/
public function getSize()
{
return $this->size;
}
/**
* @param int $size
* @return bool
*/
public function setSize($size)
{
$this->size = $size;
return \true;
}
/**
* @param string|int $index
* @return bool
*/
public function offsetExists($index)
{
return \array_key_exists((int) $index, $this->internalArray);
}
/**
* @param string|int $index
* @return mixed
*/
public function offsetGet($index)
{
/** @psalm-suppress MixedReturnStatement */
return $this->internalArray[(int) $index];
}
/**
* @param string|int $index
* @param mixed $newval
* @psalm-suppress MixedAssignment
*/
public function offsetSet($index, $newval)
{
$this->internalArray[(int) $index] = $newval;
}
/**
* @param string|int $index
*/
public function offsetUnset($index)
{
unset($this->internalArray[(int) $index]);
}
/**
* Rewind iterator back to the start
* @link https://php.net/manual/en/splfixedarray.rewind.php
* @return void
* @since 5.3.0
*/
public function rewind()
{
\reset($this->internalArray);
}
/**
* Return current array entry
* @link https://php.net/manual/en/splfixedarray.current.php
* @return mixed The current element value.
* @since 5.3.0
*/
public function current()
{
/** @psalm-suppress MixedReturnStatement */
return \current($this->internalArray);
}
/**
* Return current array index
* @return int The current array index.
*/
public function key()
{
return \key($this->internalArray);
}
/**
* @return void
*/
public function next()
{
\next($this->internalArray);
}
/**
* Check whether the array contains more elements
* @link https://php.net/manual/en/splfixedarray.valid.php
* @return bool true if the array contains any more elements, false otherwise.
*/
public function valid()
{
if (empty($this->internalArray)) {
return \false;
}
$result = \next($this->internalArray) !== \false;
\prev($this->internalArray);
return $result;
}
/**
* Do nothing.
*/
public function __wakeup()
{
// NOP
}
}
/**
* The SplFixedArray class provides the main functionalities of array. The
* main differences between a SplFixedArray and a normal PHP array is that
* the SplFixedArray is of fixed length and allows only integers within
* the range as indexes. The advantage is that it allows a faster array
* implementation.
*/

View File

@@ -0,0 +1,15 @@
<?php
if (!\class_exists('SodiumException', \false)) {
/**
* Class SodiumException
*/
class SodiumException extends \Exception
{
}
/**
* Class SodiumException
*/
}