3
3
package net.corda.core.crypto
4
4
5
5
import io.netty.util.concurrent.FastThreadLocal
6
+ import net.corda.core.CordaInternal
6
7
import net.corda.core.DeleteForDJVM
7
8
import net.corda.core.KeepForDJVM
8
9
import net.corda.core.crypto.internal.DigestAlgorithmFactory
10
+ import net.corda.core.internal.utilities.Internable
11
+ import net.corda.core.internal.utilities.PrivateInterner
9
12
import net.corda.core.serialization.CordaSerializable
10
13
import net.corda.core.utilities.OpaqueBytes
11
14
import net.corda.core.utilities.parseAsHex
@@ -66,7 +69,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
66
69
}
67
70
68
71
override fun generate (data : ByteArray ): SecureHash {
69
- return HASH (algorithm, digestAs(algorithm, data))
72
+ return interner.intern( HASH (algorithm, digestAs(algorithm, data) ))
70
73
}
71
74
}
72
75
@@ -110,7 +113,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
110
113
return if (concatAlgorithm == SHA2_256 ) {
111
114
concatBytes.sha256()
112
115
} else {
113
- HASH (concatAlgorithm, digestAs(concatAlgorithm, concatBytes))
116
+ interner.intern( HASH (concatAlgorithm, digestAs(concatAlgorithm, concatBytes) ))
114
117
}
115
118
}
116
119
@@ -121,12 +124,15 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
121
124
fun reHash () : SecureHash = hashAs(algorithm, bytes)
122
125
123
126
// Like static methods in Java, except the 'companion' is a singleton that can have state.
124
- companion object {
127
+ companion object : Internable < SecureHash > {
125
128
const val SHA2_256 = " SHA-256"
126
129
const val SHA2_384 = " SHA-384"
127
130
const val SHA2_512 = " SHA-512"
128
131
const val DELIMITER = ' :'
129
132
133
+ @CordaInternal
134
+ override val interner = PrivateInterner <SecureHash >()
135
+
130
136
/* *
131
137
* Converts a SecureHash hash value represented as a {algorithm:}hexadecimal [String] into a [SecureHash].
132
138
* @param str An optional algorithm id followed by a delimiter and the sequence of hexadecimal digits that represents a hash value.
@@ -157,7 +163,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
157
163
val digestLength = digestFor(algorithm).digestLength
158
164
val data = value.parseAsHex()
159
165
return when (data.size) {
160
- digestLength -> HASH (algorithm, data)
166
+ digestLength -> interner.intern( HASH (algorithm, data) )
161
167
else -> throw IllegalArgumentException (" Provided string is ${data.size} bytes not $digestLength bytes in hex: $value " )
162
168
}
163
169
}
@@ -171,12 +177,18 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
171
177
fun parse (str : String? ): SHA256 {
172
178
return str?.toUpperCase()?.parseAsHex()?.let {
173
179
when (it.size) {
174
- 32 -> SHA256 (it)
180
+ 32 -> interner.intern( SHA256 (it) )
175
181
else -> throw IllegalArgumentException (" Provided string is ${it.size} bytes not 32 bytes in hex: $str " )
176
182
}
177
183
} ? : throw IllegalArgumentException (" Provided string is null" )
178
184
}
179
185
186
+ /* *
187
+ * Factory method for SHA256 to be used in preference to the constructor.
188
+ */
189
+ @JvmStatic
190
+ fun createSHA256 (bytes : ByteArray ): SHA256 = interner.intern(SHA256 (bytes))
191
+
180
192
private val messageDigests: ConcurrentMap <String , DigestSupplier > = ConcurrentHashMap ()
181
193
182
194
private fun digestFor (algorithm : String ): DigestSupplier {
@@ -202,9 +214,9 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
202
214
fun hashAs (algorithm : String , bytes : ByteArray ): SecureHash {
203
215
val hashBytes = digestAs(algorithm, bytes)
204
216
return if (algorithm == SHA2_256 ) {
205
- SHA256 (hashBytes)
217
+ interner.intern( SHA256 (hashBytes) )
206
218
} else {
207
- HASH (algorithm, hashBytes)
219
+ interner.intern( HASH (algorithm, hashBytes) )
208
220
}
209
221
}
210
222
@@ -222,7 +234,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
222
234
} else {
223
235
val digest = digestFor(algorithm).get()
224
236
val hash = digest.componentDigest(bytes)
225
- HASH (algorithm, hash)
237
+ interner.intern( HASH (algorithm, hash) )
226
238
}
227
239
}
228
240
@@ -240,7 +252,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
240
252
} else {
241
253
val digest = digestFor(algorithm).get()
242
254
val hash = digest.nonceDigest(bytes)
243
- HASH (algorithm, hash)
255
+ interner.intern( HASH (algorithm, hash) )
244
256
}
245
257
}
246
258
@@ -249,7 +261,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
249
261
* @param bytes The [ByteArray] to hash.
250
262
*/
251
263
@JvmStatic
252
- fun sha256 (bytes : ByteArray ) = SHA256 (digestAs(SHA2_256 , bytes))
264
+ fun sha256 (bytes : ByteArray ) = interner.intern( SHA256 (digestAs(SHA2_256 , bytes) ))
253
265
254
266
/* *
255
267
* Computes the SHA-256 hash of the [ByteArray], and then computes the SHA-256 hash of the hash.
@@ -282,7 +294,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
282
294
randomSHA256()
283
295
} else {
284
296
val digest = digestFor(algorithm)
285
- HASH (algorithm, digest.get().digest(secureRandomBytes(digest.digestLength)))
297
+ interner.intern( HASH (algorithm, digest.get().digest(secureRandomBytes(digest.digestLength) )))
286
298
}
287
299
}
288
300
@@ -291,7 +303,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
291
303
* This field provides more intuitive access from Java.
292
304
*/
293
305
@JvmField
294
- val zeroHash: SHA256 = SHA256 (ByteArray (32 ) { 0 .toByte() })
306
+ val zeroHash: SHA256 = interner.intern( SHA256 (ByteArray (32 ) { 0 .toByte() }) )
295
307
296
308
/* *
297
309
* A SHA-256 hash value consisting of 32 0x00 bytes.
@@ -305,7 +317,7 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
305
317
* This field provides more intuitive access from Java.
306
318
*/
307
319
@JvmField
308
- val allOnesHash: SHA256 = SHA256 (ByteArray (32 ) { 255 .toByte() })
320
+ val allOnesHash: SHA256 = interner.intern( SHA256 (ByteArray (32 ) { 255 .toByte() }) )
309
321
310
322
/* *
311
323
* A SHA-256 hash value consisting of 32 0xFF bytes.
@@ -323,8 +335,8 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
323
335
return hashConstants.getOrPut(algorithm) {
324
336
val digestLength = digestFor(algorithm).digestLength
325
337
HashConstants (
326
- zero = HASH (algorithm, ByteArray (digestLength)),
327
- allOnes = HASH (algorithm, ByteArray (digestLength) { 255 .toByte() })
338
+ zero = interner.intern( HASH (algorithm, ByteArray (digestLength) )),
339
+ allOnes = interner.intern( HASH (algorithm, ByteArray (digestLength) { 255 .toByte() }) )
328
340
)
329
341
}
330
342
}
0 commit comments