Skip to content

Commit

Permalink
Merge pull request #308 from ionspin/modInverseFix
Browse files Browse the repository at this point in the history
Mod inverse fix
  • Loading branch information
ionspin authored Jul 14, 2024
2 parents 2ebf683 + 936e19c commit 2f54816
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import com.ionspin.kotlin.bignum.decimal.BigDecimal
import com.ionspin.kotlin.bignum.integer.base63.array.BigInteger63Arithmetic
import com.ionspin.kotlin.bignum.integer.base63.array.BigInteger63Arithmetic.compareTo
import com.ionspin.kotlin.bignum.modular.ModularBigInteger
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.log10

Expand Down Expand Up @@ -414,23 +413,41 @@ class BigInteger internal constructor(wordArray: WordArray, requestedSign: Sign)
return u
}

// https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers
fun modInverse(modulo: BigInteger): BigInteger {
if (gcd(modulo) != ONE) {
throw ArithmeticException("BigInteger is not invertible. This and modulus are not relatively prime (coprime)")
}
var u = ONE
var w = ZERO
var b = this
var c = modulo
while (!c.isZero()) {
val (q, r) = b divrem c
b = c
c = r
val tmpU = u
u = w
w = tmpU - q * w
// Ensure the numbers are coprime
if (this.gcd(modulo) != ONE) {
throw ArithmeticException("BigInteger is not invertible. This and modulus are not relatively prime (coprime).")
}
return u
// Initialize variables for the Extended Euclidean Algorithm
var t = ZERO
var newT = ONE
var r = modulo
var newR = this

// Loop until the remainder is zero
while (newR != ZERO) {
// Compute the quotient
val quotient = r.divide(newR)

// Update t and newT (coefficient)
val tempT = t
t = newT
newT = tempT - quotient * newT

// Update r and newR (remainder)
val tempR = r
r = newR
newR = tempR - quotient * newR
}

// If r is greater than 1, this is not invertible
if (r > ONE) throw ArithmeticException("BigInteger is not invertible.")

// Ensure the result is positive
if (t < ZERO) t += modulo

return t
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
*
*/

package com.ionspin.kotlin.bignum.integer.arithmetic
package com.ionspin.kotlin.bignum.integer

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.toBigInteger
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
Expand Down Expand Up @@ -149,15 +148,21 @@ BigIntegerTest {

@Test
fun testModInverse() {

assertTrue {
var a = BigInteger(11)
var aInverse = a.modInverse(5.toBigInteger())
val a = BigInteger(11)
val aInverse = a.modInverse(5.toBigInteger())
aInverse == BigInteger(1)
}
assertTrue {
val a = BigInteger(54647)
val aInverse = a.modInverse(1157920.toBigInteger())
aInverse == BigInteger(1141223)
}
assertFailsWith<ArithmeticException> {
var a = BigInteger(10)
val a = BigInteger(10)
a.modInverse(5.toBigInteger())
}.also {
assertEquals("BigInteger is not invertible. This and modulus are not relatively prime (coprime).", it.message)
}
}

Expand All @@ -166,7 +171,7 @@ BigIntegerTest {
val a = 10.toBigInteger()
val b = 3.toBigInteger()
assertTrue { a.gcd(b) == 1.toBigInteger() }
var c = 6.toBigInteger()
val c = 6.toBigInteger()
assertTrue { a.gcd(c) == 2.toBigInteger() }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import kotlin.test.assertEquals
* on 01-Nov-2019
*/
class BigIntegerBitwiseOperations {

@Test
fun xorWithZero() {
val operand = BigInteger.parseString("11110000", 2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,16 @@ class BigIntegerJvmTest {

@Test
fun testModInverse() {
val a = BigInteger(11)
val aInverse = a.modInverse(5.toBigInteger())
val aJavaInverse = a.toJavaBigInteger().modInverse(java.math.BigInteger.valueOf(5))
assertTrue {
val a = BigInteger(11)
val aInverse = a.modInverse(5.toBigInteger())
val aJavaInverse = a.toJavaBigInteger().modInverse(java.math.BigInteger.valueOf(5))
aInverse.toJavaBigInteger() == aJavaInverse
}
assertTrue {
val a = BigInteger(12312354647)
val aInverse = a.modInverse(121157920.toBigInteger())
val aJavaInverse = a.toJavaBigInteger().modInverse(java.math.BigInteger.valueOf(121157920))
aInverse.toJavaBigInteger() == aJavaInverse
}
}
Expand Down

0 comments on commit 2f54816

Please sign in to comment.