diff --git a/.ci/api-current.txt b/.ci/api-current.txt index 947baa9ba7..56c3c79be5 100644 --- a/.ci/api-current.txt +++ b/.ci/api-current.txt @@ -1850,13 +1850,15 @@ public final class net.corda.core.crypto.CryptoUtils extends java.lang.Object public static final boolean verify(java.security.PublicKey, byte[], byte[]) ## public interface net.corda.core.crypto.DigestAlgorithm + @NotNull + public abstract byte[] componentDigest(byte[]) @NotNull public abstract byte[] digest(byte[]) @NotNull public abstract String getAlgorithm() public abstract int getDigestLength() @NotNull - public abstract byte[] preImageResistantDigest(byte[]) + public abstract byte[] nonceDigest(byte[]) ## @CordaSerializable public class net.corda.core.crypto.DigitalSignature extends net.corda.core.utilities.OpaqueBytes diff --git a/core/src/main/kotlin/net/corda/core/crypto/DigestAlgorithm.kt b/core/src/main/kotlin/net/corda/core/crypto/DigestAlgorithm.kt index ef6b6971b7..13610eba5e 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/DigestAlgorithm.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/DigestAlgorithm.kt @@ -25,8 +25,16 @@ interface DigestAlgorithm { fun digest(bytes: ByteArray): ByteArray /** - * Computes the digest of the [ByteArray] which is resistant to pre-image attacks. + * Computes the digest of the [ByteArray] which is resistant to pre-image attacks. Only used to calculate the hash of the leaves of the + * ComponentGroup Merkle tree, starting from its serialized components. * Default implementation provides double hashing, but can it be changed to single hashing or something else for better performance. */ - fun preImageResistantDigest(bytes: ByteArray): ByteArray = digest(digest(bytes)) + fun componentDigest(bytes: ByteArray): ByteArray = digest(digest(bytes)) + + /** + * Computes the digest of the [ByteArray] which is resistant to pre-image attacks. Only used to calculate the nonces for the leaves of + * the ComponentGroup Merkle tree. + * Default implementation provides double hashing, but can it be changed to single hashing or something else for better performance. + */ + fun nonceDigest(bytes: ByteArray): ByteArray = digest(digest(bytes)) } diff --git a/core/src/main/kotlin/net/corda/core/crypto/DigestService.kt b/core/src/main/kotlin/net/corda/core/crypto/DigestService.kt index 2f88e9d959..1ef3958b21 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/DigestService.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/DigestService.kt @@ -91,7 +91,7 @@ data class DigestService(val hashAlgorithm: String) { * otherwise it's defined by DigestAlgorithm.preImageResistantDigest(nonce || serializedComponent). */ fun componentHash(nonce: SecureHash, opaqueBytes: OpaqueBytes): SecureHash { val data = nonce.bytes + opaqueBytes.bytes - return SecureHash.preImageResistantHashAs(hashAlgorithm, data) + return SecureHash.componentHashAs(hashAlgorithm, data) } /** @@ -113,7 +113,7 @@ data class DigestService(val hashAlgorithm: String) { */ fun computeNonce(privacySalt: PrivacySalt, groupIndex: Int, internalIndex: Int) : SecureHash { val data = (privacySalt.bytes + ByteBuffer.allocate(NONCE_SIZE).putInt(groupIndex).putInt(internalIndex).array()) - return SecureHash.preImageResistantHashAs(hashAlgorithm, data) + return SecureHash.nonceHashAs(hashAlgorithm, data) } } diff --git a/core/src/main/kotlin/net/corda/core/crypto/SecureHash.kt b/core/src/main/kotlin/net/corda/core/crypto/SecureHash.kt index abee5a22f5..683d2610cc 100644 --- a/core/src/main/kotlin/net/corda/core/crypto/SecureHash.kt +++ b/core/src/main/kotlin/net/corda/core/crypto/SecureHash.kt @@ -216,13 +216,31 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) { * @param bytes The [ByteArray] to hash. */ @JvmStatic - fun preImageResistantHashAs(algorithm: String, bytes: ByteArray): SecureHash { + fun componentHashAs(algorithm: String, bytes: ByteArray): SecureHash { return if (algorithm == SHA2_256) { sha256Twice(bytes) } else { val digest = digestFor(algorithm).get() - val firstHash = digest.preImageResistantDigest(bytes) - HASH(algorithm, digest.digest(firstHash)) + val hash = digest.componentDigest(bytes) + HASH(algorithm, hash) + } + } + + /** + * Computes the digest of the [ByteArray] which is resistant to pre-image attacks. + * It computes the hash of the hash for SHA2-256 and other algorithms loaded via JCA [MessageDigest]. + * For custom algorithms the strategy can be modified via [DigestAlgorithm]. + * @param algorithm The [MessageDigest] algorithm to use. + * @param bytes The [ByteArray] to hash. + */ + @JvmStatic + fun nonceHashAs(algorithm: String, bytes: ByteArray): SecureHash { + return if (algorithm == SHA2_256) { + sha256Twice(bytes) + } else { + val digest = digestFor(algorithm).get() + val hash = digest.nonceDigest(bytes) + HASH(algorithm, hash) } } diff --git a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt index fbcb012d10..22bfb19be2 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/WireTransaction.kt @@ -318,7 +318,11 @@ class WireTransaction(componentGroups: List, val privacySalt: Pr * nothing about the rest. */ internal val availableComponentNonces: Map> by lazy { - componentGroups.associate { it.groupIndex to it.components.mapIndexed { internalIndex, internalIt -> digestService.componentHash(internalIt, privacySalt, it.groupIndex, internalIndex) } } + if(digestService.hashAlgorithm == SecureHash.SHA2_256) { + componentGroups.associate { it.groupIndex to it.components.mapIndexed { internalIndex, internalIt -> digestService.componentHash(internalIt, privacySalt, it.groupIndex, internalIndex) } } + } else { + componentGroups.associate { it.groupIndex to it.components.mapIndexed { internalIndex, _ -> digestService.computeNonce(privacySalt, it.groupIndex, internalIndex) } } + } } /**