package scalaprops
import java.math.BigInteger
import scala.annotation.tailrec
object F2Polynomial {
private[scalaprops] val X = new F2Polynomial("10")
private def degree(pol: BigInteger): Int = {
if (pol == BigInteger.ZERO) {
-1
} else {
pol.bitLength - 1
}
}
private def mul(x: BigInteger, y: BigInteger): BigInteger = {
@tailrec def loop(z: BigInteger, v: BigInteger, w: BigInteger): BigInteger = {
if(w != BigInteger.ZERO) {
val z0 = if (w.and(BigInteger.ONE).testBit(0)) {
z.xor(v)
} else z
loop(z0, v.shiftLeft(1), w.shiftRight(1))
} else z
}
loop(BigInteger.ZERO, x, y)
}
private def mod(y: BigInteger, that: BigInteger): BigInteger = {
val deg = degree(that)
val diff = degree(y) - deg
if (diff < 0) {
y
} else if (diff == 0) {
y.xor(that)
} else {
var z: BigInteger = y
var x: BigInteger = that.shiftLeft(diff)
z = z.xor(x)
var zdeg: Int = z.bitLength - 1
while (zdeg >= deg) {
x = x.shiftRight(x.bitLength - 1 - zdeg)
z = z.xor(x)
zdeg = z.bitLength - 1
}
z
}
}
private def powerMod(x: BigInteger, power: BigInteger, mod: BigInteger): BigInteger = {
var z: BigInteger = BigInteger.ONE
var s: BigInteger = x
var pow: BigInteger = power
while (!(pow == BigInteger.ZERO)) {
if (pow.and(BigInteger.ONE).testBit(0)) {
z = mul(z, s)
z = this.mod(z, mod)
}
s = mul(s, s)
s = this.mod(s, mod)
pow = pow.shiftRight(1)
}
z
}
}
final class F2Polynomial private(private val pol: BigInteger) {
def this(value: String, radix: Int) {
this(new BigInteger(value, radix))
}
def this(value: String) {
this(new BigInteger(value, 2))
}
def degree: Int =
F2Polynomial.degree(pol)
def add(that: F2Polynomial): F2Polynomial =
new F2Polynomial(this.pol.xor(that.pol))
def mul(that: F2Polynomial): F2Polynomial =
if (this.degree >= that.degree) {
new F2Polynomial(F2Polynomial.mul(this.pol, that.pol))
} else {
new F2Polynomial(F2Polynomial.mul(that.pol, this.pol))
}
def getCoefficient(index: Int): Int =
if (pol.testBit(index)) {
1
} else {
0
}
def mod(that: F2Polynomial): F2Polynomial =
new F2Polynomial(F2Polynomial.mod(this.pol, that.pol))
def power(pow: BigInteger): F2Polynomial =
new F2Polynomial(power(this.pol, pow))
private def power(x: BigInteger, power: BigInteger): BigInteger = {
var z: BigInteger = BigInteger.ONE
var v: BigInteger = x
var pow: BigInteger = power
while (!(pow == BigInteger.ZERO)) {
if (pow.and(BigInteger.ONE).testBit(0)) {
z = F2Polynomial.mul(z, v)
}
v = F2Polynomial.mul(v, v)
pow = pow.shiftRight(1)
}
z
}
def powerMod(pow: BigInteger, mod: F2Polynomial): F2Polynomial = {
new F2Polynomial(F2Polynomial.powerMod(this.pol, pow, mod.pol))
}
override def toString: String =
toString(2)
def toString(base: Int): String =
pol.toString(base)
override def equals(obj: Any): Boolean = {
obj match {
case that: F2Polynomial =>
this.pol == that.pol
case _ =>
false
}
}
override def hashCode: Int =
pol.hashCode
}