1<?php 2 3/** 4 * Pure-PHP implementation of ChaCha20. 5 * 6 * PHP version 5 7 * 8 * @category Crypt 9 * @package ChaCha20 10 * @author Jim Wigginton <terrafrost@php.net> 11 * @copyright 2019 Jim Wigginton 12 * @license http://www.opensource.org/licenses/mit-license.html MIT License 13 * @link http://phpseclib.sourceforge.net 14 */ 15 16namespace phpseclib3\Crypt; 17 18use phpseclib3\Exception\BadDecryptionException; 19use phpseclib3\Exception\InsufficientSetupException; 20 21/** 22 * Pure-PHP implementation of ChaCha20. 23 * 24 * @package ChaCha20 25 * @author Jim Wigginton <terrafrost@php.net> 26 * @access public 27 */ 28class ChaCha20 extends Salsa20 29{ 30 /** 31 * The OpenSSL specific name of the cipher 32 * 33 * @var string 34 */ 35 protected $cipher_name_openssl = 'chacha20'; 36 37 /** 38 * Test for engine validity 39 * 40 * This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine() 41 * 42 * @see \phpseclib3\Crypt\Common\SymmetricKey::__construct() 43 * @param int $engine 44 * @access protected 45 * @return bool 46 */ 47 protected function isValidEngineHelper($engine) 48 { 49 switch ($engine) { 50 case self::ENGINE_LIBSODIUM: 51 // PHP 7.2.0 (30 Nov 2017) added support for libsodium 52 53 // we could probably make it so that if $this->counter == 0 then the first block would be done with either OpenSSL 54 // or PHP and then subsequent blocks would then be done with libsodium but idk - it's not a high priority atm 55 56 // we could also make it so that if $this->counter == 0 and $this->continuousBuffer then do the first string 57 // with libsodium and subsequent strings with openssl or pure-PHP but again not a high priority 58 return function_exists('sodium_crypto_aead_chacha20poly1305_ietf_encrypt') && 59 $this->key_length == 32 && 60 (($this->usePoly1305 && !isset($this->poly1305Key) && $this->counter == 0) || $this->counter == 1) && 61 !$this->continuousBuffer; 62 case self::ENGINE_OPENSSL: 63 // OpenSSL 1.1.0 (released 25 Aug 2016) added support for chacha20. 64 // PHP didn't support OpenSSL 1.1.0 until 7.0.19 (11 May 2017) 65 66 // if you attempt to provide openssl with a 128 bit key (as opposed to a 256 bit key) openssl will null 67 // pad the key to 256 bits and still use the expansion constant for 256-bit keys. the fact that 68 // openssl treats the IV as both the counter and nonce, however, let's us use openssl in continuous mode 69 // whereas libsodium does not 70 if ($this->key_length != 32) { 71 return false; 72 } 73 } 74 75 return parent::isValidEngineHelper($engine); 76 } 77 78 /** 79 * Encrypts a message. 80 * 81 * @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt() 82 * @see self::crypt() 83 * @param string $plaintext 84 * @return string $ciphertext 85 */ 86 public function encrypt($plaintext) 87 { 88 $this->setup(); 89 90 if ($this->engine == self::ENGINE_LIBSODIUM) { 91 return $this->encrypt_with_libsodium($plaintext); 92 } 93 94 return parent::encrypt($plaintext); 95 } 96 97 /** 98 * Decrypts a message. 99 * 100 * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). 101 * At least if the continuous buffer is disabled. 102 * 103 * @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt() 104 * @see self::crypt() 105 * @param string $ciphertext 106 * @return string $plaintext 107 */ 108 public function decrypt($ciphertext) 109 { 110 $this->setup(); 111 112 if ($this->engine == self::ENGINE_LIBSODIUM) { 113 return $this->decrypt_with_libsodium($ciphertext); 114 } 115 116 return parent::decrypt($ciphertext); 117 } 118 119 /** 120 * Encrypts a message with libsodium 121 * 122 * @see self::encrypt() 123 * @param string $plaintext 124 * @return string $text 125 */ 126 private function encrypt_with_libsodium($plaintext) 127 { 128 $params = [$plaintext, $this->aad, $this->nonce, $this->key]; 129 $ciphertext = strlen($this->nonce) == 8 ? 130 sodium_crypto_aead_chacha20poly1305_encrypt(...$params) : 131 sodium_crypto_aead_chacha20poly1305_ietf_encrypt(...$params); 132 if (!$this->usePoly1305) { 133 return substr($ciphertext, 0, strlen($plaintext)); 134 } 135 136 $newciphertext = substr($ciphertext, 0, strlen($plaintext)); 137 138 $this->newtag = $this->usingGeneratedPoly1305Key && strlen($this->nonce) == 12 ? 139 substr($ciphertext, strlen($plaintext)) : 140 $this->poly1305($newciphertext); 141 142 return $newciphertext; 143 } 144 145 /** 146 * Decrypts a message with libsodium 147 * 148 * @see self::decrypt() 149 * @param string $ciphertext 150 * @return string $text 151 */ 152 private function decrypt_with_libsodium($ciphertext) 153 { 154 $params = [$ciphertext, $this->aad, $this->nonce, $this->key]; 155 156 if (isset($this->poly1305Key)) { 157 if ($this->oldtag === false) { 158 throw new InsufficientSetupException('Authentication Tag has not been set'); 159 } 160 if ($this->usingGeneratedPoly1305Key && strlen($this->nonce) == 12) { 161 $plaintext = sodium_crypto_aead_chacha20poly1305_ietf_decrypt(...$params); 162 $this->oldtag = false; 163 if ($plaintext === false) { 164 throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match'); 165 } 166 return $plaintext; 167 } 168 $newtag = $this->poly1305($ciphertext); 169 if ($this->oldtag != substr($newtag, 0, strlen($this->oldtag))) { 170 $this->oldtag = false; 171 throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match'); 172 } 173 $this->oldtag = false; 174 } 175 176 $plaintext = strlen($this->nonce) == 8 ? 177 sodium_crypto_aead_chacha20poly1305_encrypt(...$params) : 178 sodium_crypto_aead_chacha20poly1305_ietf_encrypt(...$params); 179 180 return substr($plaintext, 0, strlen($ciphertext)); 181 } 182 183 /** 184 * Sets the nonce. 185 * 186 * @param string $nonce 187 */ 188 public function setNonce($nonce) 189 { 190 if (!is_string($nonce)) { 191 throw new \UnexpectedValueException('The nonce should be a string'); 192 } 193 194 /* 195 from https://tools.ietf.org/html/rfc7539#page-7 196 197 "Note also that the original ChaCha had a 64-bit nonce and 64-bit 198 block count. We have modified this here to be more consistent with 199 recommendations in Section 3.2 of [RFC5116]." 200 */ 201 switch (strlen($nonce)) { 202 case 8: // 64 bits 203 case 12: // 96 bits 204 break; 205 default: 206 throw new \LengthException('Nonce of size ' . strlen($nonce) . ' not supported by this algorithm. Only 64-bit nonces or 96-bit nonces are supported'); 207 } 208 209 $this->nonce = $nonce; 210 $this->changed = true; 211 $this->setEngine(); 212 } 213 214 /** 215 * Setup the self::ENGINE_INTERNAL $engine 216 * 217 * (re)init, if necessary, the internal cipher $engine 218 * 219 * _setup() will be called each time if $changed === true 220 * typically this happens when using one or more of following public methods: 221 * 222 * - setKey() 223 * 224 * - setNonce() 225 * 226 * - First run of encrypt() / decrypt() with no init-settings 227 * 228 * @see self::setKey() 229 * @see self::setNonce() 230 * @see self::disableContinuousBuffer() 231 */ 232 protected function setup() 233 { 234 if (!$this->changed) { 235 return; 236 } 237 238 $this->enbuffer = $this->debuffer = ['ciphertext' => '', 'counter' => $this->counter]; 239 240 $this->changed = $this->nonIVChanged = false; 241 242 if ($this->nonce === false) { 243 throw new InsufficientSetupException('No nonce has been defined'); 244 } 245 246 if ($this->key === false) { 247 throw new InsufficientSetupException('No key has been defined'); 248 } 249 250 if ($this->usePoly1305 && !isset($this->poly1305Key)) { 251 $this->usingGeneratedPoly1305Key = true; 252 if ($this->engine == self::ENGINE_LIBSODIUM) { 253 return; 254 } 255 $this->createPoly1305Key(); 256 } 257 258 $key = $this->key; 259 if (strlen($key) == 16) { 260 $constant = 'expand 16-byte k'; 261 $key .= $key; 262 } else { 263 $constant = 'expand 32-byte k'; 264 } 265 266 $this->p1 = $constant . $key; 267 $this->p2 = $this->nonce; 268 if (strlen($this->nonce) == 8) { 269 $this->p2 = "\0\0\0\0" . $this->p2; 270 } 271 } 272 273 /** 274 * The quarterround function 275 * 276 * @param int $a 277 * @param int $b 278 * @param int $c 279 * @param int $d 280 */ 281 protected static function quarterRound(&$a, &$b, &$c, &$d) 282 { 283 // in https://datatracker.ietf.org/doc/html/rfc7539#section-2.1 the addition, 284 // xor'ing and rotation are all on the same line so i'm keeping it on the same 285 // line here as well 286 // @codingStandardsIgnoreStart 287 $a+= $b; $d = self::leftRotate($d ^ $a, 16); 288 $c+= $d; $b = self::leftRotate($b ^ $c, 12); 289 $a+= $b; $d = self::leftRotate($d ^ $a, 8); 290 $c+= $d; $b = self::leftRotate($b ^ $c, 7); 291 // @codingStandardsIgnoreEnd 292 } 293 294 /** 295 * The doubleround function 296 * 297 * @param int $x0 (by reference) 298 * @param int $x1 (by reference) 299 * @param int $x2 (by reference) 300 * @param int $x3 (by reference) 301 * @param int $x4 (by reference) 302 * @param int $x5 (by reference) 303 * @param int $x6 (by reference) 304 * @param int $x7 (by reference) 305 * @param int $x8 (by reference) 306 * @param int $x9 (by reference) 307 * @param int $x10 (by reference) 308 * @param int $x11 (by reference) 309 * @param int $x12 (by reference) 310 * @param int $x13 (by reference) 311 * @param int $x14 (by reference) 312 * @param int $x15 (by reference) 313 */ 314 protected static function doubleRound(&$x0, &$x1, &$x2, &$x3, &$x4, &$x5, &$x6, &$x7, &$x8, &$x9, &$x10, &$x11, &$x12, &$x13, &$x14, &$x15) 315 { 316 // columnRound 317 static::quarterRound($x0, $x4, $x8, $x12); 318 static::quarterRound($x1, $x5, $x9, $x13); 319 static::quarterRound($x2, $x6, $x10, $x14); 320 static::quarterRound($x3, $x7, $x11, $x15); 321 // rowRound 322 static::quarterRound($x0, $x5, $x10, $x15); 323 static::quarterRound($x1, $x6, $x11, $x12); 324 static::quarterRound($x2, $x7, $x8, $x13); 325 static::quarterRound($x3, $x4, $x9, $x14); 326 } 327 328 /** 329 * The Salsa20 hash function function 330 * 331 * On my laptop this loop unrolled / function dereferenced version of parent::salsa20 encrypts 1mb of text in 332 * 0.65s vs the 0.85s that it takes with the parent method. 333 * 334 * If we were free to assume that the host OS would always be 64-bits then the if condition in leftRotate could 335 * be eliminated and we could knock this done to 0.60s. 336 * 337 * For comparison purposes, RC4 takes 0.16s and AES in CTR mode with the Eval engine takes 0.48s. 338 * AES in CTR mode with the PHP engine takes 1.19s. Salsa20 / ChaCha20 do not benefit as much from the Eval 339 * approach due to the fact that there are a lot less variables to de-reference, fewer loops to unroll, etc 340 * 341 * @param string $x 342 */ 343 protected static function salsa20($x) 344 { 345 list(, $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15) = unpack('V*', $x); 346 $z0 = $x0; 347 $z1 = $x1; 348 $z2 = $x2; 349 $z3 = $x3; 350 $z4 = $x4; 351 $z5 = $x5; 352 $z6 = $x6; 353 $z7 = $x7; 354 $z8 = $x8; 355 $z9 = $x9; 356 $z10 = $x10; 357 $z11 = $x11; 358 $z12 = $x12; 359 $z13 = $x13; 360 $z14 = $x14; 361 $z15 = $x15; 362 363 // @codingStandardsIgnoreStart 364 // columnRound 365 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 366 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 367 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 368 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 369 370 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 371 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 372 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 373 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 374 375 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 376 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 377 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 378 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 379 380 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 381 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 382 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 383 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 384 385 // rowRound 386 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 387 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 388 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 389 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 390 391 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 392 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 393 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 394 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 395 396 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 397 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 398 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 399 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 400 401 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 402 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 403 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 404 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 405 406 // columnRound 407 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 408 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 409 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 410 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 411 412 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 413 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 414 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 415 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 416 417 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 418 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 419 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 420 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 421 422 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 423 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 424 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 425 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 426 427 // rowRound 428 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 429 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 430 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 431 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 432 433 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 434 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 435 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 436 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 437 438 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 439 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 440 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 441 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 442 443 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 444 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 445 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 446 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 447 448 // columnRound 449 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 450 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 451 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 452 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 453 454 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 455 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 456 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 457 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 458 459 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 460 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 461 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 462 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 463 464 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 465 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 466 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 467 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 468 469 // rowRound 470 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 471 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 472 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 473 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 474 475 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 476 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 477 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 478 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 479 480 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 481 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 482 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 483 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 484 485 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 486 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 487 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 488 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 489 490 // columnRound 491 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 492 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 493 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 494 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 495 496 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 497 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 498 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 499 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 500 501 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 502 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 503 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 504 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 505 506 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 507 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 508 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 509 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 510 511 // rowRound 512 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 513 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 514 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 515 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 516 517 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 518 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 519 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 520 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 521 522 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 523 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 524 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 525 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 526 527 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 528 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 529 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 530 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 531 532 // columnRound 533 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 534 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 535 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 536 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 537 538 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 539 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 540 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 541 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 542 543 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 544 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 545 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 546 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 547 548 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 549 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 550 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 551 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 552 553 // rowRound 554 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 555 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 556 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 557 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 558 559 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 560 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 561 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 562 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 563 564 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 565 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 566 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 567 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 568 569 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 570 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 571 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 572 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 573 574 // columnRound 575 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 576 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 577 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 578 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 579 580 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 581 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 582 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 583 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 584 585 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 586 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 587 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 588 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 589 590 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 591 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 592 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 593 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 594 595 // rowRound 596 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 597 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 598 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 599 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 600 601 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 602 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 603 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 604 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 605 606 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 607 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 608 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 609 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 610 611 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 612 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 613 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 614 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 615 616 // columnRound 617 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 618 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 619 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 620 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 621 622 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 623 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 624 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 625 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 626 627 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 628 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 629 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 630 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 631 632 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 633 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 634 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 635 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 636 637 // rowRound 638 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 639 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 640 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 641 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 642 643 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 644 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 645 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 646 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 647 648 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 649 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 650 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 651 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 652 653 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 654 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 655 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 656 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 657 658 // columnRound 659 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 660 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 661 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 662 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 663 664 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 665 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 666 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 667 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 668 669 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 670 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 671 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 672 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 673 674 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 675 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 676 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 677 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 678 679 // rowRound 680 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 681 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 682 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 683 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 684 685 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 686 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 687 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 688 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 689 690 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 691 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 692 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 693 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 694 695 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 696 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 697 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 698 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 699 700 // columnRound 701 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 702 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 703 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 704 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 705 706 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 707 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 708 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 709 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 710 711 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 712 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 713 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 714 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 715 716 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 717 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 718 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 719 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 720 721 // rowRound 722 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 723 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 724 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 725 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 726 727 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 728 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 729 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 730 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 731 732 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 733 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 734 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 735 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 736 737 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 738 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 739 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 740 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 741 742 // columnRound 743 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 16); 744 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 12); 745 $x0+= $x4; $x12 = self::leftRotate($x12 ^ $x0, 8); 746 $x8+= $x12; $x4 = self::leftRotate($x4 ^ $x8, 7); 747 748 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 16); 749 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 12); 750 $x1+= $x5; $x13 = self::leftRotate($x13 ^ $x1, 8); 751 $x9+= $x13; $x5 = self::leftRotate($x5 ^ $x9, 7); 752 753 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 16); 754 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 12); 755 $x2+= $x6; $x14 = self::leftRotate($x14 ^ $x2, 8); 756 $x10+= $x14; $x6 = self::leftRotate($x6 ^ $x10, 7); 757 758 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 16); 759 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 12); 760 $x3+= $x7; $x15 = self::leftRotate($x15 ^ $x3, 8); 761 $x11+= $x15; $x7 = self::leftRotate($x7 ^ $x11, 7); 762 763 // rowRound 764 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 16); 765 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 12); 766 $x0+= $x5; $x15 = self::leftRotate($x15 ^ $x0, 8); 767 $x10+= $x15; $x5 = self::leftRotate($x5 ^ $x10, 7); 768 769 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 16); 770 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 12); 771 $x1+= $x6; $x12 = self::leftRotate($x12 ^ $x1, 8); 772 $x11+= $x12; $x6 = self::leftRotate($x6 ^ $x11, 7); 773 774 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 16); 775 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 12); 776 $x2+= $x7; $x13 = self::leftRotate($x13 ^ $x2, 8); 777 $x8+= $x13; $x7 = self::leftRotate($x7 ^ $x8, 7); 778 779 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 16); 780 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 12); 781 $x3+= $x4; $x14 = self::leftRotate($x14 ^ $x3, 8); 782 $x9+= $x14; $x4 = self::leftRotate($x4 ^ $x9, 7); 783 // @codingStandardsIgnoreEnd 784 785 $x0 += $z0; 786 $x1 += $z1; 787 $x2 += $z2; 788 $x3 += $z3; 789 $x4 += $z4; 790 $x5 += $z5; 791 $x6 += $z6; 792 $x7 += $z7; 793 $x8 += $z8; 794 $x9 += $z9; 795 $x10 += $z10; 796 $x11 += $z11; 797 $x12 += $z12; 798 $x13 += $z13; 799 $x14 += $z14; 800 $x15 += $z15; 801 802 return pack('V*', $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15); 803 } 804} 805