This article introduces data trustworthiness in LedgerDB. At the same time provide a method for credibility verification, users can perform credibility verification on data in LedgerDB according to business needs.

What is Data credibility?

Refers to the data written to ledger instances. The data is tamper-proof, non-repudiation-proof, traceable, and supported for credibility verification.

  • Tamper-proof: no one can modify or delete the data after it is written to the Ledger instance, including the LedgerDB service provider.
  • Non-repudiation of data: when any data is written, the data writer must sign the data using its own private key. With the "tamper-resistant" capability, no data written to ledger instances can be denied.
  • Data tracing: LedgerDB uses the journal mode for data recording, so all non-read operations of the data are written to the corresponding ledger instance. Therefore, LedgerDB provides native data tracing capabilities at the database level.

What is data trustworthiness verification?

Data credibility verification is a cryptographic algorithm used to verify whether the data stored in LedgerDB has been tampered with.

Verify credibility in the console

LedgerDB is developed based on the new merkel accumulator. When verifying the trustworthiness of data, we need to involve the concepts related to the Merkel tree.

Allows you to verify the credibility of specified data in a specified ledger.

JSON field description

result Success /Failure (Success indicates that the data credibility verification is passed)
MemberId The writer ID of the data to be verified.
LedgerId Ledger instance id to which the verified data belongs
JournalSequence The record number of the ledger to which the data to be verified belongs.
RootHash The parent node hash value of the validated data
WriterPubKey The public key of the writer.
ProofPath Auxiliary data for credibility verification. You can use the data and RootHash to perform self-verification through the verification method provided in this article
Timestamp The timestamp when the data is written.

Verify credibility of data

This method is used to verify the credibility of data based on business needs.

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() {
    // From the LedgerDB console> data trustworthiness verification> JSON replication. At the same time, it can also be assembled by itself. 
    // Corresponding profpath field
    String proofPath = "******";
    
    // From the LedgerDB console> data reliability verification> JSON replication function 
    // Corresponds to the RootHash field.
    String rootHash = "from the LedgerDB console> data trustworthiness verification> JSON copy function";
      
    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) {
        // Leaf node  
        childHash = Hex.decode((String) child);
      } else {
        // Branch node  
        childHash = calculateRoot(proofPath.getJSONArray(i));
      }
      childHashes[i] = childHash;
    }
    // The hash of the parent node is a child node, and the concatenation of the hash is calculated as the input.  
    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));
  }
}