Skip to content

Commit

Permalink
chore: code enhancements
Browse files Browse the repository at this point in the history
- Update code to use BigInteger from `ionspin` lib instead of the `JVM` one
- Added the required code for signature bytes modification in the other platforms
- Moved unit tests from `jvmTest` to `commonTest`
- Added documentation to the two newly added methods
- Replace `JVM` method `System.arraycopy` and use `Kotlin` method instead

Signed-off-by: Ahmed Moussa <ahmed.moussa@iohk.io>
  • Loading branch information
hamada147 committed Apr 25, 2024
1 parent 3551a28 commit 3461997
Show file tree
Hide file tree
Showing 5 changed files with 1,049 additions and 954 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.iohk.atala.prism.apollo.secp256k1

import com.ionspin.kotlin.bignum.integer.Sign
import fr.acinq.secp256k1.Secp256k1
import org.kotlincrypto.hash.sha2.SHA256

Expand Down Expand Up @@ -75,7 +76,50 @@ actual class Secp256k1Lib {
if (Secp256k1.verify(normalisedSignature, sha, publicKey)) {
return true
}
return Secp256k1.verify(signature, sha, publicKey)
return Secp256k1.verify(transcodeSignatureToDERBitcoin(normalisedSignature), sha, publicKey)
}

/**
* Reverses the order of bytes in the given byte array.
*
* @param inputBytes The byte array to be reversed.
* @return A new byte array with the reversed order of bytes.
*/
private fun reverseB32(inputBytes: ByteArray): ByteArray {
val reversedBytes = ByteArray(inputBytes.size)
for (i in inputBytes.indices) {
reversedBytes[inputBytes.size - i - 1] = inputBytes[i]
}
return reversedBytes
}

/**
* Transcodes a signature to DER format for use in Bitcoin transactions.
*
* @param signature The signature to be transcoded, in byte array format.
* @return A byte array representing the signature in DER format.
*/
private fun transcodeSignatureToDERBitcoin(signature: ByteArray): ByteArray {
val rawLen = signature.size / 2
val bigR = com.ionspin.kotlin.bignum.integer.BigInteger.fromByteArray(signature.copyOfRange(0, rawLen), Sign.POSITIVE)
val bigS = com.ionspin.kotlin.bignum.integer.BigInteger.fromByteArray(signature.copyOfRange(rawLen, signature.size), Sign.POSITIVE)
var r = bigR.toByteArray()
var s = bigS.toByteArray()
r = reverseB32(r)
s = reverseB32(s)
val lenR = r.size
val lenS = s.size
val derLength = 6 + lenR + lenS
val derSignature = ByteArray(derLength)
derSignature[0] = 0x30
derSignature[1] = (4 + lenR + lenS).toByte()
derSignature[2] = 0x02
derSignature[3] = lenR.toByte()
r.copyInto(derSignature, 4, 0, lenR)
derSignature[4 + lenR] = 0x02
derSignature[5 + lenR] = lenS.toByte()
s.copyInto(derSignature, 6 + lenR, 0, lenS)
return derSignature
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.iohk.atala.prism.apollo.secp256k1

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.Sign
import fr.acinq.secp256k1.Secp256k1
import fr.acinq.secp256k1.Secp256k1Native
import org.kotlincrypto.hash.sha2.SHA256
Expand Down Expand Up @@ -73,7 +75,53 @@ actual class Secp256k1Lib {
return true
}
val normalisedSignature = Secp256k1.signatureNormalize(signature).first
return Secp256k1.verify(normalisedSignature, sha, publicKey)
if (Secp256k1.verify(normalisedSignature, sha, publicKey)) {
return true
}
return Secp256k1.verify(transcodeSignatureToDERBitcoin(normalisedSignature), sha, publicKey)
}

/**
* Reverses the order of bytes in the given byte array.
*
* @param inputBytes The byte array to be reversed.
* @return A new byte array with the reversed order of bytes.
*/
private fun reverseB32(inputBytes: ByteArray): ByteArray {
val reversedBytes = ByteArray(inputBytes.size)
for (i in inputBytes.indices) {
reversedBytes[inputBytes.size - i - 1] = inputBytes[i]
}
return reversedBytes
}

/**
* Transcodes a signature to DER format for use in Bitcoin transactions.
*
* @param signature The signature to be transcoded, in byte array format.
* @return A byte array representing the signature in DER format.
*/
private fun transcodeSignatureToDERBitcoin(signature: ByteArray): ByteArray {
val rawLen = signature.size / 2
val bigR = BigInteger.fromByteArray(signature.copyOfRange(0, rawLen), Sign.POSITIVE)
val bigS = BigInteger.fromByteArray(signature.copyOfRange(rawLen, signature.size), Sign.POSITIVE)
var r = bigR.toByteArray()
var s = bigS.toByteArray()
r = reverseB32(r)
s = reverseB32(s)
val lenR = r.size
val lenS = s.size
val derLength = 6 + lenR + lenS
val derSignature = ByteArray(derLength)
derSignature[0] = 0x30
derSignature[1] = (4 + lenR + lenS).toByte()
derSignature[2] = 0x02
derSignature[3] = lenR.toByte()
r.copyInto(derSignature, 4, 0, lenR)
derSignature[4 + lenR] = 0x02
derSignature[5 + lenR] = lenS.toByte()
s.copyInto(derSignature, 6 + lenR, 0, lenS)
return derSignature
}

/**
Expand Down

0 comments on commit 3461997

Please sign in to comment.