From ae5d7d071d0274c3c748e6d6bf9d7421882de3bd Mon Sep 17 00:00:00 2001 From: huanghaiquan Date: Thu, 14 Nov 2019 11:43:08 +0800 Subject: [PATCH] Refactored HashFunction; --- .../classic/RIPEMD160HashFunction.java | 17 ++++-- .../service/classic/SHA256HashFunction.java | 13 ++++- .../crypto/utils/classic/RIPEMD160Utils.java | 28 ++++++--- .../crypto/utils/classic/SHA256Utils.java | 12 +++- .../jd/blockchain/crypto/HashFunction.java | 8 +++ .../crypto/service/sm/SM3HashFunction.java | 13 ++++- .../blockchain/crypto/utils/sm/SM3Utils.java | 31 ++++++---- ...ashDegistList.java => HashDigestList.java} | 6 +- .../blockchain/ledger/core/MerkleAccount.java | 2 +- .../ledger/core/MerkleTreeTest.java | 58 ++++++++++++++----- 10 files changed, 138 insertions(+), 50 deletions(-) rename source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/{HashDegistList.java => HashDigestList.java} (83%) diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java index 47172e87..bddbc99b 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java @@ -5,12 +5,10 @@ import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; import java.util.Arrays; import com.jd.blockchain.crypto.CryptoAlgorithm; -import com.jd.blockchain.crypto.CryptoBytes; import com.jd.blockchain.crypto.CryptoException; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.utils.classic.RIPEMD160Utils; -import com.jd.blockchain.utils.security.RipeMD160Utils; public class RIPEMD160HashFunction implements HashFunction { @@ -19,7 +17,7 @@ public class RIPEMD160HashFunction implements HashFunction { private static final int DIGEST_BYTES = 160 / 8; private static final int DIGEST_LENGTH = ALGORYTHM_CODE_SIZE + DIGEST_BYTES; - + RIPEMD160HashFunction() { } @@ -30,7 +28,6 @@ public class RIPEMD160HashFunction implements HashFunction { @Override public HashDigest hash(byte[] data) { - if (data == null) { throw new CryptoException("data is null!"); } @@ -39,6 +36,16 @@ public class RIPEMD160HashFunction implements HashFunction { return new HashDigest(RIPEMD160, digestBytes); } + @Override + public HashDigest hash(byte[] data, int offset, int len) { + if (data == null) { + throw new CryptoException("data is null!"); + } + + byte[] digestBytes = RIPEMD160Utils.hash(data, offset, len); + return new HashDigest(RIPEMD160, digestBytes); + } + @Override public boolean verify(HashDigest digest, byte[] data) { HashDigest hashDigest = hash(data); @@ -59,5 +66,5 @@ public class RIPEMD160HashFunction implements HashFunction { throw new CryptoException("digestBytes is invalid!"); } } - + } diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java index 7ba4ec6a..307a85e1 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java @@ -5,12 +5,10 @@ import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE; import java.util.Arrays; import com.jd.blockchain.crypto.CryptoAlgorithm; -import com.jd.blockchain.crypto.CryptoBytes; import com.jd.blockchain.crypto.CryptoException; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.utils.classic.SHA256Utils; -import com.jd.blockchain.utils.security.ShaUtils; public class SHA256HashFunction implements HashFunction { @@ -30,7 +28,6 @@ public class SHA256HashFunction implements HashFunction { @Override public HashDigest hash(byte[] data) { - if (data == null) { throw new CryptoException("data is null!"); } @@ -38,6 +35,16 @@ public class SHA256HashFunction implements HashFunction { byte[] digestBytes = SHA256Utils.hash(data); return new HashDigest(SHA256, digestBytes); } + + @Override + public HashDigest hash(byte[] data, int offset, int len) { + if (data == null) { + throw new CryptoException("data is null!"); + } + + byte[] digestBytes = SHA256Utils.hash(data, offset, len); + return new HashDigest(SHA256, digestBytes); + } @Override public boolean verify(HashDigest digest, byte[] data) { diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java index 05b11a6a..0ce73eab 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java @@ -10,16 +10,26 @@ import org.bouncycastle.crypto.digests.RIPEMD160Digest; */ public class RIPEMD160Utils { - // The length of RIPEMD160 output is 20 bytes - private static final int RIPEMD160DIGEST_LENGTH = 160 / 8; + // The length of RIPEMD160 output is 20 bytes + public static final int RIPEMD160DIGEST_LENGTH = 160 / 8; - public static byte[] hash(byte[] data){ + public static byte[] hash(byte[] data) { - byte[] result = new byte[RIPEMD160DIGEST_LENGTH]; - RIPEMD160Digest ripemd160Digest = new RIPEMD160Digest(); + byte[] result = new byte[RIPEMD160DIGEST_LENGTH]; + RIPEMD160Digest ripemd160Digest = new RIPEMD160Digest(); - ripemd160Digest.update(data,0,data.length); - ripemd160Digest.doFinal(result,0); - return result; - } + ripemd160Digest.update(data, 0, data.length); + ripemd160Digest.doFinal(result, 0); + return result; + } + + public static byte[] hash(byte[] data, int offset, int len) { + + byte[] result = new byte[RIPEMD160DIGEST_LENGTH]; + RIPEMD160Digest ripemd160Digest = new RIPEMD160Digest(); + + ripemd160Digest.update(data, offset, len); + ripemd160Digest.doFinal(result, 0); + return result; + } } diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java index a4a6523e..017a2b7a 100644 --- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java +++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java @@ -11,7 +11,7 @@ import org.bouncycastle.crypto.digests.SHA256Digest; public class SHA256Utils { // The length of SHA256 output is 32 bytes - private static final int SHA256DIGEST_LENGTH = 256 / 8; + public static final int SHA256DIGEST_LENGTH = 256 / 8; public static byte[] hash(byte[] data){ @@ -22,4 +22,14 @@ public class SHA256Utils { sha256Digest.doFinal(result,0); return result; } + + public static byte[] hash(byte[] data, int offset, int len){ + + byte[] result = new byte[SHA256DIGEST_LENGTH]; + SHA256Digest sha256Digest = new SHA256Digest(); + + sha256Digest.update(data, offset, len); + sha256Digest.doFinal(result,0); + return result; + } } diff --git a/source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java b/source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java index 8a1069de..26afa778 100644 --- a/source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java +++ b/source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java @@ -10,6 +10,14 @@ public interface HashFunction extends CryptoFunction { */ HashDigest hash(byte[] data); + /** + * 计算指定数据的 hash; + * + * @param data + * @return + */ + HashDigest hash(byte[] data, int offset, int len); + /** * 校验 hash 摘要与指定的数据是否匹配; diff --git a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java index 85fb943c..79893ae5 100644 --- a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java +++ b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java @@ -16,7 +16,7 @@ public class SM3HashFunction implements HashFunction { private static final int DIGEST_BYTES = 256 / 8; private static final int DIGEST_LENGTH = CryptoBytes.ALGORYTHM_CODE_SIZE + DIGEST_BYTES; - + SM3HashFunction() { } @@ -27,7 +27,6 @@ public class SM3HashFunction implements HashFunction { @Override public HashDigest hash(byte[] data) { - if (data == null) { throw new CryptoException("data is null!"); } @@ -36,6 +35,16 @@ public class SM3HashFunction implements HashFunction { return new HashDigest(SM3, digestBytes); } + @Override + public HashDigest hash(byte[] data, int offset, int len) { + if (data == null) { + throw new CryptoException("data is null!"); + } + + byte[] digestBytes = SM3Utils.hash(data, offset, len); + return new HashDigest(SM3, digestBytes); + } + @Override public boolean verify(HashDigest digest, byte[] data) { HashDigest hashDigest = hash(data); diff --git a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java index 6272a990..282a403c 100644 --- a/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java +++ b/source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java @@ -4,19 +4,30 @@ import org.bouncycastle.crypto.digests.SM3Digest; public class SM3Utils { - // The length of sm3 output is 32 bytes - private static final int SM3DIGEST_LENGTH = 32; + // The length of sm3 output is 32 bytes + public static final int SM3DIGEST_LENGTH = 32; - public static byte[] hash(byte[] data) { + public static byte[] hash(byte[] data) { - byte[] result = new byte[SM3DIGEST_LENGTH]; + byte[] result = new byte[SM3DIGEST_LENGTH]; - SM3Digest sm3digest = new SM3Digest(); + SM3Digest sm3digest = new SM3Digest(); - sm3digest.update(data, 0, data.length); - sm3digest.doFinal(result, 0); + sm3digest.update(data, 0, data.length); + sm3digest.doFinal(result, 0); - return result; - } -} + return result; + } + + public static byte[] hash(byte[] data, int offset, int len) { + + byte[] result = new byte[SM3DIGEST_LENGTH]; + SM3Digest sm3digest = new SM3Digest(); + + sm3digest.update(data, offset, len); + sm3digest.doFinal(result, 0); + + return result; + } +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDegistList.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDigestList.java similarity index 83% rename from source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDegistList.java rename to source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDigestList.java index 41dc4f3d..e2a74de7 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDegistList.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDigestList.java @@ -11,14 +11,14 @@ import com.jd.blockchain.ledger.HashProof; * @author huanghaiquan * */ -public class HashDegistList implements HashProof { +public class HashDigestList implements HashProof { private List proofs = new ArrayList(); - public HashDegistList() { + public HashDigestList() { } - public HashDegistList(HashProof proof) { + public HashDigestList(HashProof proof) { concat(proof); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java index dc0169a5..38a65e31 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java @@ -208,7 +208,7 @@ public class MerkleAccount implements CompositeAccount, HashProvable, MerkleSnap if (rootProof == null) { return null; } - HashDegistList proof = new HashDegistList(rootProof); + HashDigestList proof = new HashDigestList(rootProof); proof.concat(dataProof); return proof; } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java index afe8e435..f73e981e 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java @@ -556,6 +556,9 @@ public class MerkleTreeTest { /** * 测试从存储重新加载 Merkle 树的正确性; */ + /** + * + */ @Test public void testMerkleReload() { CryptoSetting setting = Mockito.mock(CryptoSetting.class); @@ -563,7 +566,7 @@ public class MerkleTreeTest { when(setting.getAutoVerifyHash()).thenReturn(true); // 保存所有写入的数据节点的 SN-Hash 映射表; - TreeMap dataNodes = new TreeMap<>(); + TreeMap expectedDataNodes = new TreeMap<>(); MerkleNode nd; // 测试从空的树开始,顺序增加数据节点; @@ -580,7 +583,7 @@ public class MerkleTreeTest { for (int i = 0; i < count; i++) { rand.nextBytes(dataBuf); nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf); - dataNodes.put(sn, nd.getNodeHash()); + expectedDataNodes.put(sn, nd.getNodeHash()); sn++; } mkt.commit(); @@ -610,6 +613,24 @@ public class MerkleTreeTest { // 预期扩展为 4 层16叉树,由 3 层满16叉树扩展 1 新分支(4个路径节点)而形成; long expectedNodes = getMaxPathNodeCount(3) + 4 + 4097; assertEquals(expectedNodes, storage.getCount()); + + //重新加载,判断数据是否正确; + MerkleTree r1_mkt = new MerkleTree(r1_rootHash, setting, keyPrefix, storage, true); + { + // 验证每一个数据节点都产生了存在性证明; + MerkleProof proof = null; + HashDigest expectedNodeHash = null; + MerkleDataNode reallyDataNode = null; + for (long n = 0; n < maxSN; n++) { + expectedNodeHash = expectedDataNodes.get(n); + reallyDataNode = r1_mkt.getData(n); + assertEquals(expectedNodeHash, reallyDataNode.getNodeHash()); + + proof = r1_mkt.getProof(n); + assertNotNull(proof); + assertEquals(expectedNodeHash, proof.getHash(0)); + } + } } // 覆盖到每一路分支修改数据节点; @@ -621,7 +642,7 @@ public class MerkleTreeTest { rand.nextBytes(dataBuf); sn = i; nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf); - dataNodes.put(sn, nd.getNodeHash()); + expectedDataNodes.put(sn, nd.getNodeHash()); } mkt.commit(); @@ -658,16 +679,18 @@ public class MerkleTreeTest { rand.nextBytes(dataBuf); sn = maxSN + 1 + i; nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf); - dataNodes.put(sn, nd.getNodeHash()); + expectedDataNodes.put(sn, nd.getNodeHash()); } mkt.commit(); - // 验证每一个数据节点都产生了存在性证明; - MerkleProof proof = null; - for (Long n : dataNodes.keySet()) { - proof = mkt.getProof(n.longValue()); - assertNotNull(proof); - assertEquals(dataNodes.get(n), proof.getHash(0)); + { + // 验证每一个数据节点都产生了存在性证明; + MerkleProof proof = null; + for (Long n : expectedDataNodes.keySet()) { + proof = mkt.getProof(n.longValue()); + assertNotNull(proof); + assertEquals(expectedDataNodes.get(n), proof.getHash(0)); + } } // 记录一次提交的根哈希以及部分节点信息,用于后续的加载校验; @@ -700,6 +723,7 @@ public class MerkleTreeTest { assertEquals(r1_proof1, r1_mkt.getProof(r1_sn1).toString()); assertEquals(r1_proof2, r1_mkt.getProof(r1_sn2).toString()); + // 从第 2 轮提交的 Merkle 根哈希加载; // 第 2 轮生成的 Merkle 树是对第 1 轮的数据的全部节点的修改,因此同一个 SN 的节点的证明是不同的; MerkleTree r2_mkt = new MerkleTree(r2_rootHash, setting, keyPrefix, storage, true); @@ -730,10 +754,13 @@ public class MerkleTreeTest { assertEquals(r3_proof3, r3_mkt.getProof(r3_sn3).toString()); // 验证每一个数据节点都产生了存在性证明; - for (Long n : dataNodes.keySet()) { - proof = r3_mkt.getProof(n.longValue()); - assertNotNull(proof); - assertEquals(dataNodes.get(n), proof.getHash(0)); + { + MerkleProof proof = null; + for (Long n : expectedDataNodes.keySet()) { + proof = r3_mkt.getProof(n.longValue()); + assertNotNull(proof); + assertEquals(expectedDataNodes.get(n), proof.getHash(0)); + } } } @@ -772,8 +799,7 @@ public class MerkleTreeTest { * 注:此方法不处理溢出;调用者需要自行规避; * * @param value - * @param x - * 大于等于 0 的整数; + * @param x 大于等于 0 的整数; * @return */ private static long power(long value, int x) {