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 java.util.Arrays;


import com.jd.blockchain.crypto.CryptoAlgorithm; import com.jd.blockchain.crypto.CryptoAlgorithm;
import com.jd.blockchain.crypto.CryptoBytes;
import com.jd.blockchain.crypto.CryptoException; import com.jd.blockchain.crypto.CryptoException;
import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.HashFunction;
import com.jd.blockchain.crypto.utils.classic.RIPEMD160Utils; import com.jd.blockchain.crypto.utils.classic.RIPEMD160Utils;
import com.jd.blockchain.utils.security.RipeMD160Utils;


public class RIPEMD160HashFunction implements HashFunction { 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_BYTES = 160 / 8;


private static final int DIGEST_LENGTH = ALGORYTHM_CODE_SIZE + DIGEST_BYTES; private static final int DIGEST_LENGTH = ALGORYTHM_CODE_SIZE + DIGEST_BYTES;
RIPEMD160HashFunction() { RIPEMD160HashFunction() {
} }


@@ -30,7 +28,6 @@ public class RIPEMD160HashFunction implements HashFunction {


@Override @Override
public HashDigest hash(byte[] data) { public HashDigest hash(byte[] data) {

if (data == null) { if (data == null) {
throw new CryptoException("data is null!"); throw new CryptoException("data is null!");
} }
@@ -39,6 +36,16 @@ public class RIPEMD160HashFunction implements HashFunction {
return new HashDigest(RIPEMD160, digestBytes); 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 @Override
public boolean verify(HashDigest digest, byte[] data) { public boolean verify(HashDigest digest, byte[] data) {
HashDigest hashDigest = hash(data); HashDigest hashDigest = hash(data);
@@ -59,5 +66,5 @@ public class RIPEMD160HashFunction implements HashFunction {
throw new CryptoException("digestBytes is invalid!"); 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 java.util.Arrays;


import com.jd.blockchain.crypto.CryptoAlgorithm; import com.jd.blockchain.crypto.CryptoAlgorithm;
import com.jd.blockchain.crypto.CryptoBytes;
import com.jd.blockchain.crypto.CryptoException; import com.jd.blockchain.crypto.CryptoException;
import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.crypto.HashFunction; import com.jd.blockchain.crypto.HashFunction;
import com.jd.blockchain.crypto.utils.classic.SHA256Utils; import com.jd.blockchain.crypto.utils.classic.SHA256Utils;
import com.jd.blockchain.utils.security.ShaUtils;


public class SHA256HashFunction implements HashFunction { public class SHA256HashFunction implements HashFunction {


@@ -30,7 +28,6 @@ public class SHA256HashFunction implements HashFunction {


@Override @Override
public HashDigest hash(byte[] data) { public HashDigest hash(byte[] data) {

if (data == null) { if (data == null) {
throw new CryptoException("data is null!"); throw new CryptoException("data is null!");
} }
@@ -38,6 +35,16 @@ public class SHA256HashFunction implements HashFunction {
byte[] digestBytes = SHA256Utils.hash(data); byte[] digestBytes = SHA256Utils.hash(data);
return new HashDigest(SHA256, digestBytes); 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 @Override
public boolean verify(HashDigest digest, byte[] data) { 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 { 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 { public class SHA256Utils {


// The length of SHA256 output is 32 bytes // 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){ public static byte[] hash(byte[] data){


@@ -22,4 +22,14 @@ public class SHA256Utils {
sha256Digest.doFinal(result,0); sha256Digest.doFinal(result,0);
return result; 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); HashDigest hash(byte[] data);
/**
* 计算指定数据的 hash;
*
* @param data
* @return
*/
HashDigest hash(byte[] data, int offset, int len);


/** /**
* 校验 hash 摘要与指定的数据是否匹配; * 校验 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_BYTES = 256 / 8;


private static final int DIGEST_LENGTH = CryptoBytes.ALGORYTHM_CODE_SIZE + DIGEST_BYTES; private static final int DIGEST_LENGTH = CryptoBytes.ALGORYTHM_CODE_SIZE + DIGEST_BYTES;
SM3HashFunction() { SM3HashFunction() {
} }


@@ -27,7 +27,6 @@ public class SM3HashFunction implements HashFunction {


@Override @Override
public HashDigest hash(byte[] data) { public HashDigest hash(byte[] data) {

if (data == null) { if (data == null) {
throw new CryptoException("data is null!"); throw new CryptoException("data is null!");
} }
@@ -36,6 +35,16 @@ public class SM3HashFunction implements HashFunction {
return new HashDigest(SM3, digestBytes); 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 @Override
public boolean verify(HashDigest digest, byte[] data) { public boolean verify(HashDigest digest, byte[] data) {
HashDigest hashDigest = hash(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 { 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 * @author huanghaiquan
* *
*/ */
public class HashDegistList implements HashProof {
public class HashDigestList implements HashProof {


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


public HashDegistList() {
public HashDigestList() {
} }


public HashDegistList(HashProof proof) {
public HashDigestList(HashProof proof) {
concat(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) { if (rootProof == null) {
return null; return null;
} }
HashDegistList proof = new HashDegistList(rootProof);
HashDigestList proof = new HashDigestList(rootProof);
proof.concat(dataProof); proof.concat(dataProof);
return proof; 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 树的正确性; * 测试从存储重新加载 Merkle 树的正确性;
*/ */
/**
*
*/
@Test @Test
public void testMerkleReload() { public void testMerkleReload() {
CryptoSetting setting = Mockito.mock(CryptoSetting.class); CryptoSetting setting = Mockito.mock(CryptoSetting.class);
@@ -563,7 +566,7 @@ public class MerkleTreeTest {
when(setting.getAutoVerifyHash()).thenReturn(true); when(setting.getAutoVerifyHash()).thenReturn(true);


// 保存所有写入的数据节点的 SN-Hash 映射表; // 保存所有写入的数据节点的 SN-Hash 映射表;
TreeMap<Long, HashDigest> dataNodes = new TreeMap<>();
TreeMap<Long, HashDigest> expectedDataNodes = new TreeMap<>();
MerkleNode nd; MerkleNode nd;


// 测试从空的树开始,顺序增加数据节点; // 测试从空的树开始,顺序增加数据节点;
@@ -580,7 +583,7 @@ public class MerkleTreeTest {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
rand.nextBytes(dataBuf); rand.nextBytes(dataBuf);
nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf); nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
dataNodes.put(sn, nd.getNodeHash());
expectedDataNodes.put(sn, nd.getNodeHash());
sn++; sn++;
} }
mkt.commit(); mkt.commit();
@@ -610,6 +613,24 @@ public class MerkleTreeTest {
// 预期扩展为 4 层16叉树,由 3 层满16叉树扩展 1 新分支(4个路径节点)而形成; // 预期扩展为 4 层16叉树,由 3 层满16叉树扩展 1 新分支(4个路径节点)而形成;
long expectedNodes = getMaxPathNodeCount(3) + 4 + 4097; long expectedNodes = getMaxPathNodeCount(3) + 4 + 4097;
assertEquals(expectedNodes, storage.getCount()); 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); rand.nextBytes(dataBuf);
sn = i; sn = i;
nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf); nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
dataNodes.put(sn, nd.getNodeHash());
expectedDataNodes.put(sn, nd.getNodeHash());
} }


mkt.commit(); mkt.commit();
@@ -658,16 +679,18 @@ public class MerkleTreeTest {
rand.nextBytes(dataBuf); rand.nextBytes(dataBuf);
sn = maxSN + 1 + i; sn = maxSN + 1 + i;
nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf); nd = mkt.setData(sn, "KEY-" + sn, 0, dataBuf);
dataNodes.put(sn, nd.getNodeHash());
expectedDataNodes.put(sn, nd.getNodeHash());
} }
mkt.commit(); 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_proof1, r1_mkt.getProof(r1_sn1).toString());
assertEquals(r1_proof2, r1_mkt.getProof(r1_sn2).toString()); assertEquals(r1_proof2, r1_mkt.getProof(r1_sn2).toString());



// 从第 2 轮提交的 Merkle 根哈希加载; // 从第 2 轮提交的 Merkle 根哈希加载;
// 第 2 轮生成的 Merkle 树是对第 1 轮的数据的全部节点的修改,因此同一个 SN 的节点的证明是不同的; // 第 2 轮生成的 Merkle 树是对第 1 轮的数据的全部节点的修改,因此同一个 SN 的节点的证明是不同的;
MerkleTree r2_mkt = new MerkleTree(r2_rootHash, setting, keyPrefix, storage, true); 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()); 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 value
* @param x
* 大于等于 0 的整数;
* @param x 大于等于 0 的整数;
* @return * @return
*/ */
private static long power(long value, int x) { private static long power(long value, int x) {


Loading…
Cancel
Save