From 76fedc4a6f039a352a37260ca23ac845bb2548ad Mon Sep 17 00:00:00 2001 From: "hoang.nt" Date: Mon, 1 Jul 2024 23:21:02 +0700 Subject: [PATCH 1/2] Fix function modInverse --- .../kotlin/bignum/integer/BigInteger.kt | 48 +++++++++++++------ .../kotlin/bignum/integer/BigIntegerTest.kt | 21 ++++---- .../integer/BigIntegerBitwiseOperations.kt | 1 - .../bignum/integer/BigIntegerJvmTest.kt | 12 +++-- 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/integer/BigInteger.kt b/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/integer/BigInteger.kt index 609e7cdf..692cfbd7 100644 --- a/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/integer/BigInteger.kt +++ b/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/integer/BigInteger.kt @@ -413,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 != ZERO) { - 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 } /** diff --git a/bignum/src/commonTest/kotlin/com/ionspin/kotlin/bignum/integer/BigIntegerTest.kt b/bignum/src/commonTest/kotlin/com/ionspin/kotlin/bignum/integer/BigIntegerTest.kt index f40179dd..d7a27784 100644 --- a/bignum/src/commonTest/kotlin/com/ionspin/kotlin/bignum/integer/BigIntegerTest.kt +++ b/bignum/src/commonTest/kotlin/com/ionspin/kotlin/bignum/integer/BigIntegerTest.kt @@ -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 @@ -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 { - 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) } } @@ -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() } } diff --git a/bignum/src/commonTest/kotlin/com/ionspin/kotlin/bignum/integer/integer/BigIntegerBitwiseOperations.kt b/bignum/src/commonTest/kotlin/com/ionspin/kotlin/bignum/integer/integer/BigIntegerBitwiseOperations.kt index b643af4e..5c70ceff 100644 --- a/bignum/src/commonTest/kotlin/com/ionspin/kotlin/bignum/integer/integer/BigIntegerBitwiseOperations.kt +++ b/bignum/src/commonTest/kotlin/com/ionspin/kotlin/bignum/integer/integer/BigIntegerBitwiseOperations.kt @@ -27,7 +27,6 @@ import kotlin.test.assertEquals * on 01-Nov-2019 */ class BigIntegerBitwiseOperations { - @Test fun xorWithZero() { val operand = BigInteger.parseString("11110000", 2) diff --git a/bignum/src/jvmTest/kotlin/com/ionspin/kotlin/bignum/integer/BigIntegerJvmTest.kt b/bignum/src/jvmTest/kotlin/com/ionspin/kotlin/bignum/integer/BigIntegerJvmTest.kt index e89b5331..249aadab 100644 --- a/bignum/src/jvmTest/kotlin/com/ionspin/kotlin/bignum/integer/BigIntegerJvmTest.kt +++ b/bignum/src/jvmTest/kotlin/com/ionspin/kotlin/bignum/integer/BigIntegerJvmTest.kt @@ -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 } } From 936e19c2e074111eae84523202e34365c6c19d41 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sun, 14 Jul 2024 18:45:37 +0200 Subject: [PATCH 2/2] Spotless --- .../kotlin/com/ionspin/kotlin/bignum/integer/BigInteger.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/integer/BigInteger.kt b/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/integer/BigInteger.kt index 9bce3178..05ee6473 100644 --- a/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/integer/BigInteger.kt +++ b/bignum/src/commonMain/kotlin/com/ionspin/kotlin/bignum/integer/BigInteger.kt @@ -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