diff --git a/common/mock-enclave/src/main/kotlin/com/r3/conclave/encryptedtx/dto/VerifiableTxAndDependencies.kt b/common/mock-enclave/src/main/kotlin/com/r3/conclave/encryptedtx/dto/VerifiableTxAndDependencies.kt new file mode 100644 index 0000000000..2898bc4426 --- /dev/null +++ b/common/mock-enclave/src/main/kotlin/com/r3/conclave/encryptedtx/dto/VerifiableTxAndDependencies.kt @@ -0,0 +1,10 @@ +package com.r3.conclave.encryptedtx.dto + +import net.corda.core.serialization.CordaSerializable +import net.corda.core.transactions.EncryptedTransaction + +@CordaSerializable +data class VerifiableTxAndDependencies( + val conclaveLedgerTxModel: ConclaveLedgerTxModel, + val dependencies: Set +) \ No newline at end of file diff --git a/common/mock-enclave/src/main/kotlin/com/r3/conclave/encryptedtx/enclave/EncryptedTxEnclave.kt b/common/mock-enclave/src/main/kotlin/com/r3/conclave/encryptedtx/enclave/EncryptedTxEnclave.kt index 1d9e92a3fe..938939e613 100644 --- a/common/mock-enclave/src/main/kotlin/com/r3/conclave/encryptedtx/enclave/EncryptedTxEnclave.kt +++ b/common/mock-enclave/src/main/kotlin/com/r3/conclave/encryptedtx/enclave/EncryptedTxEnclave.kt @@ -1,4 +1,70 @@ package com.r3.conclave.encryptedtx.enclave +import com.github.benmanes.caffeine.cache.Caffeine +import com.r3.conclave.encryptedtx.dto.ConclaveLedgerTxModel +import com.r3.conclave.encryptedtx.dto.VerifiableTxAndDependencies +import net.corda.core.crypto.Crypto +import net.corda.core.crypto.SignableData +import net.corda.core.crypto.SignatureMetadata +import net.corda.core.crypto.sign +import net.corda.core.transactions.EncryptedTransaction +import net.corda.core.utilities.ByteSequence +import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme +import net.corda.serialization.internal.AMQP_P2P_CONTEXT +import net.corda.serialization.internal.SerializationFactoryImpl +import net.corda.serialization.internal.amqp.SerializationFactoryCacheKey +import net.corda.serialization.internal.amqp.SerializerFactory + class EncryptedTxEnclave { + + private val keyPair = Crypto.generateKeyPair("ECDSA_SECP256K1_SHA256") + private val signatureMetadata = SignatureMetadata( + platformVersion = 1, + schemeNumberID = Crypto.findSignatureScheme(keyPair.public).schemeNumberID + ) + + private val serializerFactoriesForContexts = Caffeine.newBuilder() + .maximumSize(128) + .build() + .asMap() + + private val serializationFactoryImpl: SerializationFactoryImpl + + init { + val serverScheme = AMQPServerSerializationScheme(emptyList(), serializerFactoriesForContexts) + val clientScheme = AMQPServerSerializationScheme(emptyList(), serializerFactoriesForContexts) + + serializationFactoryImpl = SerializationFactoryImpl().apply { + registerScheme(serverScheme) + registerScheme(clientScheme) + } + } + + fun encryptSignedTx(ledgerTxBytes: ByteArray): EncryptedTransaction { + val ledgerTxModel = serializationFactoryImpl.deserialize( + byteSequence = ByteSequence.of(ledgerTxBytes, 0, ledgerTxBytes.size), + clazz = ConclaveLedgerTxModel::class.java, + context = AMQP_P2P_CONTEXT + ) + + val signedTransaction = ledgerTxModel.signedTransaction + val signableData = SignableData(signedTransaction.id, signatureMetadata) + val transactionSignature = keyPair.sign(signableData) + + return EncryptedTransaction( + id = signedTransaction.id, + encryptedBytes = ledgerTxBytes, + dependencies = emptySet(), + sigs = listOf(transactionSignature) + ) + } + + fun verifyTx(txAndDependenciesBytes: ByteArray) { + val txAndDependencies = serializationFactoryImpl.deserialize( + byteSequence = ByteSequence.of(txAndDependenciesBytes, 0, txAndDependenciesBytes.size), + clazz = VerifiableTxAndDependencies::class.java, + context = AMQP_P2P_CONTEXT) + + // TODO: add verification + } } \ No newline at end of file diff --git a/common/mock-enclave/src/test/kotlin/com/r3/conclave/encryptedtx/EncryptedTxEnclaveTest.kt b/common/mock-enclave/src/test/kotlin/com/r3/conclave/encryptedtx/EncryptedTxEnclaveTest.kt new file mode 100644 index 0000000000..15c03f68c9 --- /dev/null +++ b/common/mock-enclave/src/test/kotlin/com/r3/conclave/encryptedtx/EncryptedTxEnclaveTest.kt @@ -0,0 +1,110 @@ +package com.r3.conclave.encryptedtx + +import com.github.benmanes.caffeine.cache.Caffeine +import com.r3.conclave.encryptedtx.dto.ConclaveLedgerTxModel +import com.r3.conclave.encryptedtx.dto.VerifiableTxAndDependencies +import com.r3.conclave.encryptedtx.enclave.EncryptedTxEnclave +import net.corda.core.identity.Party +import net.corda.core.node.ServiceHub +import net.corda.core.serialization.serialize +import net.corda.core.transactions.SignedTransaction +import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.getOrThrow +import net.corda.finance.DOLLARS +import net.corda.finance.flows.CashIssueFlow +import net.corda.finance.flows.CashPaymentFlow +import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme +import net.corda.serialization.internal.SerializationFactoryImpl +import net.corda.serialization.internal.amqp.SerializationFactoryCacheKey +import net.corda.serialization.internal.amqp.SerializerFactory +import net.corda.testing.core.* +import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin +import net.corda.testing.node.MockNetwork +import net.corda.testing.node.MockNetworkParameters +import net.corda.testing.node.StartedMockNode +import net.corda.testing.node.internal.FINANCE_CORDAPPS +import org.junit.After +import org.junit.Before +import org.junit.Test + +class EncryptedTxEnclaveTest { + + private lateinit var mockNet: MockNetwork + private val initialBalance = 2000.DOLLARS + private val ref = OpaqueBytes.of(0x01) + + private lateinit var bankOfCordaNode: StartedMockNode + private lateinit var bankOfCorda: Party + + private lateinit var aliceNode: StartedMockNode + private lateinit var bobNode: StartedMockNode + + private val serializerFactoriesForContexts = Caffeine.newBuilder() + .maximumSize(128) + .build() + .asMap() + + private lateinit var serializationFactoryImpl: SerializationFactoryImpl + + private val encryptedTxEnclave = EncryptedTxEnclave() + + @Before + fun start() { + mockNet = MockNetwork(MockNetworkParameters(servicePeerAllocationStrategy = RoundRobin(), cordappsForAllNodes = FINANCE_CORDAPPS)) + bankOfCordaNode = mockNet.createPartyNode(BOC_NAME) + bankOfCorda = bankOfCordaNode.info.identityFromX500Name(BOC_NAME) + + aliceNode = mockNet.createPartyNode(ALICE_NAME) + bobNode = mockNet.createPartyNode(BOB_NAME) + + val serverScheme = AMQPServerSerializationScheme(emptyList(), serializerFactoriesForContexts) + val clientScheme = AMQPServerSerializationScheme(emptyList(), serializerFactoriesForContexts) + + serializationFactoryImpl = SerializationFactoryImpl().apply { + registerScheme(serverScheme) + registerScheme(clientScheme) + } + } + + @After + fun cleanUp() { + mockNet.stopNodes() + } + + @Test(timeout=300_000) + fun `pay some cash`() { + val payTo = aliceNode.info.singleIdentity() + val expectedPayment = 500.DOLLARS + + var future = bankOfCordaNode.startFlow(CashIssueFlow(initialBalance, ref, mockNet.defaultNotaryIdentity)) + val issuanceStx = future.getOrThrow().stx + + val issuanceConclaveLedgerTxBytes = issuanceStx + .toLedgerTxModel(bankOfCordaNode.services) + .serialize(serializationFactoryImpl) + .bytes + + val encryptedTx = encryptedTxEnclave.encryptSignedTx(issuanceConclaveLedgerTxBytes) + + future = bankOfCordaNode.startFlow(CashPaymentFlow(expectedPayment, payTo)) + mockNet.runNetwork() + val paymentStx = future.getOrThrow().stx + + val ledgerTxModel = paymentStx.toLedgerTxModel(bankOfCordaNode.services) + val txAndDependenciesBytes = VerifiableTxAndDependencies(ledgerTxModel, setOf(encryptedTx)).serialize() + + encryptedTxEnclave.verifyTx(txAndDependenciesBytes.bytes) + } + + private fun SignedTransaction.toLedgerTxModel(services: ServiceHub): ConclaveLedgerTxModel { + val ledgerTx = this.toLedgerTransaction(services) + + return ConclaveLedgerTxModel( + signedTransaction = this, + inputStates = ledgerTx.inputs.toTypedArray(), + attachments = ledgerTx.attachments.toTypedArray(), + networkParameters = ledgerTx.networkParameters!!, + references = ledgerTx.references.toTypedArray() + ) + } +}