Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use multiplatform big numbers #96

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
5 changes: 3 additions & 2 deletions bip32/src/main/kotlin/org/kethereum/bip32/BIP32.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

package org.kethereum.bip32

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.Sign
import org.kethereum.bip32.model.CHAINCODE_SIZE
import org.kethereum.bip32.model.ExtendedKey
import org.kethereum.bip32.model.Seed
Expand All @@ -14,7 +16,6 @@ import org.komputing.kbip44.BIP44
import org.komputing.kbip44.BIP44Element
import org.komputing.khash.ripemd160.extensions.digestRipemd160
import org.komputing.khash.sha256.extensions.sha256
import java.math.BigInteger
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.security.InvalidKeyException
Expand Down Expand Up @@ -76,7 +77,7 @@ fun ExtendedKey.generateChildKey(element: BIP44Element): ExtendedKey {
val l = lr.copyOfRange(0, PRIVATE_KEY_SIZE)
val r = lr.copyOfRange(PRIVATE_KEY_SIZE, PRIVATE_KEY_SIZE + CHAINCODE_SIZE)

val m = BigInteger(1, l)
val m = BigInteger.fromByteArray(l, Sign.POSITIVE)
if (m >= CURVE.n) {
throw KeyException("Child key derivation resulted in a key with higher modulus. Suggest deriving the next increment.")
}
Expand Down
7 changes: 4 additions & 3 deletions bip32/src/main/kotlin/org/kethereum/bip32/Converter.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.kethereum.bip32

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.Sign
import org.kethereum.bip32.model.*
import org.kethereum.crypto.CURVE
import org.kethereum.crypto.CryptoAPI
Expand All @@ -10,7 +12,6 @@ import org.kethereum.model.PRIVATE_KEY_SIZE
import org.kethereum.model.PrivateKey
import org.kethereum.model.PublicKey
import org.komputing.kbase58.decodeBase58WithChecksum
import java.math.BigInteger
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.security.InvalidKeyException
Expand All @@ -23,7 +24,7 @@ fun Seed.toExtendedKey(publicKeyOnly: Boolean = false, testnet: Boolean = false)
val lr = CryptoAPI.hmac.init(BITCOIN_SEED).generate(seed)
val l = lr.copyOfRange(0, PRIVATE_KEY_SIZE)
val r = lr.copyOfRange(PRIVATE_KEY_SIZE, PRIVATE_KEY_SIZE + CHAINCODE_SIZE)
val m = BigInteger(1, l)
val m = BigInteger.fromByteArray(l, Sign.POSITIVE)
if (m >= CURVE.n) {
throw KeyException("Master key creation resulted in a key with higher modulus. Suggest deriving the next increment.")
}
Expand Down Expand Up @@ -83,7 +84,7 @@ fun XPriv.toExtendedKey(): ExtendedKey {
val uncompressedPublicBytes = decompressKey(compressedPublicBytes)
ECKeyPair(
PrivateKey(BigInteger.ZERO),
PublicKey(BigInteger(1, uncompressedPublicBytes))
PublicKey(BigInteger.fromByteArray(uncompressedPublicBytes, Sign.POSITIVE))
)
}
return ExtendedKey(keyPair, chainCode, depth, parent, sequence, versionBytes)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package org.kethereum.bip32.model

import com.ionspin.kotlin.bignum.integer.BigInteger
import org.kethereum.crypto.getCompressedPublicKey
import org.kethereum.extensions.toBytesPadded
import org.kethereum.model.ECKeyPair
import org.kethereum.model.PRIVATE_KEY_SIZE
import org.komputing.kbase58.encodeToBase58WithChecksum
import java.io.IOException
import java.math.BigInteger
import java.nio.ByteBuffer
import java.security.KeyException

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package org.walleth.kethereum.blockscout

import com.ionspin.kotlin.bignum.integer.BigInteger
import org.kethereum.model.ChainId

private const val BLOCKSCOUTCOM_BASE_URL = "https://blockscout.com"

private val BLOCKSCOUT_URLS = mapOf(
1L.toBigInteger() to "$BLOCKSCOUTCOM_BASE_URL/eth/mainnet",
42L.toBigInteger() to "$BLOCKSCOUTCOM_BASE_URL/eth/kovan",
61L.toBigInteger() to "$BLOCKSCOUTCOM_BASE_URL/etc/mainnet",
77L.toBigInteger() to "$BLOCKSCOUTCOM_BASE_URL/poa/sokol",
99L.toBigInteger() to "$BLOCKSCOUTCOM_BASE_URL/poa/core",
100L.toBigInteger() to "$BLOCKSCOUTCOM_BASE_URL/poa/xdai",
BigInteger(1L) to "$BLOCKSCOUTCOM_BASE_URL/eth/mainnet",
BigInteger(42L) to "$BLOCKSCOUTCOM_BASE_URL/eth/kovan",
BigInteger(61L) to "$BLOCKSCOUTCOM_BASE_URL/etc/mainnet",
BigInteger(77L) to "$BLOCKSCOUTCOM_BASE_URL/poa/sokol",
BigInteger(99L) to "$BLOCKSCOUTCOM_BASE_URL/poa/core",
BigInteger(100L) to "$BLOCKSCOUTCOM_BASE_URL/poa/xdai",

43110L.toBigInteger() to "http://athexplorer.ava.network"
BigInteger(43110L) to "http://athexplorer.ava.network"
)

val ALL_BLOCKSCOUT_SUPPORTED_NETWORKS = BLOCKSCOUT_URLS.map { it.key }.toSet()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package org.kethereum.bloomfilter

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.Sign
import org.komputing.khash.sha256.extensions.sha256
import java.math.BigInteger
import java.util.*
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.read
Expand Down Expand Up @@ -31,7 +32,7 @@ class BloomFilter(private val size: Int) {
}

private fun hashing(filterSize: Int, seed: Int, value: ByteArray) =
BigInteger(1, value.plus(seed.toByte()).sha256())
.remainder(BigInteger.valueOf(filterSize.toLong()))
.toInt()
BigInteger.fromByteArray(value.plus(seed.toByte()).sha256(), Sign.POSITIVE)
.remainder(BigInteger(filterSize.toLong()))
.intValue()
}
10 changes: 8 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ buildscript {
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlin}")
classpath("com.github.ben-manes:gradle-versions-plugin:${Versions.versions_plugin}")
classpath("com.github.komputing:kethabi:0.1.8")
classpath("com.github.fullkomnun:kethabi:${Versions.kethabi_plugin}") {
isChanging = true
}
}
}

