6 * Utilizes the factory design pattern
10 * @author Jim Wigginton <terrafrost@php.net>
11 * @copyright 2017 Jim Wigginton
12 * @license http://www.opensource.org/licenses/mit-license.html MIT License
15 namespace phpseclib3\Math;
17 use phpseclib3\Common\Functions\Strings;
18 use phpseclib3\Math\BinaryField\Integer;
19 use phpseclib3\Math\Common\FiniteField;
22 * Binary Finite Fields
24 * @author Jim Wigginton <terrafrost@php.net>
26 class BinaryField extends FiniteField
33 private static $instanceCounter = 0;
36 * Keeps track of current instance
40 protected $instanceID;
42 /** @var BigInteger */
48 public function __construct(...$indices)
50 $m = array_shift($indices);
51 $val = str_repeat('0', $m) . '1';
52 foreach ($indices as $index) {
55 $modulo = static::base2ToBase256(strrev($val));
59 $finalMask = chr((1 << ($m % 8)) - 1);
60 if ($finalMask == "\0") {
63 $bitLen = $mStart + 1;
64 $pad = ceil($bitLen / 8);
68 $r = rtrim(substr($val, 0, -1), '0');
69 $u = [static::base2ToBase256(strrev($r))];
70 for ($i = 1; $i < 8; $i++) {
71 $u[] = static::base2ToBase256(strrev(str_repeat('0', $i) . $r));
74 // implements algorithm 2.40 (in section 2.3.5) in "Guide to Elliptic Curve Cryptography"
76 $reduce = function ($c) use ($u, $mStart, $m, $t, $finalMask, $pad, $h) {
77 $c = str_pad($c, $pad, "\0", STR_PAD_LEFT);
78 for ($i = $mStart; $i >= $m;) {
81 $mask = $mask ? 1 << (7 - $mask) : 0x80;
82 for (; $mask > 0; $mask >>= 1, $i--, $h++) {
83 if (ord($c[$g]) & $mask) {
87 $t1 = $j ? substr($c, 0, -$j) : $c;
88 $length = strlen($t1);
90 $t2 = str_pad($u[$k], $length, "\0", STR_PAD_LEFT);
92 $c = $j ? substr_replace($c, $temp, 0, $length) : $temp;
98 if (strlen($c) == $t) {
99 $c[0] = $c[0] & $finalMask;
101 return ltrim($c, "\0");
104 $this->instanceID = self::$instanceCounter++;
105 Integer::setModulo($this->instanceID, $modulo);
106 Integer::setRecurringModuloFunction($this->instanceID, $reduce);
108 $this->randomMax = new BigInteger($modulo, 2);
112 * Returns an instance of a dynamically generated PrimeFieldInteger class
117 public function newInteger($num)
119 return new Integer($this->instanceID, $num instanceof BigInteger ? $num->toBytes() : $num);
123 * Returns an integer on the finite field between one and the prime modulo
127 public function randomInteger()
131 $one = new BigInteger(1);
134 return new Integer($this->instanceID, BigInteger::randomRange($one, $this->randomMax)->toBytes());
138 * Returns the length of the modulo in bytes
142 public function getLengthInBytes()
144 return strlen(Integer::getModulo($this->instanceID));
148 * Returns the length of the modulo in bits
152 public function getLength()
154 return strlen(Integer::getModulo($this->instanceID)) << 3;
158 * Converts a base-2 string to a base-256 string
161 * @param int|null $size
164 public static function base2ToBase256($x, $size = null)
166 $str = Strings::bits2bin($x);
168 $pad = strlen($x) >> 3;
169 if (strlen($x) & 3) {
172 $str = str_pad($str, $pad, "\0", STR_PAD_LEFT);
174 $str = str_pad($str, $size, "\0", STR_PAD_LEFT);
181 * Converts a base-256 string to a base-2 string
186 public static function base256ToBase2($x)
188 if (function_exists('gmp_import')) {
189 return gmp_strval(gmp_import($x), 2);
192 return Strings::bin2bits($x);