| 
<?phpdeclare(strict_types=1);
 
 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\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
 }
 if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
 define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
 }
 
 class ParagonIE_Sodium_Core_AEGIS_State128L
 {
 /** @var array<int, string> $state */
 protected array $state;
 
 public function __construct()
 {
 $this->state = array_fill(0, 8, '');
 }
 
 /**
 * @internal Only use this for unit tests!
 * @return string[]
 */
 public function getState(): array
 {
 return array_values($this->state);
 }
 
 /**
 * @param array $input
 * @return self
 * @throws SodiumException
 *
 * @internal Only for unit tests
 */
 public static function initForUnitTests(array $input): self
 {
 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(
 #[SensitiveParameter]
 string $key,
 string $nonce
 ): self {
 $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 static
 *
 * @throws SodiumException
 */
 public function absorb(string $ai): static
 {
 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(string $ci): string
 {
 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
 *
 * @throws SodiumException
 */
 public function decPartial(string $cn): string
 {
 $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, "\0");
 $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, "\0");
 $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(
 #[SensitiveParameter]
 string $xi
 ): string {
 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(int $ad_len_bits, int $msg_len_bits): string
 {
 $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 static
 */
 public function update(string $m0, string $m1): static
 {
 /*
 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;
 }
 }
 |