diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt index 7a93ac0c03..a34cd9f158 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Cash.kt @@ -8,6 +8,7 @@ import com.r3corda.core.contracts.clauses.* import com.r3corda.core.crypto.* import com.r3corda.core.node.services.Wallet import com.r3corda.core.utilities.Emoji +import java.math.BigInteger import java.security.PublicKey import java.util.* @@ -334,7 +335,7 @@ infix fun Cash.State.`with deposit`(deposit: PartyAndReference): Cash.State = wi // Unit testing helpers. These could go in a separate file but it's hardly worth it for just a few functions. /** A randomly generated key. */ -val DUMMY_CASH_ISSUER_KEY by lazy { generateKeyPair() } +val DUMMY_CASH_ISSUER_KEY by lazy { entropyToKeyPair(BigInteger.valueOf(10)) } /** A dummy, randomly generated issuer party by the name of "Snake Oil Issuer" */ val DUMMY_CASH_ISSUER by lazy { Party("Snake Oil Issuer", DUMMY_CASH_ISSUER_KEY.public).ref(1) } /** An extension property that lets you write 100.DOLLARS.CASH */ diff --git a/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt b/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt index 1bace21711..f7682c03e2 100644 --- a/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt +++ b/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt @@ -5,10 +5,14 @@ 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 net.i2p.crypto.eddsa.EdDSAPrivateKey import net.i2p.crypto.eddsa.EdDSAPublicKey +import net.i2p.crypto.eddsa.KeyPairGenerator +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable +import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec +import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec import java.math.BigInteger import java.security.* -import net.i2p.crypto.eddsa.KeyPairGenerator as EddsaKeyPairGenerator fun newSecureRandom(): SecureRandom { if (System.getProperty("os.name") == "Linux") { @@ -115,6 +119,7 @@ object NullPublicKey : PublicKey, Comparable { override fun toString() = "NULL_KEY" } +// TODO: Clean up this duplication between Null and Dummy public key class DummyPublicKey(val s: String) : PublicKey, Comparable { override fun getAlgorithm() = "DUMMY" override fun getEncoded() = s.toByteArray() @@ -125,6 +130,9 @@ class DummyPublicKey(val s: String) : PublicKey, Comparable { override fun toString() = "PUBKEY[$s]" } +/** A signature with a key and value of zero. Useful when you want a signature object that you know won't ever be used. */ +object NullSignature : DigitalSignature.WithKey(NullPublicKey, ByteArray(32)) + /** Utility to simplify the act of signing a byte array */ fun PrivateKey.signWithECDSA(bits: ByteArray): DigitalSignature { val signer = EdDSAEngine() @@ -163,10 +171,24 @@ fun PublicKey.toStringShort(): String { } ?: toString() } +fun Iterable.toStringsShort(): String = map { it.toStringShort() }.toString() + // Allow Kotlin destructuring: val (private, public) = keypair 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(): KeyPair = EddsaKeyPairGenerator().generateKeyPair() +fun generateKeyPair(): KeyPair = KeyPairGenerator().generateKeyPair() + +/** + * Returns a keypair derived from the given private key entropy. This is useful for unit tests and other cases where + * you want hard-coded private keys. + */ +fun entropyToKeyPair(entropy: BigInteger): KeyPair { + val params = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512) + val bits = entropy.toByteArray().copyOf(params.curve.field.getb() / 8) + val priv = EdDSAPrivateKeySpec(bits, params) + val pub = EdDSAPublicKeySpec(priv.a, params) + val key = KeyPair(EdDSAPublicKey(pub), EdDSAPrivateKey(priv)) + return key +} diff --git a/core/src/main/kotlin/com/r3corda/core/testing/CoreTestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/CoreTestUtils.kt index 704601cdec..1a80c1a024 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/CoreTestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/CoreTestUtils.kt @@ -7,14 +7,12 @@ import com.google.common.net.HostAndPort import com.r3corda.core.contracts.Attachment import com.r3corda.core.contracts.StateRef import com.r3corda.core.contracts.TransactionBuilder -import com.r3corda.core.crypto.DummyPublicKey -import com.r3corda.core.crypto.Party -import com.r3corda.core.crypto.SecureHash -import com.r3corda.core.crypto.generateKeyPair +import com.r3corda.core.crypto.* import com.r3corda.core.node.services.IdentityService import com.r3corda.core.node.services.StorageService import com.r3corda.core.node.services.testing.MockIdentityService import com.r3corda.core.node.services.testing.MockStorageService +import java.math.BigInteger import java.net.ServerSocket import java.security.KeyPair import java.security.PublicKey @@ -73,7 +71,7 @@ val CHARLIE: Party get() = Party("Charlie", CHARLIE_PUBKEY) val MEGA_CORP: Party get() = Party("MegaCorp", MEGA_CORP_PUBKEY) val MINI_CORP: Party get() = Party("MiniCorp", MINI_CORP_PUBKEY) -val DUMMY_NOTARY_KEY: KeyPair by lazy { generateKeyPair() } +val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) } val DUMMY_NOTARY: Party get() = Party("Notary Service", DUMMY_NOTARY_KEY.public) val ALL_TEST_KEYS: List get() = listOf(MEGA_CORP_KEY, MINI_CORP_KEY, ALICE_KEY, BOB_KEY, DUMMY_NOTARY_KEY)