mirror of
https://github.com/corda/corda.git
synced 2025-06-23 01:19:00 +00:00
Backward compatible fix for Merkle tree case where a single leaf becomes the tree root (#6895)
This commit is contained in:
@ -37,19 +37,19 @@ sealed class MerkleTree {
|
||||
require(algorithms.size == 1) {
|
||||
"Cannot build Merkle tree with multiple hash algorithms: $algorithms"
|
||||
}
|
||||
val leaves = padWithZeros(allLeavesHashes).map { Leaf(it) }
|
||||
val leaves = padWithZeros(allLeavesHashes, nodeDigestService.hashAlgorithm == SecureHash.SHA2_256).map { Leaf(it) }
|
||||
return buildMerkleTree(leaves, nodeDigestService)
|
||||
}
|
||||
|
||||
// If number of leaves in the tree is not a power of 2, we need to pad it with zero hashes.
|
||||
private fun padWithZeros(allLeavesHashes: List<SecureHash>): List<SecureHash> {
|
||||
private fun padWithZeros(allLeavesHashes: List<SecureHash>, singleLeafWithoutPadding: Boolean): List<SecureHash> {
|
||||
var n = allLeavesHashes.size
|
||||
if (isPow2(n)) return allLeavesHashes
|
||||
if (isPow2(n) && (n > 1 || singleLeafWithoutPadding)) return allLeavesHashes
|
||||
val paddedHashes = ArrayList(allLeavesHashes)
|
||||
val zeroHash = SecureHash.zeroHashFor(paddedHashes[0].algorithm)
|
||||
while (!isPow2(n++)) {
|
||||
do {
|
||||
paddedHashes.add(zeroHash)
|
||||
}
|
||||
} while (!isPow2(++n))
|
||||
return paddedHashes
|
||||
}
|
||||
|
||||
|
@ -1,33 +1,19 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.crypto.internal.DigestAlgorithmFactory
|
||||
import org.bouncycastle.crypto.digests.Blake2sDigest
|
||||
import net.corda.core.internal.BLAKE2s256DigestAlgorithm
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class Blake2s256DigestServiceTest {
|
||||
class BLAKE2s256DigestService : DigestAlgorithm {
|
||||
override val algorithm = "BLAKE_TEST"
|
||||
|
||||
override val digestLength = 32
|
||||
|
||||
override fun digest(bytes: ByteArray): ByteArray {
|
||||
val blake2s256 = Blake2sDigest(null, digestLength, null, "12345678".toByteArray())
|
||||
blake2s256.reset()
|
||||
blake2s256.update(bytes, 0, bytes.size)
|
||||
val hash = ByteArray(digestLength)
|
||||
blake2s256.doFinal(hash, 0)
|
||||
return hash
|
||||
}
|
||||
}
|
||||
|
||||
private val service = DigestService("BLAKE_TEST")
|
||||
|
||||
@Before
|
||||
fun before() {
|
||||
DigestAlgorithmFactory.registerClass(BLAKE2s256DigestService::class.java.name)
|
||||
DigestAlgorithmFactory.registerClass(BLAKE2s256DigestAlgorithm::class.java.name)
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
|
@ -0,0 +1,36 @@
|
||||
package net.corda.core.internal
|
||||
|
||||
import net.corda.core.crypto.DigestAlgorithm
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import org.bouncycastle.crypto.digests.Blake2sDigest
|
||||
|
||||
/**
|
||||
* A set of custom hash algorithms
|
||||
*/
|
||||
|
||||
open class BLAKE2s256DigestAlgorithm : DigestAlgorithm {
|
||||
override val algorithm = "BLAKE_TEST"
|
||||
|
||||
override val digestLength = 32
|
||||
|
||||
protected fun blake2sHash(bytes: ByteArray): ByteArray {
|
||||
val blake2s256 = Blake2sDigest(null, digestLength, null, "12345678".toByteArray())
|
||||
blake2s256.reset()
|
||||
blake2s256.update(bytes, 0, bytes.size)
|
||||
val hash = ByteArray(digestLength)
|
||||
blake2s256.doFinal(hash, 0)
|
||||
return hash
|
||||
}
|
||||
|
||||
override fun digest(bytes: ByteArray): ByteArray = blake2sHash(bytes)
|
||||
}
|
||||
|
||||
class SHA256BLAKE2s256DigestAlgorithm : BLAKE2s256DigestAlgorithm() {
|
||||
override val algorithm = "SHA256-BLAKE2S256-TEST"
|
||||
|
||||
override fun digest(bytes: ByteArray): ByteArray = SecureHash.hashAs(SecureHash.SHA2_256, bytes).bytes
|
||||
|
||||
override fun componentDigest(bytes: ByteArray): ByteArray = blake2sHash(bytes)
|
||||
|
||||
override fun nonceDigest(bytes: ByteArray): ByteArray = blake2sHash(bytes)
|
||||
}
|
@ -18,6 +18,7 @@ fun WireTransaction.accessGroupHashes() = this.groupHashes
|
||||
|
||||
fun WireTransaction.accessGroupMerkleRoots() = this.groupsMerkleRoots
|
||||
fun WireTransaction.accessAvailableComponentHashes() = this.availableComponentHashes
|
||||
fun WireTransaction.accessAvailableComponentNonces() = this.availableComponentNonces
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
fun createLedgerTransaction(
|
||||
|
Reference in New Issue
Block a user