/** * @param $a * @param $p * @return int|string */ public function squareRootModP($a, $p) { if (0 <= $a && $a < $p && 1 < $p) { if ($a == 0) { return 0; } if ($p == 2) { return $a; } $jac = $this->adapter->jacobi($a, $p); if ($jac == -1) { throw new \LogicException($a . " has no square root modulo " . $p); } if ($this->adapter->mod($p, 4) == 3) { return $this->adapter->powmod($a, $this->adapter->div($this->adapter->add($p, 1), 4), $p); } if ($this->adapter->mod($p, 8) == 5) { $d = $this->adapter->powmod($a, $this->adapter->div($this->adapter->sub($p, 1), 4), $p); if ($d == 1) { return $this->adapter->powmod($a, $this->adapter->div($this->adapter->add($p, 3), 8), $p); } if ($d == $p - 1) { return $this->adapter->mod($this->adapter->mul($this->adapter->mul(2, $a), $this->adapter->powmod($this->adapter->mul(4, $a), $this->adapter->div($this->adapter->sub($p, 5), 8), $p)), $p); } //shouldn't get here } for ($b = 2; $b < $p; $b++) { if ($this->adapter->jacobi($this->adapter->sub($this->adapter->mul($b, $b), $this->adapter->mul(4, $a)), $p) == -1) { $f = array($a, -$b, 1); $ff = $this->polynomialPowMod(array(0, 1), $this->adapter->div($this->adapter->add($p, 1), 2), $f, $p); if ($ff[1] == 0) { return $ff[0]; } // if we got here no b was found } } } throw new \InvalidArgumentException('Unable to calculate square root mod p!'); }
/** * @param $dividend * @param $divisor * @return int|string */ public function div($dividend, $divisor) { return $this->adapter->mod($this->adapter->mul($dividend, $this->adapter->inverseMod($divisor, $this->modulus)), $this->modulus); }