本文主要介绍LedgerDB内的数据可信性验证。同时提供可信性验证的方法,用户可根据业务需求,自行对LedgerDB内的数据进行可信性验证。
什么是数据可信性?
指写入Ledger实例的数据,具有不可篡改和不可抵赖性,同时可追溯和溯源,并且支持可信性的验证。
- 不可篡改:任何数据写入Ledger实例后,任何人都无能力修改和删除,包括LedgerDB服务提供方。
- 数据不可抵赖:任何数据的写入动作,都需要数据的写入方使用自己的私钥为待写入的数据进行签名,配合“不可篡改”能力,任何写入Ledger实例的数据都不能被抵赖。
- 数据溯源(追溯):由于LedgerDB在数据记录时采用类似Journal模式,所有数据的非读操作都会被写入对应的Ledger实例中,因此LedgerDB在数据库层面提供原生的数据溯源能力。
什么是数据可信性验证?
数据可信性验证,是指通过密码学算法来验证存入LedgerDB内的数据是否被篡改。
控制台可信性验证
LedgerDB底层基于新型的默克尔累加器进行研发,所以在数据可信性验证时,会涉及到默克尔树的相关概念。
用户可对指定账本的指定数据进行可信性验证。
JSON字段解释
result | 验证结果。成功/失败(成功表示数据可信性验证通过) |
MemberId | 被验证数据的写入方ID |
LedgerId | 被验证数据所属LedgerID |
JournalSequence | 被验证数据在所属Ledger中的记录编号 |
RootHash | 被验证数据的父节点哈希值 |
WriterPubKey | 被验证数据的写入方公钥 |
ProofPath | 进行可信性验证的辅助数据。用户可利用此数据和RootHash,通过本文提供的验证方法自行进行验证 |
Timestamp | 被验证数据的写入时间戳 |
数据可信性验证方法
用户可根据业务需求,通过此方法自行验证数据的可信性。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.google.common.hash.Hashing;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.util.StringUtils;
public class ProofDemo {
@Test
public void test() {
// 来自于从LedgerDB控制台>数据可信性验证>JSON复制功能。同时也可以自行拼装
// 对应ProofPath字段
String proofPath = "******";
// 来自于从LedgerDB控制台>数据可信性验证>JSON复制功能
// 对应RootHash字段
String rootHash = "来自于从LedgerDB控制台>数据可信性验证>JSON复制功能";
Assert.assertTrue(verifyProofPathV1(rootHash, proofPath));
}
public static byte[] calculateRoot(JSONArray proofPath) {
byte[][] childHashes = new byte[proofPath.size()][];
for (int i = 0; i < proofPath.size(); i++) {
Object child = proofPath.get(i);
byte[] childHash = null;
if (child instanceof String) {
// 叶子节点
childHash = Hex.decode((String) child);
} else {
// 分支节点
childHash = calculateRoot(proofPath.getJSONArray(i));
}
childHashes[i] = childHash;
}
// 父节点hash为子节点的hash的拼接作为输入计算而得
byte[] input = Arrays.concatenate(childHashes);
return Hashing.sha256().hashBytes(input).asBytes();
}
public static boolean verifyProofPathV1(String rootHash, String proofPath) {
JSONArray path = JSON.parseArray(proofPath);
if (StringUtils.isEmpty(rootHash)) {
if (path.size() == 0) {
return true;
} else {
return false;
}
}
if (path.size() == 1) {
return rootHash.equals(path.getString(0));
}
byte[] rootCalculated = calculateRoot(path);
return rootHash.equalsIgnoreCase(Hex.toHexString(rootCalculated));
}
}