Browse Source

Refactored HashFunction;

tags/1.1.2^2
huanghaiquan 4 years ago
parent
commit
ae5d7d071d
10 changed files with 138 additions and 50 deletions
  1. +12
    -5
      source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java
  2. +10
    -3
      source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java
  3. +19
    -9
      source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java
  4. +11
    -1
      source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java
  5. +8
    -0
      source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java
  6. +11
    -2
      source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java
  7. +21
    -10
      source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java
  8. +3
    -3
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDigestList.java
  9. +1
    -1
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java
  10. +42
    -16
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java

+ 12
- 5
source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RIPEMD160HashFunction.java View File

@@ -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!");
}
}
}

+ 10
- 3
source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/SHA256HashFunction.java View File

@@ -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) {


+ 19
- 9
source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RIPEMD160Utils.java View File

@@ -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;
}
}

+ 11
- 1
source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SHA256Utils.java View File

@@ -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;
}
}

+ 8
- 0
source/crypto/crypto-framework/src/main/java/com/jd/blockchain/crypto/HashFunction.java View File

@@ -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 摘要与指定的数据是否匹配;


+ 11
- 2
source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/service/sm/SM3HashFunction.java View File

@@ -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);


+ 21
- 10
source/crypto/crypto-sm/src/main/java/com/jd/blockchain/crypto/utils/sm/SM3Utils.java View File

@@ -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;
}
}

source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDegistList.java → source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/HashDigestList.java View File

@@ -11,14 +11,14 @@ import com.jd.blockchain.ledger.HashProof;
* @author huanghaiquan
*
*/
public class HashDegistList implements HashProof {
public class HashDigestList implements HashProof {

private List<HashDigest> proofs = new ArrayList<HashDigest>();

public HashDegistList() {
public HashDigestList() {
}

public HashDegistList(HashProof proof) {
public HashDigestList(HashProof proof) {
concat(proof);
}


+ 1
- 1
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/MerkleAccount.java View File

@@ -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;
}


+ 42
- 16
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/MerkleTreeTest.java View File

@@ -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<Long, HashDigest> dataNodes = new TreeMap<>();
TreeMap<Long, HashDigest> 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) {


Loading…
Cancel
Save