NodeAndWeight deterministic comparator (#1003)

NodeAndWeight deterministic ordering by comparing hashes of public keys when required.
This commit is contained in:
Konstantinos Chalkias 2017-07-11 10:18:22 +01:00 committed by GitHub
parent 5b78863e57
commit d52b0e5db9
3 changed files with 25 additions and 6 deletions

View File

@ -4,6 +4,7 @@ import net.corda.core.crypto.CompositeKey.NodeAndWeight
import net.corda.core.serialization.CordaSerializable
import org.bouncycastle.asn1.*
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import java.nio.ByteBuffer
import java.security.PublicKey
import java.util.*
@ -109,11 +110,11 @@ class CompositeKey private constructor (val threshold: Int,
// We don't allow zero or negative weights. Minimum weight = 1.
require (weight > 0) { "A non-positive weight was detected. Node info: $this" }
}
override fun compareTo(other: NodeAndWeight): Int {
if (weight == other.weight) {
return node.hashCode().compareTo(other.node.hashCode())
}
else return weight.compareTo(other.weight)
return if (weight == other.weight) {
ByteBuffer.wrap(node.toSHA256Bytes()).compareTo(ByteBuffer.wrap(other.node.toSHA256Bytes()))
} else weight.compareTo(other.weight)
}
override fun toASN1Primitive(): ASN1Primitive {

View File

@ -65,4 +65,4 @@ fun String.hexToBase64(): String = hexToByteArray().toBase64()
// structure, e.g. mapping a PublicKey to a condition with the specific feature (ED25519).
fun parsePublicKeyBase58(base58String: String): PublicKey = base58String.base58ToByteArray().deserialize<PublicKey>()
fun PublicKey.toBase58String(): String = this.serialize().bytes.toBase58()
fun PublicKey.toSHA256Bytes(): ByteArray = this.serialize().bytes.sha256().bytes
fun PublicKey.toSHA256Bytes(): ByteArray = this.serialize().bytes.sha256().bytes // TODO: decide on the format of hashed key (encoded Vs serialised).

View File

@ -1,7 +1,7 @@
package net.corda.core.crypto
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.serialization.serialize
import net.corda.core.utilities.OpaqueBytes
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@ -259,4 +259,22 @@ class CompositeKeyTests {
val signaturesWithoutRSA = listOf(K1Signature, R1Signature, EdSignature, SPSignature)
assertFalse { compositeKey.isFulfilledBy(signaturesWithoutRSA.byKeys()) }
}
@Test
fun `CompositeKey deterministic children sorting`() {
val (_, pub1) = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
val (_, pub2) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
val (_, pub3) = Crypto.generateKeyPair(Crypto.RSA_SHA256)
val (_, pub4) = Crypto.generateKeyPair(Crypto.EDDSA_ED25519_SHA512)
val (_, pub5) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
val (_, pub6) = Crypto.generateKeyPair(Crypto.SPHINCS256_SHA256)
val (_, pub7) = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
// Using default weight = 1, thus all weights are equal.
val composite1 = CompositeKey.Builder().addKeys(pub1, pub2, pub3, pub4, pub5, pub6, pub7).build() as CompositeKey
// Store in reverse order.
val composite2 = CompositeKey.Builder().addKeys(pub7, pub6, pub5, pub4, pub3, pub2, pub1).build() as CompositeKey
// There are 7! = 5040 permutations, but as sorting is deterministic the following should never fail.
assertEquals(composite1.children, composite2.children)
}
}