Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ kotlin {
}

sourceSets {
val secp256k1KmpVersion = "0.15.0"
val secp256k1KmpVersion = "0.16.0"

val commonMain by getting {
dependencies {
Expand All @@ -59,8 +59,8 @@ kotlin {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
implementation("org.kodein.memory:klio-files:0.12.0")
api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.5.4")
api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
}
}

Expand Down
15 changes: 1 addition & 14 deletions src/commonTest/kotlin/fr/acinq/bitcoin/BlockTestsCommon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,11 @@

package fr.acinq.bitcoin

import fr.acinq.bitcoin.reference.TransactionTestsCommon
import fr.acinq.secp256k1.Hex
import org.kodein.memory.file.openReadableFile
import org.kodein.memory.file.resolve
import org.kodein.memory.use
import kotlin.test.*

class BlockTestsCommon {
private val blockData = run {
val file = TransactionTestsCommon.resourcesDir().resolve("block1.dat")
file.openReadableFile().use {
val len = it.size
// workaround for a bug in kotlin memory file where dstOffset cannot be 0 but is still ignored...
val buffer = ByteArray(len)
it.readBytes(buffer, 0, buffer.size)
buffer
}
}
private val blockData = TestHelpers.readResourceAsByteArray("block1.dat")

@Test
fun `read blocks`() {
Expand Down
55 changes: 26 additions & 29 deletions src/commonTest/kotlin/fr/acinq/bitcoin/CryptoTestsCommon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@

package fr.acinq.bitcoin

import fr.acinq.bitcoin.reference.TransactionTestsCommon
import fr.acinq.secp256k1.Hex
import fr.acinq.secp256k1.Secp256k1
import org.kodein.memory.file.openReadableFile
import org.kodein.memory.file.resolve
import org.kodein.memory.text.readLine
import org.kodein.memory.use
import kotlinx.io.buffered
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem
import kotlinx.io.readLine
import kotlin.random.Random
import kotlin.test.*

Expand Down Expand Up @@ -207,7 +206,6 @@ class CryptoTestsCommon {
val publicKey = privateKey.publicKey()
val shared = Crypto.ecdh(privateKey, publicKey)
assertEquals("56bc84cffc7db1ca04046fc04ec8f84232c340be789bc4779d221fe8b978af06", Hex.encode(shared))

val random = Random
val privateKey1 = PrivateKey(random.nextBytes(32))
val privateKey2 = PrivateKey(random.nextBytes(32))
Expand Down Expand Up @@ -257,29 +255,28 @@ class CryptoTestsCommon {
var pub: PublicKey? = null
var sig: ByteVector? = null
var recid: Int
val file = TransactionTestsCommon.resourcesDir().resolve("recid.txt")
file.openReadableFile().use {
while (true) {
val line = it.readLine() ?: return
val values = line.split(" = ")
val lhs = values[0]
val rhs = values[1]
when (lhs) {
"privkey" -> priv = PrivateKey(ByteVector(rhs).toByteArray())
"message" -> message = ByteVector(rhs)
"pubkey" -> pub = PublicKey(ByteVector(rhs))
"sig" -> sig = run {
val reversed = ByteVector(rhs).take(64)
ByteVector((reversed.take(32).reversed() + reversed.takeRight(32).reversed()).toByteArray())
}
"recid" -> {
recid = rhs.toInt()
assertEquals(priv!!.publicKey(), pub)
val sig1 = Crypto.sign(message!!.toByteArray(), priv!!)
assertEquals(sig1, sig)
val pub1 = Crypto.recoverPublicKey(sig1, message!!.toByteArray(), recid)
assertEquals(pub1, pub)
}
val source = SystemFileSystem.source(Path(TestHelpers.resourcesPath, "recid.txt")).buffered()
while (true) {
val line = source.readLine() ?: return
val values = line.split(" = ")
val lhs = values[0]
val rhs = values[1]
when (lhs) {
"privkey" -> priv = PrivateKey(ByteVector(rhs).toByteArray())
"message" -> message = ByteVector(rhs)
"pubkey" -> pub = PublicKey(ByteVector(rhs))
"sig" -> sig = run {
val reversed = ByteVector(rhs).take(64)
ByteVector((reversed.take(32).reversed() + reversed.takeRight(32).reversed()).toByteArray())
}

"recid" -> {
recid = rhs.toInt()
assertEquals(priv!!.publicKey(), pub)
val sig1 = Crypto.sign(message!!.toByteArray(), priv)
assertEquals(sig1, sig)
val pub1 = Crypto.recoverPublicKey(sig1, message.toByteArray(), recid)
assertEquals(pub1, pub)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package fr.acinq.bitcoin

import fr.acinq.bitcoin.MnemonicCode.toMnemonics
import fr.acinq.bitcoin.MnemonicCode.toSeed
import fr.acinq.bitcoin.reference.TransactionTestsCommon
import fr.acinq.secp256k1.Hex
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
Expand All @@ -42,7 +41,7 @@ class MnemonicCodeTestsCommon {

@Test
fun `reference tests`() {
val tests = TransactionTestsCommon.readData("bip39_vectors.json")
val tests = TestHelpers.readResourceAsJson("bip39_vectors.json")

tests.jsonObject["english"]!!.jsonArray.map {
val raw = it.jsonArray[0].jsonPrimitive.content
Expand Down
14 changes: 2 additions & 12 deletions src/commonTest/kotlin/fr/acinq/bitcoin/TaprootTestsCommon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,8 @@ import fr.acinq.bitcoin.Bech32.hrp
import fr.acinq.bitcoin.Bitcoin.addressToPublicKeyScript
import fr.acinq.bitcoin.Transaction.Companion.hashForSigningSchnorr
import fr.acinq.bitcoin.io.ByteArrayInput
import fr.acinq.bitcoin.io.ByteArrayOutput
import fr.acinq.bitcoin.reference.TransactionTestsCommon.Companion.resourcesDir
import fr.acinq.secp256k1.Hex
import fr.acinq.secp256k1.Secp256k1
import org.kodein.memory.file.openReadableFile
import org.kodein.memory.file.resolve
import kotlin.test.*

class TaprootTestsCommon {
Expand Down Expand Up @@ -356,10 +352,7 @@ class TaprootTestsCommon {
@Test
fun `parse and validate huge transaction`() {
// this is the tx that broke btcd/lnd
val file = resourcesDir().resolve("7393096d97bfee8660f4100ffd61874d62f9a65de9fb6acf740c4c386990ef73.bin").openReadableFile()
val buffer = ByteArray(file.size)
file.readBytes(buffer, 0, buffer.size)
file.close()
val buffer = TestHelpers.readResourceAsByteArray("7393096d97bfee8660f4100ffd61874d62f9a65de9fb6acf740c4c386990ef73.bin")
val tx = Transaction.read(buffer)
assertEquals(1001, tx.txIn[0].witness.stack.size)
val parentTx = Transaction.read(
Expand Down Expand Up @@ -408,10 +401,7 @@ class TaprootTestsCommon {

@Test
fun `parse and validate large ordinals transaction`() {
val file = resourcesDir().resolve("b5a7e05f28d00e4a791759ad7b6bd6799d856693293ceeaad9b0bb93c8851f7f.bin").openReadableFile()
val buffer = ByteArray(file.size)
file.readBytes(buffer, 0, buffer.size)
file.close()
val buffer = TestHelpers.readResourceAsByteArray("b5a7e05f28d00e4a791759ad7b6bd6799d856693293ceeaad9b0bb93c8851f7f.bin")
val tx = Transaction.read(buffer)
val parentTx = Transaction.read(
"0100000000010273721ae5e7d59775f7104670fc8f74e9dee6fe57de47a2ebc14c95cafe4241050000000000fdffffff73721ae5e7d59775f7104670fc8f74e9dee6fe57de47a2ebc14c95cafe4241050100000000fdffffff025459f00200000000225120ca991d5bfbc6840c7568146e305f9eb67d8650948b1f929e941659b2649195941ea50c000000000022512051bf94b8b1d63574a47847d5fdccf2c90953189fa0220cf8f2d6284cf60e5f820140a844d30c2231d6e9c370b094200004475f21545efbd548a6f374ea956e2eea51d62d7048350130bc2fca3a5517ffe34d9e02d150ac58aba2920c88acb3cfc7fe014089d904d0be731c542ef9fe623b19502483348b1b6e0c9058e31c5ebd755070a27aa7dea288b839e2853da70607ea35851394f887e71c1ed58f15bf661969aa5900000000"
Expand Down
26 changes: 26 additions & 0 deletions src/commonTest/kotlin/fr/acinq/bitcoin/TestHelpers.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package fr.acinq.bitcoin

import kotlinx.io.buffered
import kotlinx.io.files.Path
import kotlinx.io.files.SystemFileSystem
import kotlinx.io.readByteArray
import kotlinx.io.readString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement

object TestHelpers {
val resourcesPath = Path(readEnvironmentVariable("TEST_RESOURCES_PATH")?: "src/commonTest/resources")

fun readResourceAsJson(filename: String): JsonElement {
val raw = SystemFileSystem.source(Path(resourcesPath, filename)).buffered().readString()
val format = Json { ignoreUnknownKeys = true }
return format.parseToJsonElement(raw)
}


fun readResourceAsByteArray(filename: String): ByteArray {
return SystemFileSystem.source(Path(resourcesPath, filename)).buffered().readByteArray()
}
}

expect fun readEnvironmentVariable(name: String): String?
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import kotlin.test.*
class Musig2TestsCommon {
@Test
fun `aggregate public keys`() {
val tests = TransactionTestsCommon.readData("musig2/key_agg_vectors.json")
val tests = TestHelpers.readResourceAsJson("musig2/key_agg_vectors.json")
val pubkeys = tests.jsonObject["pubkeys"]!!.jsonArray.map { PublicKey(ByteVector(it.jsonPrimitive.content)) }
val tweaks = tests.jsonObject["tweaks"]!!.jsonArray.map { ByteVector32.fromValidHex(it.jsonPrimitive.content) }

Expand Down Expand Up @@ -58,7 +58,7 @@ class Musig2TestsCommon {

@Test
fun `generate secret nonce`() {
val tests = TransactionTestsCommon.readData("musig2/nonce_gen_vectors.json")
val tests = TestHelpers.readResourceAsJson("musig2/nonce_gen_vectors.json")
tests.jsonObject["test_cases"]!!.jsonArray.forEach {
val randprime = ByteVector32.fromValidHex(it.jsonObject["rand_"]!!.jsonPrimitive.content)
val sk = it.jsonObject["sk"]?.jsonPrimitive?.contentOrNull?.let { PrivateKey.fromHex(it) }
Expand All @@ -85,7 +85,7 @@ class Musig2TestsCommon {

@Test
fun `aggregate nonces`() {
val tests = TransactionTestsCommon.readData("musig2/nonce_agg_vectors.json")
val tests = TestHelpers.readResourceAsJson("musig2/nonce_agg_vectors.json")
val nonces = tests.jsonObject["pnonces"]!!.jsonArray.map { IndividualNonce(it.jsonPrimitive.content) }
tests.jsonObject["valid_test_cases"]!!.jsonArray.forEach {
val nonceIndices = it.jsonObject["pnonce_indices"]!!.jsonArray.map { it.jsonPrimitive.int }
Expand All @@ -102,7 +102,7 @@ class Musig2TestsCommon {

@Test
fun sign() {
val tests = TransactionTestsCommon.readData("musig2/sign_verify_vectors.json")
val tests = TestHelpers.readResourceAsJson("musig2/sign_verify_vectors.json")
val sk = PrivateKey.fromHex(tests.jsonObject["sk"]!!.jsonPrimitive.content)
val pubkeys = tests.jsonObject["pubkeys"]!!.jsonArray.map { PublicKey(ByteVector(it.jsonPrimitive.content)) }
val secnonces = tests.jsonObject["secnonces"]!!.jsonArray.map { deserializeSecretNonce(it.jsonPrimitive.content) }
Expand Down Expand Up @@ -148,7 +148,7 @@ class Musig2TestsCommon {

@Test
fun `aggregate signatures`() {
val tests = TransactionTestsCommon.readData("musig2/sig_agg_vectors.json")
val tests = TestHelpers.readResourceAsJson("musig2/sig_agg_vectors.json")
val pubkeys = tests.jsonObject["pubkeys"]!!.jsonArray.map { PublicKey(ByteVector(it.jsonPrimitive.content)) }
val pnonces = tests.jsonObject["pnonces"]!!.jsonArray.map { IndividualNonce(it.jsonPrimitive.content) }
val tweaks = tests.jsonObject["tweaks"]!!.jsonArray.map { ByteVector32.fromValidHex(it.jsonPrimitive.content) }
Expand Down Expand Up @@ -193,7 +193,7 @@ class Musig2TestsCommon {

@Test
fun `tweak tests`() {
val tests = TransactionTestsCommon.readData("musig2/tweak_vectors.json")
val tests = TestHelpers.readResourceAsJson("musig2/tweak_vectors.json")
val sk = PrivateKey.fromHex(tests.jsonObject["sk"]!!.jsonPrimitive.content)
val pubkeys = tests.jsonObject["pubkeys"]!!.jsonArray.map { PublicKey(ByteVector(it.jsonPrimitive.content)) }
val pnonces = tests.jsonObject["pnonces"]!!.jsonArray.map { IndividualNonce(it.jsonPrimitive.content) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import kotlin.test.assertNotNull
class BIP341TestsCommon {
@Test
fun `BIP341 reference tests -- key path spending`() {
val tests = TransactionTestsCommon.readData("data/bip341_wallet_vectors.json").jsonObject["keyPathSpending"]!!
val tests = TestHelpers.readResourceAsJson("data/bip341_wallet_vectors.json").jsonObject["keyPathSpending"]!!
tests.jsonArray.forEach { it ->
val fullySignedTx = Transaction.read(it.jsonObject["auxiliary"]!!.jsonObject["fullySignedTx"]!!.jsonPrimitive.content)
val rawUnsignedTx = Transaction.read(it.jsonObject["given"]!!.jsonObject["rawUnsignedTx"]!!.jsonPrimitive.content)
Expand Down Expand Up @@ -78,7 +78,7 @@ class BIP341TestsCommon {

@Test
fun `BIP341 reference tests -- script path spending`() {
val tests = TransactionTestsCommon.readData("data/bip341_wallet_vectors.json").jsonObject["scriptPubKey"]!!
val tests = TestHelpers.readResourceAsJson("data/bip341_wallet_vectors.json").jsonObject["scriptPubKey"]!!
tests.jsonArray.forEach { it ->
val given = it.jsonObject["given"]!!.jsonObject
val internalPubkey = XonlyPublicKey(ByteVector32.fromValidHex(given["internalPubkey"]!!.jsonPrimitive.content))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package fr.acinq.bitcoin.reference

import fr.acinq.bitcoin.Base58
import fr.acinq.bitcoin.Base58Check
import fr.acinq.bitcoin.TestHelpers
import fr.acinq.secp256k1.Hex
import kotlinx.serialization.json.boolean
import kotlinx.serialization.json.jsonArray
Expand All @@ -29,7 +30,7 @@ import kotlin.test.assertEquals
class Base58ReferenceTestsCommon {
@Test
fun `reference encode-decode test`() {
val tests = TransactionTestsCommon.readData("data/base58_encode_decode.json")
val tests = TestHelpers.readResourceAsJson("data/base58_encode_decode.json")
tests.jsonArray.filter { it.jsonArray.size == 2 }.map { it.jsonArray }.forEach {
val hex = it[0].jsonPrimitive.content
val expected = it[1].jsonPrimitive.content
Expand All @@ -41,7 +42,7 @@ class Base58ReferenceTestsCommon {

@Test
fun `reference valid keys test`() {
val tests = TransactionTestsCommon.readData("data/base58_keys_valid.json")
val tests = TestHelpers.readResourceAsJson("data/base58_keys_valid.json")
tests.jsonArray.forEach {
val base58: String = it.jsonArray[0].jsonPrimitive.content
val (version, data) = Base58Check.decode(base58)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import kotlin.test.assertTrue
class KeyEncodingTestsCommon {
@Test
fun `valid keys`() {
val tests = TransactionTestsCommon.readData("data/key_io_valid.json")
val tests = TestHelpers.readResourceAsJson("data/key_io_valid.json")
tests.jsonArray.filter { it.jsonArray.size == 3 }.map { it.jsonArray }.forEach {
var encoded: String = it[0].jsonPrimitive.content
val hex: String = it[1].jsonPrimitive.content
Expand Down Expand Up @@ -94,7 +94,7 @@ class KeyEncodingTestsCommon {

@Test
fun `invalid keys`() {
val tests = TransactionTestsCommon.readData("data/key_io_invalid.json")
val tests = TestHelpers.readResourceAsJson("data/key_io_invalid.json")
tests.jsonArray.forEach {
val value = it.jsonArray[0].jsonPrimitive.content
assertTrue(!isValidBase58(value))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class ScriptTestsCommon {
@Test
fun `reference client script test`() {
// ["Format is: [[wit..., amount]?, scriptSig, scriptPubKey, flags, expected_scripterror, ... comments]"]
val tests = TransactionTestsCommon.readData("data/script_tests.json")
val tests = TestHelpers.readResourceAsJson("data/script_tests.json")
var count = 0
tests.jsonArray.filter { it.jsonArray.size >= 4 }.forEach {
runTest(it.jsonArray)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,20 @@

package fr.acinq.bitcoin.reference

import fr.acinq.bitcoin.TestHelpers
import fr.acinq.bitcoin.Transaction
import fr.acinq.secp256k1.Hex
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.int
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonPrimitive
import org.kodein.memory.file.openReadableFile
import org.kodein.memory.file.resolve
import org.kodein.memory.text.readString
import org.kodein.memory.use
import kotlin.test.Test
import kotlin.test.assertEquals

class SigHashTestsCommon {

@Test
fun `reference client sighash test`() {
val file = TransactionTestsCommon.resourcesDir().resolve("data/sighash.json")
val raw = file.openReadableFile().use { it.readString() }
val format = Json { ignoreUnknownKeys = true }
val json = format.parseToJsonElement(raw)
val json = TestHelpers.readResourceAsJson("data/sighash.json")
// ["raw_transaction, script, input_index, hashType, signature_hash (result)"],
json.jsonArray.filter { it.jsonArray.size == 5 }.map { it.jsonArray }.forEach {
val rawTx = it[0].jsonPrimitive.content
Expand Down
Loading
Loading