diff --git a/phpseclib/Crypt/AES.php b/phpseclib/Crypt/AES.php index aac0fdd0..b195e9d6 100644 --- a/phpseclib/Crypt/AES.php +++ b/phpseclib/Crypt/AES.php @@ -56,7 +56,7 @@ * @author Jim Wigginton * @copyright MMVIII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: AES.php,v 1.5 2009-11-23 19:06:06 terrafrost Exp $ + * @version $Id: AES.php,v 1.6 2010-01-04 07:59:01 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -332,12 +332,19 @@ class Crypt_AES extends Crypt_Rijndael { { $state = unpack('N*word', $in); + $Nr = $this->Nr; + $w = $this->w; + $t0 = $this->t0; + $t1 = $this->t1; + $t2 = $this->t2; + $t3 = $this->t3; + // addRoundKey and reindex $state $state = array( - $state['word1'] ^ $this->w[0][0], - $state['word2'] ^ $this->w[0][1], - $state['word3'] ^ $this->w[0][2], - $state['word4'] ^ $this->w[0][3] + $state['word1'] ^ $w[0][0], + $state['word2'] ^ $w[0][1], + $state['word3'] ^ $w[0][2], + $state['word4'] ^ $w[0][3] ); // shiftRows + subWord + mixColumns + addRoundKey @@ -345,10 +352,10 @@ class Crypt_AES extends Crypt_Rijndael { // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it. for ($round = 1; $round < $this->Nr; $round++) { $state = array( - $this->t0[$state[0] & 0xFF000000] ^ $this->t1[$state[1] & 0x00FF0000] ^ $this->t2[$state[2] & 0x0000FF00] ^ $this->t3[$state[3] & 0x000000FF] ^ $this->w[$round][0], - $this->t0[$state[1] & 0xFF000000] ^ $this->t1[$state[2] & 0x00FF0000] ^ $this->t2[$state[3] & 0x0000FF00] ^ $this->t3[$state[0] & 0x000000FF] ^ $this->w[$round][1], - $this->t0[$state[2] & 0xFF000000] ^ $this->t1[$state[3] & 0x00FF0000] ^ $this->t2[$state[0] & 0x0000FF00] ^ $this->t3[$state[1] & 0x000000FF] ^ $this->w[$round][2], - $this->t0[$state[3] & 0xFF000000] ^ $this->t1[$state[0] & 0x00FF0000] ^ $this->t2[$state[1] & 0x0000FF00] ^ $this->t3[$state[2] & 0x000000FF] ^ $this->w[$round][3] + $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0], + $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1], + $t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2], + $t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3] ); } @@ -386,31 +393,38 @@ class Crypt_AES extends Crypt_Rijndael { { $state = unpack('N*word', $in); + $Nr = $this->Nr; + $dw = $this->dw; + $dt0 = $this->dt0; + $dt1 = $this->dt1; + $dt2 = $this->dt2; + $dt3 = $this->dt3; + // addRoundKey and reindex $state $state = array( - $state['word1'] ^ $this->dw[$this->Nr][0], - $state['word2'] ^ $this->dw[$this->Nr][1], - $state['word3'] ^ $this->dw[$this->Nr][2], - $state['word4'] ^ $this->dw[$this->Nr][3] + $state['word1'] ^ $dw[$this->Nr][0], + $state['word2'] ^ $dw[$this->Nr][1], + $state['word3'] ^ $dw[$this->Nr][2], + $state['word4'] ^ $dw[$this->Nr][3] ); // invShiftRows + invSubBytes + invMixColumns + addRoundKey for ($round = $this->Nr - 1; $round > 0; $round--) { $state = array( - $this->dt0[$state[0] & 0xFF000000] ^ $this->dt1[$state[3] & 0x00FF0000] ^ $this->dt2[$state[2] & 0x0000FF00] ^ $this->dt3[$state[1] & 0x000000FF] ^ $this->dw[$round][0], - $this->dt0[$state[1] & 0xFF000000] ^ $this->dt1[$state[0] & 0x00FF0000] ^ $this->dt2[$state[3] & 0x0000FF00] ^ $this->dt3[$state[2] & 0x000000FF] ^ $this->dw[$round][1], - $this->dt0[$state[2] & 0xFF000000] ^ $this->dt1[$state[1] & 0x00FF0000] ^ $this->dt2[$state[0] & 0x0000FF00] ^ $this->dt3[$state[3] & 0x000000FF] ^ $this->dw[$round][2], - $this->dt0[$state[3] & 0xFF000000] ^ $this->dt1[$state[2] & 0x00FF0000] ^ $this->dt2[$state[1] & 0x0000FF00] ^ $this->dt3[$state[0] & 0x000000FF] ^ $this->dw[$round][3] + $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0], + $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1], + $dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2], + $dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3] ); } // invShiftRows + invSubWord + addRoundKey $state = array( - $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $this->dw[0][0], - $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $this->dw[0][1], - $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $this->dw[0][2], - $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $this->dw[0][3] + $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0], + $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1], + $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2], + $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3] ); return pack('N*', $state[0], $state[1], $state[2], $state[3]); diff --git a/phpseclib/Crypt/DES.php b/phpseclib/Crypt/DES.php index c99924a3..10616f2b 100644 --- a/phpseclib/Crypt/DES.php +++ b/phpseclib/Crypt/DES.php @@ -53,7 +53,7 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: DES.php,v 1.10 2009-12-06 07:26:52 terrafrost Exp $ + * @version $Id: DES.php,v 1.11 2010-01-04 07:59:01 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -613,6 +613,8 @@ class Crypt_DES { ) ); + $keys = $this->keys; + $temp = unpack('Na/Nb', $block); $block = array($temp['a'], $temp['b']); @@ -667,14 +669,14 @@ class Crypt_DES { for ($i = 0; $i < 16; $i++) { // start of "the Feistel (F) function" - see the following URL: // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png - $temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $this->keys[$mode][$i][0]]) << 28) - | (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $this->keys[$mode][$i][1]]) << 24) - | (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $this->keys[$mode][$i][2]]) << 20) - | (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $this->keys[$mode][$i][3]]) << 16) - | (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $this->keys[$mode][$i][4]]) << 12) - | (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $this->keys[$mode][$i][5]]) << 8) - | (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $this->keys[$mode][$i][6]]) << 4) - | ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $this->keys[$mode][$i][7]]); + $temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28) + | (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24) + | (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20) + | (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16) + | (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12) + | (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $keys[$mode][$i][5]]) << 8) + | (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $keys[$mode][$i][6]]) << 4) + | ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]); $msb = ($temp >> 31) & 1; $temp &= 0x7FFFFFFF; diff --git a/phpseclib/Crypt/Rijndael.php b/phpseclib/Crypt/Rijndael.php index 5ca59e1f..2caf83da 100644 --- a/phpseclib/Crypt/Rijndael.php +++ b/phpseclib/Crypt/Rijndael.php @@ -64,7 +64,7 @@ * @author Jim Wigginton * @copyright MMVIII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: Rijndael.php,v 1.9 2009-12-06 07:26:52 terrafrost Exp $ + * @version $Id: Rijndael.php,v 1.10 2010-01-04 07:59:01 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -369,10 +369,20 @@ class Crypt_Rijndael { $this->mode = CRYPT_RIJNDAEL_MODE_CBC; } + $t3 = &$this->t3; + $t2 = &$this->t2; + $t1 = &$this->t1; + $t0 = &$this->t0; + + $dt3 = &$this->dt3; + $dt2 = &$this->dt2; + $dt1 = &$this->dt1; + $dt0 = &$this->dt0; + // according to (section 5.2.1), // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so // those are the names we'll use. - $this->t3 = array( + $t3 = array( 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, @@ -407,7 +417,7 @@ class Crypt_Rijndael { 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C ); - $this->dt3 = array( + $dt3 = array( 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, @@ -443,13 +453,13 @@ class Crypt_Rijndael { ); for ($i = 0; $i < 256; $i++) { - $this->t2[$i << 8] = (($this->t3[$i] << 8) & 0xFFFFFF00) | (($this->t3[$i] >> 24) & 0x000000FF); - $this->t1[$i << 16] = (($this->t3[$i] << 16) & 0xFFFF0000) | (($this->t3[$i] >> 16) & 0x0000FFFF); - $this->t0[$i << 24] = (($this->t3[$i] << 24) & 0xFF000000) | (($this->t3[$i] >> 8) & 0x00FFFFFF); + $t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF); + $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF); + $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF); - $this->dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($this->dt3[$i] >> 24) & 0x000000FF); - $this->dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($this->dt3[$i] >> 16) & 0x0000FFFF); - $this->dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($this->dt3[$i] >> 8) & 0x00FFFFFF); + $dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF); + $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF); + $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF); } } @@ -629,9 +639,19 @@ class Crypt_Rijndael { $state = array(); $words = unpack('N*word', $in); + $w = $this->w; + $t0 = $this->t0; + $t1 = $this->t1; + $t2 = $this->t2; + $t3 = $this->t3; + $Nb = $this->Nb; + $Nr = $this->Nr; + $c = $this->c; + // addRoundKey + $i = 0; foreach ($words as $word) { - $state[] = $word ^ $this->w[0][count($state)]; + $state[] = $word ^ $w[0][$i++]; } // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - @@ -643,49 +663,49 @@ class Crypt_Rijndael { // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf $temp = array(); - for ($round = 1; $round < $this->Nr; $round++) { - $i = 0; // $this->c[0] == 0 - $j = $this->c[1]; - $k = $this->c[2]; - $l = $this->c[3]; + for ($round = 1; $round < $Nr; $round++) { + $i = 0; // $c[0] == 0 + $j = $c[1]; + $k = $c[2]; + $l = $c[3]; while ($i < $this->Nb) { - $temp[$i] = $this->t0[$state[$i] & 0xFF000000] ^ - $this->t1[$state[$j] & 0x00FF0000] ^ - $this->t2[$state[$k] & 0x0000FF00] ^ - $this->t3[$state[$l] & 0x000000FF] ^ - $this->w[$round][$i]; + $temp[$i] = $t0[$state[$i] & 0xFF000000] ^ + $t1[$state[$j] & 0x00FF0000] ^ + $t2[$state[$k] & 0x0000FF00] ^ + $t3[$state[$l] & 0x000000FF] ^ + $w[$round][$i]; $i++; - $j = ($j + 1) % $this->Nb; - $k = ($k + 1) % $this->Nb; - $l = ($l + 1) % $this->Nb; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; } - for ($i = 0; $i < $this->Nb; $i++) { + for ($i = 0; $i < $Nb; $i++) { $state[$i] = $temp[$i]; } } // subWord - for ($i = 0; $i < $this->Nb; $i++) { + for ($i = 0; $i < $Nb; $i++) { $state[$i] = $this->_subWord($state[$i]); } // shiftRows + addRoundKey - $i = 0; // $this->c[0] == 0 - $j = $this->c[1]; - $k = $this->c[2]; - $l = $this->c[3]; + $i = 0; // $c[0] == 0 + $j = $c[1]; + $k = $c[2]; + $l = $c[3]; while ($i < $this->Nb) { $temp[$i] = ($state[$i] & 0xFF000000) ^ ($state[$j] & 0x00FF0000) ^ ($state[$k] & 0x0000FF00) ^ ($state[$l] & 0x000000FF) ^ - $this->w[$this->Nr][$i]; + $w[$Nr][$i]; $i++; - $j = ($j + 1) % $this->Nb; - $k = ($k + 1) % $this->Nb; - $l = ($l + 1) % $this->Nb; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; } $state = $temp; @@ -706,51 +726,62 @@ class Crypt_Rijndael { $state = array(); $words = unpack('N*word', $in); + $num_states = count($state); + $dw = $this->dw; + $dt0 = $this->dt0; + $dt1 = $this->dt1; + $dt2 = $this->dt2; + $dt3 = $this->dt3; + $Nb = $this->Nb; + $Nr = $this->Nr; + $c = $this->c; + // addRoundKey + $i = 0; foreach ($words as $word) { - $state[] = $word ^ $this->dw[0][count($state)]; + $state[] = $word ^ $dw[$Nr][$i++]; } $temp = array(); - for ($round = $this->Nr - 1; $round > 0; $round--) { - $i = 0; // $this->c[0] == 0 - $j = $this->Nb - $this->c[1]; - $k = $this->Nb - $this->c[2]; - $l = $this->Nb - $this->c[3]; + for ($round = $Nr - 1; $round > 0; $round--) { + $i = 0; // $c[0] == 0 + $j = $Nb - $c[1]; + $k = $Nb - $c[2]; + $l = $Nb - $c[3]; - while ($i < $this->Nb) { - $temp[$i] = $this->dt0[$state[$i] & 0xFF000000] ^ - $this->dt1[$state[$j] & 0x00FF0000] ^ - $this->dt2[$state[$k] & 0x0000FF00] ^ - $this->dt3[$state[$l] & 0x000000FF] ^ - $this->dw[$round][$i]; + while ($i < $Nb) { + $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^ + $dt1[$state[$j] & 0x00FF0000] ^ + $dt2[$state[$k] & 0x0000FF00] ^ + $dt3[$state[$l] & 0x000000FF] ^ + $dw[$round][$i]; $i++; - $j = ($j + 1) % $this->Nb; - $k = ($k + 1) % $this->Nb; - $l = ($l + 1) % $this->Nb; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; } - for ($i = 0; $i < $this->Nb; $i++) { + for ($i = 0; $i < $Nb; $i++) { $state[$i] = $temp[$i]; } } // invShiftRows + invSubWord + addRoundKey - $i = 0; // $this->c[0] == 0 - $j = $this->Nb - $this->c[1]; - $k = $this->Nb - $this->c[2]; - $l = $this->Nb - $this->c[3]; + $i = 0; // $c[0] == 0 + $j = $Nb - $c[1]; + $k = $Nb - $c[2]; + $l = $Nb - $c[3]; - while ($i < $this->Nb) { - $temp[$i] = $this->dw[0][$i] ^ + while ($i < $Nb) { + $temp[$i] = $dw[0][$i] ^ $this->_invSubWord(($state[$i] & 0xFF000000) | ($state[$j] & 0x00FF0000) | ($state[$k] & 0x0000FF00) | ($state[$l] & 0x000000FF)); $i++; - $j = ($j + 1) % $this->Nb; - $k = ($k + 1) % $this->Nb; - $l = ($l + 1) % $this->Nb; + $j = ($j + 1) % $Nb; + $k = ($k + 1) % $Nb; + $l = ($l + 1) % $Nb; } $state = $temp; @@ -1049,6 +1080,7 @@ class Crypt_Rijndael { $length = ord($text[strlen($text) - 1]); if (!$length || $length > $this->block_size) { +echo "RETURNING FALSE ($length)\r\n"; return false; } diff --git a/phpseclib/Crypt/TripleDES.php b/phpseclib/Crypt/TripleDES.php index 44fea10f..00ce6a27 100644 --- a/phpseclib/Crypt/TripleDES.php +++ b/phpseclib/Crypt/TripleDES.php @@ -47,7 +47,7 @@ * @author Jim Wigginton * @copyright MMVII Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: TripleDES.php,v 1.10 2009-12-06 07:26:52 terrafrost Exp $ + * @version $Id: TripleDES.php,v 1.11 2010-01-04 07:59:01 terrafrost Exp $ * @link http://phpseclib.sourceforge.net */ @@ -348,14 +348,16 @@ class Crypt_TripleDES { // "The data is padded with "\0" to make sure the length of the data is n * blocksize." $plaintext = str_pad($plaintext, ceil(strlen($plaintext) / 8) * 8, chr(0)); + $des = $this->des; + $ciphertext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: for ($i = 0; $i < strlen($plaintext); $i+=8) { $block = substr($plaintext, $i, 8); - $block = $this->des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $this->des[1]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $this->des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); $ciphertext.= $block; } break; @@ -363,9 +365,9 @@ class Crypt_TripleDES { $xor = $this->encryptIV; for ($i = 0; $i < strlen($plaintext); $i+=8) { $block = substr($plaintext, $i, 8) ^ $xor; - $block = $this->des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $this->des[1]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $this->des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); $xor = $block; $ciphertext.= $block; } @@ -417,14 +419,16 @@ class Crypt_TripleDES { return $this->_unpad($this->des[0]->decrypt($plaintext)); } + $des = $this->des; + $plaintext = ''; switch ($this->mode) { case CRYPT_DES_MODE_ECB: for ($i = 0; $i < strlen($ciphertext); $i+=8) { $block = substr($ciphertext, $i, 8); - $block = $this->des[2]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $this->des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $this->des[0]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); $plaintext.= $block; } break; @@ -432,9 +436,9 @@ class Crypt_TripleDES { $xor = $this->decryptIV; for ($i = 0; $i < strlen($ciphertext); $i+=8) { $orig = $block = substr($ciphertext, $i, 8); - $block = $this->des[2]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $this->des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $this->des[0]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); + $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); + $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); $plaintext.= $block ^ $xor; $xor = $orig; } diff --git a/phpseclib/Math/BigInteger.php b/phpseclib/Math/BigInteger.php index 4562ac3c..9f0d5a05 100644 --- a/phpseclib/Math/BigInteger.php +++ b/phpseclib/Math/BigInteger.php @@ -72,7 +72,7 @@ * @author Jim Wigginton * @copyright MMVI Jim Wigginton * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: BigInteger.php,v 1.21 2009-12-31 06:11:07 terrafrost Exp $ + * @version $Id: BigInteger.php,v 1.22 2010-01-04 07:59:01 terrafrost Exp $ * @link http://pear.php.net/package/Math_BigInteger */ @@ -748,6 +748,7 @@ class Math_BigInteger { } $result = new Math_BigInteger(); + $result_value = &$result->value; $carry = 0; $size = max($this_size, $y_size); @@ -763,12 +764,12 @@ class Math_BigInteger { $temp = floor($sum / 0x4000000); - $result->value[] = $sum - 0x4000000 * $temp; // eg. a faster alternative to fmod($sum, 0x4000000) - $result->value[] = $temp; + $result_value[] = $sum - 0x4000000 * $temp; // eg. a faster alternative to fmod($sum, 0x4000000) + $result_value[] = $temp; } if ($carry) { - $result->value[] = (int) $carry; + $result_value[] = (int) $carry; } $result->is_negative = $this->is_negative; @@ -861,6 +862,7 @@ class Math_BigInteger { } $result = new Math_BigInteger(); + $result_value = &$result->value; $carry = 0; $size = max($this_size, $y_size); @@ -876,8 +878,8 @@ class Math_BigInteger { $temp = floor($sum / 0x4000000); - $result->value[] = $sum - 0x4000000 * $temp; - $result->value[] = $temp; + $result_value[] = $sum - 0x4000000 * $temp; + $result_value[] = $temp; } // $carry shouldn't be anything other than zero, at this point, since we already made sure that $this @@ -971,7 +973,11 @@ class Math_BigInteger { } $product = new Math_BigInteger(); - $product->value = $this->_array_repeat(0, $this_length + $x_length); + $product_value = &$product->value; + $product_value = $this->_array_repeat(0, $this_length + $x_length); + + $this_value = $this->value; + $x_value = $x->value; // the following for loop could be removed if the for loop following it // (the one with nested for loops) initially set $i to 0, but @@ -984,10 +990,10 @@ class Math_BigInteger { for ($j = 0; $j < $this_length; $j++) { // ie. $i = 0 $temp = $this->value[$j] * $x->value[0] + $carry; // $product->value[$k] == 0 $carry = floor($temp / 0x4000000); - $product->value[$j] = $temp - 0x4000000 * $carry; + $product_value[$j] = $temp - 0x4000000 * $carry; } - $product->value[$j] = $carry; + $product_value[$j] = $carry; // the above for loop is what the previous comment was talking about. the // following for loop is the "one with nested for loops" @@ -995,12 +1001,12 @@ class Math_BigInteger { $carry = 0; for ($j = 0, $k = $i; $j < $this_length; $j++, $k++) { - $temp = $product->value[$k] + $this->value[$j] * $x->value[$i] + $carry; + $temp = $product_value[$k] + $this_value[$j] * $x_value[$i] + $carry; $carry = floor($temp / 0x4000000); - $product->value[$k] = $temp - 0x4000000 * $carry; + $product_value[$k] = $temp - 0x4000000 * $carry; } - $product->value[$k] = $carry; + $product_value[$k] = $carry; } $product->is_negative = $this->is_negative != $x->is_negative; @@ -1022,21 +1028,27 @@ class Math_BigInteger { { $x = $this->copy(); - $m = min(count($x->value) >> 1, count($y->value) >> 1); + $x_value = $x->value; + $y_value = $y->value; + + $m = min(count($x_value) >> 1, count($y_value) >> 1); if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { return $x->_multiply($y); } - $x1 = new Math_BigInteger(); - $x0 = new Math_BigInteger(); - $y1 = new Math_BigInteger(); - $y0 = new Math_BigInteger(); + static $x1, $x0, $y1, $y0; + if (!isset($x1)) { + $x1 = new Math_BigInteger(); + $x0 = new Math_BigInteger(); + $y1 = new Math_BigInteger(); + $y0 = new Math_BigInteger(); + } - $x1->value = array_slice($x->value, $m); - $x0->value = array_slice($x->value, 0, $m); - $y1->value = array_slice($y->value, $m); - $y0->value = array_slice($y->value, 0, $m); + $x1->value = array_slice($x_value, $m); + $x0->value = array_slice($x_value, 0, $m); + $y1->value = array_slice($y_value, $m); + $y0->value = array_slice($y_value, 0, $m); $z2 = $x1->_karatsuba($y1); $z0 = $x0->_karatsuba($y0); @@ -1045,8 +1057,11 @@ class Math_BigInteger { $z1 = $z1->_karatsuba($y1->add($y0)); $z1 = $z1->subtract($z2->add($z0)); - $z2->value = array_merge(array_fill(0, 2 * $m, 0), $z2->value); - $z1->value = array_merge(array_fill(0, $m, 0), $z1->value); + $z1_value = &$z1->value; + $z2_value = &$z2->value; + + $z2_value = array_merge(array_fill(0, 2 * $m, 0), $z2_value); + $z1_value = array_merge(array_fill(0, $m, 0), $z1_value); $xy = $z2->add($z1); $xy = $xy->add($z0); @@ -1087,25 +1102,28 @@ class Math_BigInteger { } $square = new Math_BigInteger(); - $square->value = $this->_array_repeat(0, 2 * count($this->value)); + $square_value = &$square->value; + $square_value = $this->_array_repeat(0, 2 * count($this->value)); - for ($i = 0, $max_index = count($this->value) - 1; $i <= $max_index; $i++) { + $this_value = &$this->value; + + for ($i = 0, $max_index = count($this_value) - 1; $i <= $max_index; $i++) { $i2 = 2 * $i; - $temp = $square->value[$i2] + $this->value[$i] * $this->value[$i]; + $temp = $square_value[$i2] + $this_value[$i] * $this_value[$i]; $carry = floor($temp / 0x4000000); - $square->value[$i2] = $temp - 0x4000000 * $carry; + $square_value[$i2] = $temp - 0x4000000 * $carry; // note how we start from $i+1 instead of 0 as we do in multiplication. for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; $j++, $k++) { - $temp = $square->value[$k] + 2 * $this->value[$j] * $this->value[$i] + $carry; + $temp = $square_value[$k] + 2 * $this_value[$j] * $this_value[$i] + $carry; $carry = floor($temp / 0x4000000); - $square->value[$k] = $temp - 0x4000000 * $carry; + $square_value[$k] = $temp - 0x4000000 * $carry; } // the following line can yield values larger 2**15. at this point, PHP should switch // over to floats. - $square->value[$i + $max_index + 1] = $carry; + $square_value[$i + $max_index + 1] = $carry; } return $square; @@ -1123,17 +1141,22 @@ class Math_BigInteger { */ function _karatsubaSquare() { - $m = count($this->value) >> 1; + $value = $this->value; + + $m = count($value) >> 1; if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { return $this->_square(); } - $x1 = new Math_BigInteger(); - $x0 = new Math_BigInteger(); + static $x1, $x0; + if (!isset($x1)) { + $x1 = new Math_BigInteger(); + $x0 = new Math_BigInteger(); + } - $x1->value = array_slice($this->value, $m); - $x0->value = array_slice($this->value, 0, $m); + $x1->value = array_slice($value, $m); + $x0->value = array_slice($value, 0, $m); $z2 = $x1->_karatsubaSquare(); $z0 = $x0->_karatsubaSquare(); @@ -1142,8 +1165,11 @@ class Math_BigInteger { $z1 = $z1->_karatsubaSquare(); $z1 = $z1->subtract($z2->add($z0)); - $z2->value = array_merge(array_fill(0, 2 * $m, 0), $z2->value); - $z1->value = array_merge(array_fill(0, $m, 0), $z1->value); + $z1_value = &$z1->value; + $z2_value = &$z2->value; + + $z2_value = array_merge(array_fill(0, 2 * $m, 0), $z2_value); + $z1_value = array_merge(array_fill(0, $m, 0), $z1_value); $xx = $z2->add($z1); $xx = $xx->add($z0); @@ -1251,80 +1277,87 @@ class Math_BigInteger { } $x->_lshift($shift); $y->_lshift($shift); + $y_value = &$y->value; $x_max = count($x->value) - 1; $y_max = count($y->value) - 1; $quotient = new Math_BigInteger(); - $quotient->value = $this->_array_repeat(0, $x_max - $y_max + 1); + $quotient_value = &$quotient->value; + $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1); + + static $temp, $lhs, $rhs; + if (!isset($temp)) { + $temp = new Math_BigInteger(); + $lhs = new Math_BigInteger(); + $rhs = new Math_BigInteger(); + } + $temp_value = &$temp->value; + $rhs_value = &$rhs->value; // $temp = $y << ($x_max - $y_max-1) in base 2**26 - $temp = new Math_BigInteger(); - $temp->value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y->value); + $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value); while ( $x->compare($temp) >= 0 ) { // calculate the "common residue" - $quotient->value[$x_max - $y_max]++; + $quotient_value[$x_max - $y_max]++; $x = $x->subtract($temp); $x_max = count($x->value) - 1; } for ($i = $x_max; $i >= $y_max + 1; $i--) { - $x_value = array( - isset($x->value[$i]) ? $x->value[$i] : 0, - isset($x->value[$i - 1]) ? $x->value[$i - 1] : 0, - isset($x->value[$i - 2]) ? $x->value[$i - 2] : 0 + $x_value = &$x->value; + $x_window = array( + isset($x_value[$i]) ? $x_value[$i] : 0, + isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0, + isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0 ); - $y_value = array( - $y->value[$y_max], - ( $y_max > 0 ) ? $y->value[$y_max - 1] : 0 + $y_window = array( + $y_value[$y_max], + ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0 ); $q_index = $i - $y_max - 1; - if ($x_value[0] == $y_value[0]) { - $quotient->value[$q_index] = 0x3FFFFFF; + if ($x_window[0] == $y_window[0]) { + $quotient_value[$q_index] = 0x3FFFFFF; } else { - $quotient->value[$q_index] = floor( - ($x_value[0] * 0x4000000 + $x_value[1]) + $quotient_value[$q_index] = floor( + ($x_window[0] * 0x4000000 + $x_window[1]) / - $y_value[0] + $y_window[0] ); } - $temp = new Math_BigInteger(); - $temp->value = array($y_value[1], $y_value[0]); + $temp_value = array($y_window[1], $y_window[0]); - $lhs = new Math_BigInteger(); - $lhs->value = array($quotient->value[$q_index]); + $lhs->value = array($quotient_value[$q_index]); $lhs = $lhs->multiply($temp); - $rhs = new Math_BigInteger(); - $rhs->value = array($x_value[2], $x_value[1], $x_value[0]); + $rhs_value = array($x_window[2], $x_window[1], $x_window[0]); while ( $lhs->compare($rhs) > 0 ) { - $quotient->value[$q_index]--; + $quotient_value[$q_index]--; - $lhs = new Math_BigInteger(); - $lhs->value = array($quotient->value[$q_index]); + $lhs->value = array($quotient_value[$q_index]); $lhs = $lhs->multiply($temp); } $adjust = $this->_array_repeat(0, $q_index); - $temp = new Math_BigInteger(); - $temp->value = array($quotient->value[$q_index]); + $temp_value = array($quotient_value[$q_index]); $temp = $temp->multiply($y); - $temp->value = array_merge($adjust, $temp->value); + $temp_value = &$temp->value; + $temp_value = array_merge($adjust, $temp_value); $x = $x->subtract($temp); if ($x->compare($zero) < 0) { - $temp->value = array_merge($adjust, $y->value); + $temp_value = array_merge($adjust, $y_value); $x = $x->add($temp); - $quotient->value[$q_index]--; + $quotient_value[$q_index]--; } - $x_max = count($x->value) - 1; + $x_max = count($x_value) - 1; } // unnormalize the remainder @@ -1354,11 +1387,14 @@ class Math_BigInteger { { $carry = 0; $result = new Math_BigInteger(); + $result_value = &$result->value; + + $this_value = &$this->value; for ($i = count($this->value) - 1; $i >= 0; $i--) { - $temp = 0x4000000 * $carry + $this->value[$i]; - $result->value[$i] = floor($temp / $divisor); - $carry = fmod($temp, $divisor); + $temp = 0x4000000 * $carry + $this_value[$i]; + $result_value[$i] = floor($temp / $divisor); + $carry = $temp - $divisor * $result_value[$i]; } $remainder = new Math_BigInteger(); @@ -1531,10 +1567,11 @@ class Math_BigInteger { static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1 - $e_length = count($e->value) - 1; - $e_bits = decbin($e->value[$e_length]); + $e_value = $e->value; + $e_length = count($e_value) - 1; + $e_bits = decbin($e_value[$e_length]); for ($i = $e_length - 1; $i >= 0; $i--) { - $e_bits.= str_pad(decbin($e->value[$i]), 26, '0', STR_PAD_LEFT); + $e_bits.= str_pad(decbin($e_value[$i]), 26, '0', STR_PAD_LEFT); } $e_length = strlen($e_bits); @@ -1698,8 +1735,11 @@ class Math_BigInteger { * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x." * * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that - * usable on account of its not using reasonable radix points as discussed in - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2}. + * usable on account of (1) its not using reasonable radix points as discussed in + * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable + * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that + * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line + * comments for details. * * @see _slidingWindow() * @access private @@ -1713,53 +1753,78 @@ class Math_BigInteger { MATH_BIGINTEGER_DATA => array() ); - // "given an n-bit modulus, M, ..." - $n_length = count($m->value); + $m_value = $m->value; + $m_length = count($m_value); - if (count($this->value) > 2 * $n_length) {// || count($this->value) < count($m->value)) { + if ($m_length & 1) { + $m_value[] = 0; + $m_length++; + } + + // if ($this->compare($m->_square()) >= 0) { + if (count($this->value) > 2 * $m_length) { list(, $temp) = $this->divide($m); return $temp; } - $n = $this->copy(); - $temp = new Math_BigInteger(); - $temp2= new Math_BigInteger(); + // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced + if ($m_length < 5) { + return $this->_regularBarrett($m); + } - if ( ($key = array_search($m->value, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $n = $this->copy(); // 2 * m.length + static $temp; + if (!isset($temp)) { + $temp = new Math_BigInteger(); + } + $temp_value = &$temp->value; + + if ( ($key = array_search($m_value, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { $key = count($cache[MATH_BIGINTEGER_VARIABLE]); - $cache[MATH_BIGINTEGER_VARIABLE][] = $m->value; + $cache[MATH_BIGINTEGER_VARIABLE][] = $m_value; - $temp->value = $this->_array_repeat(0, $n_length + ($n_length >> 1)); - $temp->value[] = 1; + $temp_value = $this->_array_repeat(0, $m_length + ($m_length >> 1)); + $temp_value[] = 1; list($u, $m1) = $temp->divide($m); $cache[MATH_BIGINTEGER_DATA][] = array( - 'u' => $u, - 'm1'=> $m1 + 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1) + 'm1'=> $m1 // m.length ); + } else { + extract($cache[MATH_BIGINTEGER_DATA][$key]); } - extract($cache[MATH_BIGINTEGER_DATA][$key]); + $n_value = $n->value; - $cutoff = $n_length + ($n_length >> 1); + $cutoff = $m_length + ($m_length >> 1); $msd = new Math_BigInteger(); $lsd = new Math_BigInteger(); - $lsd->value = array_slice($n->value, 0, $cutoff); - $msd->value = array_slice($n->value, $cutoff); + $lsd->value = array_slice($n_value, 0, $cutoff); // m.length + (m.length >> 1) + $msd->value = array_slice($n_value, $cutoff); // m.length >> 1 $lsd->_trim(); - $n = $lsd->add($msd->multiply($m1)); + $n = $lsd->add($msd->multiply($m1)); // m.length + (m.length >> 1) + 1 - /* at this point, given list($a, $b) = $n->divide($m) and list($c, $d) = $this->divide($m), - we can safely assume $b == $d (even though $a != $c). */ - - $temp = new Math_BigInteger(); - $temp->value = array_slice($n->value, $n_length - 1); + // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2 + $temp_value = array_slice($n->value, $m_length - 1); + // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 + // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 $temp = $temp->multiply($u); - $temp->value = array_slice($temp->value, ($n_length >> 1) + 1); + $temp_value = &$temp->value; + // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 + // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + $temp_value = array_slice($temp_value, ($m_length >> 1) + 1); + // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 + // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) $temp = $temp->multiply($m); + // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit + // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop + // following this comment would loop a lot (hence our conditionally adding a 0 as the most significant digit). + $result = $n->subtract($temp); + while ($result->compare($m) >= 0) { $result = $result->subtract($m); } @@ -1767,6 +1832,148 @@ class Math_BigInteger { return $result; } + /** + * (Regular) Barrett Modular Reduction + * + * For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this + * is that this function does not fold the denominator into a smaller form. + * + * @see _slidingWindow() + * @access private + * @param Math_BigInteger + * @return Math_BigInteger + */ + function _regularBarrett($n) + { + static $cache = array( + MATH_BIGINTEGER_VARIABLE => array(), + MATH_BIGINTEGER_DATA => array() + ); + + $n_value = $n->value; + + $n_length = count($n_value); + + if (count($this->value) > 2 * $n_length) { + list(, $temp) = $this->divide($n); + return $temp; + } + + static $temp; + if (!isset($temp)) { + $temp = new Math_BigInteger(); + } + + if ( ($key = array_search($n_value, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { + $key = count($cache[MATH_BIGINTEGER_VARIABLE]); + $cache[MATH_BIGINTEGER_VARIABLE][] = $n_value; + $temp_value = &$temp->value; + $temp_value = $this->_array_repeat(0, 2 * $n_length); + $temp_value[] = 1; + list($cache[MATH_BIGINTEGER_DATA][], ) = $temp->divide($n); + } + + $this_value = $this->value; + + $temp->value = array_slice($this_value, $n_length - 1); + $temp = $temp->multiply($cache[MATH_BIGINTEGER_DATA][$key]); + $temp_value = &$temp->value; + $temp_value = array_slice($temp_value, $n_length + 1); + + $result = new Math_BigInteger(); + $result->value = array_slice($this_value, 0, $n_length + 1); + $temp = $temp->_multiplyLower($n, $n_length + 1); + // $temp->value == array_slice($temp->multiply($n)->value, 0, $n_length + 1) + + if ($result->compare($temp) < 0) { + static $corrector; + if (!isset($corrector)) { + $corrector = new Math_BigInteger(); + } + $corrector_value = &$corrector->value; + $corrector_value = $this->_array_repeat(0, $n_length + 1); + $corrector_value[] = 1; + $result = $result->add($corrector); + } + + $result = $result->subtract($temp); + while ($result->compare($n) > 0) { + $result = $result->subtract($n); + } + + return $result; + } + + /** + * Performs long multiplication up to $stop digits + * + * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved. + * + * @see _regularBarrett() + * @param Math_BigInteger $x + * @return Math_BigInteger + * @access private + */ + function _multiplyLower($x, $stop) + { + $this_value = $this->value; + $x_value = $x->value; + + $this_length = count($this_value); + $x_length = count($x_value); + + if ( !$this_length || !$x_length ) { // a 0 is being multiplied + return new Math_BigInteger(); + } + + if ( $this_length < $x_length ) { + return $x->_multiplyLower($this, $stop); + } + + $product = new Math_BigInteger(); + $product_value = &$product->value; + $product_value = $this->_array_repeat(0, $this_length + $x_length); + + // the following for loop could be removed if the for loop following it + // (the one with nested for loops) initially set $i to 0, but + // doing so would also make the result in one set of unnecessary adds, + // since on the outermost loops first pass, $product->value[$k] is going + // to always be 0 + + $carry = 0; + + for ($j = 0; $j < $this_length; $j++) { // ie. $i = 0, $k = $i + $temp = $this_value[$j] * $x_value[0] + $carry; // $product_value[$k] == 0 + $carry = floor($temp / 0x4000000); + $product_value[$j] = $temp - 0x4000000 * $carry; + } + + if ($j < $stop) { + $product_value[$j] = $carry; + } + + // the above for loop is what the previous comment was talking about. the + // following for loop is the "one with nested for loops" + + for ($i = 1; $i < $x_length; $i++) { + $carry = 0; + + for ($j = 0, $k = $i; $j < $this_length && $k < $stop; $j++, $k++) { + $temp = $product_value[$k] + $this_value[$j] * $x_value[$i] + $carry; + $carry = floor($temp / 0x4000000); + $product_value[$k] = $temp - 0x4000000 * $carry; + } + + if ($k < $stop) { + $product_value[$k] = $carry; + } + } + + $product->is_negative = $this->is_negative != $x->is_negative; + + return $product; + } + /** * Montgomery Modular Reduction * @@ -2082,7 +2289,7 @@ class Math_BigInteger { $d = new Math_BigInteger(); $a->value = $d->value = $g->value = array(1); - $b->value = $c->value = array(); + $b->value = $c->value = array(0); while ( !empty($u->value) ) { while ( !($u->value[0] & 1) ) { @@ -2204,7 +2411,9 @@ class Math_BigInteger { } $x = $this->_normalize($this->copy()); + $x_value = &$x->value; $y = $this->_normalize($y); + $y_value = &$y->value; if ( $x->is_negative != $y->is_negative ) { return ( !$x->is_negative && $y->is_negative ) ? 1 : -1; @@ -2212,13 +2421,13 @@ class Math_BigInteger { $result = $x->is_negative ? -1 : 1; - if ( count($x->value) != count($y->value) ) { - return ( count($x->value) > count($y->value) ) ? $result : -$result; + if ( count($x_value) != count($y_value) ) { + return ( count($x_value) > count($y_value) ) ? $result : -$result; } - for ($i = count($x->value) - 1; $i >= 0; $i--) { - if ($x->value[$i] != $y->value[$i]) { - return ( $x->value[$i] > $y->value[$i] ) ? $result : -$result; + for ($i = count($x_value) - 1; $i >= 0; $i--) { + if ($x_value[$i] != $y_value[$i]) { + return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result; } } @@ -2835,6 +3044,7 @@ class Math_BigInteger { $n_2 = $n->subtract($two); $r = $n_1->copy(); + $r_value = $r->value; // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { $s = 0; @@ -2844,8 +3054,8 @@ class Math_BigInteger { $s++; } } else { - for ($i = 0; $i < count($r->value); $i++) { - $temp = ~$r->value[$i] & 0xFFFFFF; + for ($i = 0, $r_length = count($r_value); $i < $r_length; $i++) { + $temp = ~$r_value[$i] & 0xFFFFFF; for ($j = 1; ($temp >> $j) & 1; $j++); if ($j != 25) { break; @@ -2856,8 +3066,7 @@ class Math_BigInteger { } for ($i = 0; $i < $t; $i++) { - $a = new Math_BigInteger(); - $a = $a->random($two, $n_2); + $a = $this->random($two, $n_2); $y = $a->modPow($r, $n); if (!$y->equals($one) && !$y->equals($n_1)) { @@ -2973,22 +3182,23 @@ class Math_BigInteger { return $result; } - if ( !count($result->value) ) { + $value = &$result->value; + + if ( !count($value) ) { return $result; } $result->_trim(); if (!empty($result->bitmask->value)) { - $length = min(count($result->value), count($this->bitmask->value)); - $result->value = array_slice($result->value, 0, $length); + $length = min(count($value), count($this->bitmask->value)); + $value = array_slice($value, 0, $length); for ($i = 0; $i < $length; $i++) { - $result->value[$i] = $result->value[$i] & $this->bitmask->value[$i]; + $value[$i] = $value[$i] & $this->bitmask->value[$i]; } } - //return $result->copy(); return $result; } @@ -3002,11 +3212,12 @@ class Math_BigInteger { */ function _trim() { - for ($i = count($this->value) - 1; $i >= 0; $i--) { - if ( $this->value[$i] ) { + $value = &$this->value; + for ($i = count($value) - 1; $i >= 0; $i--) { + if ( $value[$i] ) { break; } - unset($this->value[$i]); + unset($value[$i]); } }