configurations.all {
resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS)
}
}

subprojects {
repositories {
Expand All @@ -40,6 +45,7 @@ subprojects {

dependencies {
"implementation"("org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}")
"implementation"("com.ionspin.kotlin:bignum-jvm:${Versions.bignum}")

"testImplementation"("org.assertj:assertj-core:3.19.0")
"testImplementation"("org.junit.jupiter:junit-jupiter-api:${Versions.jupiter}")
Expand Down
2 changes: 2 additions & 0 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
object Versions {
const val kotlin = "1.4.21"
const val versions_plugin = "0.36.0"
const val kethabi_plugin = "use_multiplatform_big_numbers-SNAPSHOT"
const val jupiter = "5.7.0"
const val moshi = "1.8.0"
const val khex = "1.0.0"
Expand All @@ -12,4 +13,5 @@ object Versions {
const val threetenbp = "1.5.0"
const val okio = "2.4.0"
const val base58 = "0.2"
const val bignum = "0.2.8"
}
5 changes: 3 additions & 2 deletions crypto/src/main/kotlin/org/kethereum/crypto/Converters.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package org.kethereum.crypto

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.Sign
import org.kethereum.crypto.api.ec.CurvePoint
import org.kethereum.extensions.toHexStringZeroPadded
import org.kethereum.keccakshortcut.keccak
import org.kethereum.model.*
import org.komputing.khex.extensions.hexToByteArray
import org.komputing.khex.extensions.toHexString
import org.komputing.khex.model.HexString
import java.math.BigInteger

fun PublicKey.toAddress() : Address {
val publicKeyHexString = HexString(key.toHexStringZeroPadded(PUBLIC_KEY_LENGTH_IN_HEX, false))
Expand All @@ -28,5 +29,5 @@ fun PrivateKey.toECKeyPair() = ECKeyPair(this, publicKeyFromPrivate(this))
* Decodes an uncompressed public key (without 0x04 prefix) given an ECPoint
*/
fun CurvePoint.toPublicKey() = encoded().let { encoded ->
PublicKey(BigInteger(1, encoded.copyOfRange(1, encoded.size)))
PublicKey(BigInteger.fromByteArray(encoded.copyOfRange(1, encoded.size), Sign.POSITIVE))
}
3 changes: 2 additions & 1 deletion crypto/src/main/kotlin/org/kethereum/crypto/Sign.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.kethereum.crypto

import com.ionspin.kotlin.bignum.integer.BigInteger
import org.kethereum.crypto.api.ec.Curve
import org.kethereum.crypto.api.ec.ECDSASignature
import org.kethereum.keccakshortcut.keccak
Expand Down Expand Up @@ -47,7 +48,7 @@ fun signMessageHash(messageHash: ByteArray, keyPair: ECKeyPair, toCanonical: Boo

val headerByte = recId + 27

return SignatureData(signature.r, signature.s, headerByte.toBigInteger())
return SignatureData(signature.r, signature.s, BigInteger(headerByte))
}

fun ECDSASignature.determineRecId(messageHash: ByteArray, publicKey: PublicKey): Int {
Expand Down
2 changes: 1 addition & 1 deletion crypto/src/main/kotlin/org/kethereum/crypto/Signatures.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.kethereum.crypto

import com.ionspin.kotlin.bignum.integer.BigInteger
import org.kethereum.extensions.toHexStringNoPrefix
import org.kethereum.extensions.toHexStringZeroPadded
import org.kethereum.model.SignatureData
import java.math.BigInteger

fun SignatureData.toHex() = r.to64BytePaddedHex() + s.to64BytePaddedHex() + v.toHexStringNoPrefix()

Expand Down
5 changes: 3 additions & 2 deletions crypto/src/test/kotlin/org/kethereum/crypto/SignTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.kethereum.crypto

import com.ionspin.kotlin.bignum.integer.BigInteger
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.kethereum.crypto.test_data.KEY_PAIR
Expand All @@ -22,7 +23,7 @@ class SignTest {
val expected = SignatureData(
HexString("0x9631f6d21dec448a213585a4a41a28ef3d4337548aa34734478b563036163786").hexToBigInteger(),
HexString("0x2ff816ee6bbb82719e983ecd8a33a4b45d32a4b58377ef1381163d75eedc900b").hexToBigInteger(),
27.toBigInteger()
BigInteger(27)
)

assertThat(signatureData).isEqualTo(expected)
Expand All @@ -39,7 +40,7 @@ class SignTest {
val expected = SignatureData(
HexString("0x6bcd81446183af193ca4a172d5c5c26345903b24770d90b5d790f74a9dec1f68").hexToBigInteger(),
HexString("0xe2b85b3c92c9b4f3cf58de46e7997d8efb6e14b2e532d13dfa22ee02f3a43d5d").hexToBigInteger(),
28.toBigInteger()
BigInteger(28)
)

assertThat(expected).isEqualTo(signatureData)
Expand Down
3 changes: 2 additions & 1 deletion crypto/src/test/kotlin/org/kethereum/crypto/TheSignatures.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.kethereum.crypto

import com.ionspin.kotlin.bignum.integer.BigInteger
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.kethereum.extensions.hexToBigInteger
Expand All @@ -14,7 +15,7 @@ class TheSignatures {
val signatureData = SignatureData(
HexString("0x0031f6d21dec448a213585a4a41a28ef3d4337548aa34734478b563036163786").hexToBigInteger(),
HexString("0x2ff816ee6bbb82719e983ecd8a33a4b45d32a4b58377ef1381163d75eedc900b").hexToBigInteger(),
27.toBigInteger()
BigInteger(27)
)

assertThat(signatureData.toHex()).isEqualTo("0031f6d21dec448a213585a4a41a28ef3d4337548aa34734478b5630361637862ff816ee6bbb82719e983ecd8a33a4b45d32a4b58377ef1381163d75eedc900b1b")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.kethereum.crypto.api.ec

import java.math.BigInteger
import com.ionspin.kotlin.bignum.integer.BigInteger

interface Curve {
val n: BigInteger
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.kethereum.crypto.api.ec

import java.math.BigInteger
import com.ionspin.kotlin.bignum.integer.BigInteger

interface CurvePoint {
val x: BigInteger
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package org.kethereum.crypto.api.ec

import java.math.BigInteger
import com.ionspin.kotlin.bignum.integer.BigInteger

data class ECDSASignature(val r: BigInteger, val s: BigInteger)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.kethereum.crypto.api.ec

import java.math.BigInteger
import com.ionspin.kotlin.bignum.integer.BigInteger

interface Signer {
fun sign(transactionHash: ByteArray, privateKey: BigInteger, canonical: Boolean): ECDSASignature
Expand Down
12 changes: 12 additions & 0 deletions crypto_api/src/main/kotlin/org/kethereum/crypto/impl/BigInteger.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.kethereum.crypto.impl

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.util.fromTwosComplementByteArray
import com.ionspin.kotlin.bignum.integer.util.toTwosComplementByteArray
import java.math.BigInteger as JavaBigInteger

fun JavaBigInteger.toKotlinBigInteger(): BigInteger =
BigInteger.fromTwosComplementByteArray(toByteArray())

fun BigInteger.toJavaBigInteger(): JavaBigInteger =
JavaBigInteger(toTwosComplementByteArray())
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package org.kethereum.crypto.impl.ec

import com.ionspin.kotlin.bignum.integer.BigInteger
import org.bouncycastle.crypto.ec.CustomNamedCurves
import org.bouncycastle.crypto.params.ECDomainParameters
import org.kethereum.crypto.api.ec.Curve
import org.kethereum.crypto.api.ec.CurvePoint
import java.math.BigInteger
import org.kethereum.crypto.impl.toJavaBigInteger
import org.kethereum.crypto.impl.toKotlinBigInteger

internal val CURVE_PARAMS by lazy { CustomNamedCurves.getByName("secp256k1")!! }
internal val DOMAIN_PARAMS = CURVE_PARAMS.run { ECDomainParameters(curve, g, n, h) }

class EllipticCurve : Curve {

override val n: BigInteger
get() = CURVE_PARAMS.n
get() = CURVE_PARAMS.n.toKotlinBigInteger()

override val g: CurvePoint
get() = CURVE_PARAMS.g.toCurvePoint()
Expand All @@ -21,5 +23,5 @@ class EllipticCurve : Curve {
CURVE_PARAMS.curve.decodePoint(data).toCurvePoint()

override fun createPoint(x: BigInteger, y: BigInteger): CurvePoint =
CURVE_PARAMS.curve.createPoint(x, y).toCurvePoint()
CURVE_PARAMS.curve.createPoint(x.toJavaBigInteger(), y.toJavaBigInteger()).toCurvePoint()
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
package org.kethereum.crypto.impl.ec

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.Sign
import org.bouncycastle.crypto.generators.ECKeyPairGenerator
import org.bouncycastle.crypto.params.ECKeyGenerationParameters
import org.bouncycastle.crypto.params.ECPrivateKeyParameters
import org.bouncycastle.crypto.params.ECPublicKeyParameters
import org.kethereum.crypto.api.ec.KeyPairGenerator
import org.kethereum.crypto.impl.toKotlinBigInteger
import org.kethereum.model.ECKeyPair
import org.kethereum.model.PrivateKey
import org.kethereum.model.PublicKey
import java.math.BigInteger
import java.util.*

class EllipticCurveKeyPairGenerator : KeyPairGenerator {
override fun generate() = ECKeyPairGenerator().run {
init(ECKeyGenerationParameters(DOMAIN_PARAMS, null))
generateKeyPair().run {
val privateKeyValue = (private as ECPrivateKeyParameters).d
val privateKeyValue = (private as ECPrivateKeyParameters).d.toKotlinBigInteger()
val publicKeyBytes = (public as ECPublicKeyParameters).q.getEncoded(false)
val publicKeyValue = BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 1, publicKeyBytes.size))
val publicKeyValue = BigInteger.fromByteArray(Arrays.copyOfRange(publicKeyBytes, 1, publicKeyBytes.size), Sign.POSITIVE)
ECKeyPair(PrivateKey(privateKeyValue), PublicKey(publicKeyValue))
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package org.kethereum.crypto.impl.ec

import com.ionspin.kotlin.bignum.integer.BigInteger
import org.bouncycastle.math.ec.ECPoint
import org.kethereum.crypto.api.ec.CurvePoint
import java.math.BigInteger
import org.kethereum.crypto.impl.toJavaBigInteger
import org.kethereum.crypto.impl.toKotlinBigInteger

class EllipticCurvePoint(private val ecPoint: ECPoint) : CurvePoint {
override val x: BigInteger
get() = ecPoint.xCoord.toBigInteger()
get() = ecPoint.xCoord.toBigInteger().toKotlinBigInteger()
override val y: BigInteger
get() = ecPoint.yCoord.toBigInteger()
get() = ecPoint.yCoord.toBigInteger().toKotlinBigInteger()

override fun mul(n: BigInteger): CurvePoint =
ecPoint.multiply(n).toCurvePoint()
ecPoint.multiply(n.toJavaBigInteger()).toCurvePoint()

override fun add(p: CurvePoint): CurvePoint =
(p as? EllipticCurvePoint)?.let {
Expand Down
Loading