mirror of
https://github.com/corda/corda.git
synced 2024-12-30 09:48:59 +00:00
commit
cb1b274d5c
core
docs/source
@ -67,6 +67,9 @@ dependencies {
|
||||
// For JSON
|
||||
compile "com.fasterxml.jackson.core:jackson-databind:2.5.5"
|
||||
|
||||
// Java ed25519 implementation. See https://github.com/str4d/ed25519-java/
|
||||
compile 'net.i2p.crypto:eddsa:0.1.0'
|
||||
|
||||
// Quasar: for the bytecode rewriting for state machines.
|
||||
quasar "co.paralleluniverse:quasar-core:${quasar_version}:jdk8@jar"
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
package com.r3corda.core.crypto
|
||||
|
||||
import com.google.common.io.BaseEncoding
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.serialization.OpaqueBytes
|
||||
import com.r3corda.core.serialization.SerializedBytes
|
||||
import com.r3corda.core.serialization.deserialize
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import java.math.BigInteger
|
||||
import java.security.*
|
||||
import java.security.interfaces.ECPublicKey
|
||||
import net.i2p.crypto.eddsa.KeyPairGenerator as EddsaKeyPairGenerator
|
||||
|
||||
// "sealed" here means there can't be any subclasses other than the ones defined here.
|
||||
sealed class SecureHash private constructor(bits: ByteArray) : OpaqueBytes(bits) {
|
||||
@ -118,7 +119,7 @@ class DummyPublicKey(val s: String) : PublicKey, Comparable<PublicKey> {
|
||||
|
||||
/** Utility to simplify the act of signing a byte array */
|
||||
fun PrivateKey.signWithECDSA(bits: ByteArray): DigitalSignature {
|
||||
val signer = Signature.getInstance("SHA256withECDSA")
|
||||
val signer = EdDSAEngine()
|
||||
signer.initSign(this)
|
||||
signer.update(bits)
|
||||
val sig = signer.sign()
|
||||
@ -140,7 +141,7 @@ fun KeyPair.signWithECDSA(bitsToSign: ByteArray, party: Party): DigitalSignature
|
||||
|
||||
/** Utility to simplify the act of verifying a signature */
|
||||
fun PublicKey.verifyWithECDSA(content: ByteArray, signature: DigitalSignature) {
|
||||
val verifier = Signature.getInstance("SHA256withECDSA")
|
||||
val verifier = EdDSAEngine()
|
||||
verifier.initVerify(this)
|
||||
verifier.update(content)
|
||||
if (verifier.verify(signature.bits) == false)
|
||||
@ -160,4 +161,4 @@ operator fun KeyPair.component1() = this.private
|
||||
operator fun KeyPair.component2() = this.public
|
||||
|
||||
/** A simple wrapper that will make it easier to swap out the EC algorithm we use in future */
|
||||
fun generateKeyPair() = KeyPairGenerator.getInstance("EC").genKeyPair()
|
||||
fun generateKeyPair() = EddsaKeyPairGenerator().generateKeyPair()
|
@ -17,6 +17,11 @@ import com.r3corda.core.crypto.sha256
|
||||
import com.r3corda.core.node.AttachmentsClassLoader
|
||||
import com.r3corda.core.node.services.AttachmentStorage
|
||||
import de.javakaffee.kryoserializers.ArraysAsListSerializer
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec
|
||||
import org.objenesis.strategy.StdInstantiatorStrategy
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.ObjectInputStream
|
||||
@ -29,6 +34,7 @@ import java.util.*
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.javaType
|
||||
import java.security.PrivateKey
|
||||
|
||||
/**
|
||||
* Serialization utilities, using the Kryo framework with a custom serialiser for immutable data classes and a dead
|
||||
@ -205,6 +211,16 @@ inline fun <T> Kryo.useClassLoader(cl: ClassLoader, body: () -> T) : T {
|
||||
}
|
||||
}
|
||||
|
||||
inline fun Output.writeBytesWithLength(byteArray: ByteArray) {
|
||||
this.writeInt(byteArray.size, true)
|
||||
this.writeBytes(byteArray)
|
||||
}
|
||||
|
||||
inline fun Input.readBytesWithLength(): ByteArray {
|
||||
val size = this.readInt(true)
|
||||
return this.readBytes(size)
|
||||
}
|
||||
|
||||
/** Thrown during deserialisation to indicate that an attachment needed to construct the [WireTransaction] is not found */
|
||||
class MissingAttachmentsException(val ids: List<SecureHash>) : Exception()
|
||||
|
||||
@ -250,6 +266,39 @@ object WireTransactionSerializer : Serializer<WireTransaction>() {
|
||||
}
|
||||
}
|
||||
|
||||
/** For serialising an ed25519 private key */
|
||||
@ThreadSafe
|
||||
object Ed25519PrivateKeySerializer : Serializer<EdDSAPrivateKey>() {
|
||||
val ed25519Curve = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512)
|
||||
|
||||
override fun write(kryo: Kryo, output: Output, obj: EdDSAPrivateKey) {
|
||||
check(obj.params == ed25519Curve)
|
||||
output.writeBytesWithLength(obj.seed)
|
||||
}
|
||||
|
||||
override fun read(kryo: Kryo, input: Input, type: Class<EdDSAPrivateKey>): EdDSAPrivateKey {
|
||||
val seed = input.readBytesWithLength()
|
||||
return EdDSAPrivateKey(EdDSAPrivateKeySpec(seed, ed25519Curve))
|
||||
}
|
||||
}
|
||||
|
||||
/** For serialising an ed25519 public key */
|
||||
@ThreadSafe
|
||||
object Ed25519PublicKeySerializer : Serializer<EdDSAPublicKey>() {
|
||||
val ed25519Curve = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512)
|
||||
|
||||
override fun write(kryo: Kryo, output: Output, obj: EdDSAPublicKey) {
|
||||
check(obj.params == ed25519Curve)
|
||||
output.writeBytesWithLength(obj.abyte)
|
||||
}
|
||||
|
||||
override fun read(kryo: Kryo, input: Input, type: Class<EdDSAPublicKey>): EdDSAPublicKey {
|
||||
val A = input.readBytesWithLength()
|
||||
return EdDSAPublicKey(EdDSAPublicKeySpec(A, ed25519Curve))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun createKryo(k: Kryo = Kryo()): Kryo {
|
||||
return k.apply {
|
||||
// Allow any class to be deserialized (this is insecure but for prototyping we don't care)
|
||||
@ -273,8 +322,8 @@ fun createKryo(k: Kryo = Kryo()): Kryo {
|
||||
|
||||
// Some things where the JRE provides an efficient custom serialisation.
|
||||
val keyPair = generateKeyPair()
|
||||
register(keyPair.public.javaClass, ReferencesAwareJavaSerializer)
|
||||
register(keyPair.private.javaClass, ReferencesAwareJavaSerializer)
|
||||
register(keyPair.public.javaClass, Ed25519PublicKeySerializer)
|
||||
register(keyPair.private.javaClass, Ed25519PrivateKeySerializer)
|
||||
register(Instant::class.java, ReferencesAwareJavaSerializer)
|
||||
|
||||
// Some classes have to be handled with the ImmutableClassSerializer because they need to have their
|
||||
|
@ -1,7 +1,11 @@
|
||||
package com.r3corda.core.serialization
|
||||
|
||||
import com.google.common.primitives.Ints
|
||||
import com.r3corda.core.crypto.generateKeyPair
|
||||
import com.r3corda.core.crypto.signWithECDSA
|
||||
import com.r3corda.core.crypto.verifyWithECDSA
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
@ -54,6 +58,21 @@ class KryoTests {
|
||||
assertThat(bits.deserialize(kryo)).isEqualTo(cyclic)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `deserialised keypair functions the same as serialised one`() {
|
||||
val keyPair = generateKeyPair()
|
||||
val bitsToSign: ByteArray = Ints.toByteArray(0x01234567)
|
||||
val wrongBits: ByteArray = Ints.toByteArray(0x76543210)
|
||||
val signature = keyPair.signWithECDSA(bitsToSign)
|
||||
signature.verifyWithECDSA(bitsToSign)
|
||||
assertThatThrownBy { signature.verifyWithECDSA(wrongBits) }
|
||||
|
||||
val deserialisedKeyPair = keyPair.serialize(kryo).deserialize(kryo)
|
||||
val deserialisedSignature = deserialisedKeyPair.signWithECDSA(bitsToSign)
|
||||
assertThat(deserialisedSignature).isEqualTo(signature)
|
||||
deserialisedSignature.verifyWithECDSA(bitsToSign)
|
||||
assertThatThrownBy { deserialisedSignature.verifyWithECDSA(wrongBits) }
|
||||
}
|
||||
|
||||
private data class Person(val name: String, val birthday: Instant?)
|
||||
|
||||
@ -65,4 +84,4 @@ class KryoTests {
|
||||
override fun toString(): String = "Cyclic($value)"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ Here are changes in git master that haven't yet made it to a snapshot release:
|
||||
* Amount class is now generic, to support non-currency types (such as assets, or currency with additional information).
|
||||
* Refactored the Cash contract to have a new FungibleAsset superclass, to model all countable assets that can be merged
|
||||
and split (currency, barrels of oil, etc.)
|
||||
|
||||
* Switched to the ed25519 elliptic curve from secp256r1. Note that this introduces a new external lib dependency.
|
||||
|
||||
Milestone 0
|
||||
-----------
|
||||
@ -24,4 +24,4 @@ This is the first release, which includes:
|
||||
* The first version of the protocol/orchestration framework
|
||||
* Some initial support for pluggable consensus mechanisms
|
||||
* Tutorials and documentation explaining how it works
|
||||
* Much more ...
|
||||
* Much more ...
|
||||
|
Loading…
Reference in New Issue
Block a user