Skip to content

Commit

Permalink
update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmytro-Shashkevych committed Nov 22, 2023
1 parent 122a904 commit ff21759
Showing 1 changed file with 81 additions and 41 deletions.
122 changes: 81 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,26 @@ Introduction
### Field Interactions and Proving Logic

1. Operating Fields:
- The NEAR zk-light-client operates on several critical fields within the blockchain ecosystem. These fields include the validators, the `next_bp_hash` (next block producers' hash), and the block hash itself.
- The NEAR zk-light-client operates on several critical fields within the blockchain ecosystem. These fields include
the validators, the `next_bp_hash` (next block producers' hash), and the block hash itself.
2. Formation of next_bp_hash:
- The `next_bp_hash` is a crucial component in this process. It is derived from the set of validators responsible for producing the next block. This hash serves as a cryptographic representation of the validators' identity and their role in the upcoming block production.
- The `next_bp_hash` is a crucial component in this process. It is derived from the set of validators responsible
for producing the next block. This hash serves as a cryptographic representation of the validators' identity and
their role in the upcoming block production.
3. Calculation of Block Hash:
- The block hash is then calculated based on the data of the current block. This data includes the `next_bp_hash`. By incorporating the `next_bp_hash` into the block hash calculation, there is a direct cryptographic link between the validators of the next block and the current block's integrity.
- The block hash is then calculated based on the data of the current block. This data includes the `next_bp_hash`.
By incorporating the `next_bp_hash` into the block hash calculation, there is a direct cryptographic link between
the validators of the next block and the current block's integrity.
4. Underpinning Idea of Proving:
- The core idea here is to establish a traceable and verifiable chain of custody for block creation. By proving that the `next_bp_hash` (derived from the validators) is a part of the current block's data, which in turn is used to calculate the block's hash, a seamless and secure linkage is formed.
- This linkage ensures that each block is not only a product of its immediate data but also carries a cryptographic signature of its contextual environment, i.e., the validators for the next block.
- Therefore, verifying a block's authenticity involves confirming that the set of validators is valid (thus legitimizing the `next_bp_hash`) and ensuring that the block hash is correctly derived from the data, including this `next_bp_hash`.
- The core idea here is to establish a traceable and verifiable chain of custody for block creation. By proving that
the `next_bp_hash` (derived from the validators) is a part of the current block's data, which in turn is used to
calculate the block's hash, a seamless and secure linkage is formed.
- This linkage ensures that each block is not only a product of its immediate data but also carries a cryptographic
signature of its contextual environment, i.e., the validators for the next block.
- Therefore, verifying a block's authenticity involves confirming that the set of validators is valid (thus
legitimizing the `next_bp_hash`) and ensuring that the block hash is correctly derived from the data, including
this `next_bp_hash`.


```
defined set of validators ======> defined next_bp_hash ======> defined block hash
```
Expand All @@ -54,7 +63,6 @@ _(for utility purposes)_
- prev_epoch_block_header.json : **arbitrary block from prev_epoch (required next_bp_hash field)**
- validators_ordered.json : **set of validators for proving block**


Illustrative scheme ( full-size
image [here](https://user-images.githubusercontent.com/58668238/284517560-69ad218f-13e9-47aa-9a59-cfecfbd6da70.png) ):

Expand All @@ -65,8 +73,6 @@ image [here](https://user-images.githubusercontent.com/58668238/284517560-69ad21
Proving next_bp_hash
============



##### Let's consider arbitrary block from the [Near Explorer](https://explorer.near.org/blocks/EcqGW4G71aXD3TU1cMbLUiPnahFc15MkyBScTgUveGQz) and its hash `EcqGW4G71aXD3TU1cMbLUiPnahFc15MkyBScTgUveGQz`

The underpinning idea is to replicate the Near core's logic for calculating `next_bp_hash` and compare it to the real
Expand Down Expand Up @@ -95,7 +101,6 @@ values obtained from the blockchain through RPC commands. The logic is the follo

```


1) Configure the account in the config.json file

```json
Expand Down Expand Up @@ -662,43 +667,78 @@ Calculated block hash from BlockHeaderInnerLiteView EcqGW4G71aXD3TU1cMbLUiPnahFc

Developers
============
To process and use light client you can copy `.json` utility files `block_header.json` and `validators_ordered.json` -
the only pieces of data you have to obtain to verify the block. And then replicate the verification logic using any
script language: Rust, JS , Go etc.
To process and use light client you can copy `.json` utility files:

`block_header.json`
`next_block_header.json `
`prev_epoch_block_header.json`
`validators_ordered.json`
and then replicate the verification logic using any language: Rust, JS , Go etc.

Example using Rust ( simplified version ):

```rust
pub fn main() -> Result<()> {
let mut file = File::open("../data/block_header.json")?;
let mut data = String::new();
file.read_to_string(&mut data)?;
let block_response: BlockResponse = serde_json::from_str(&data)?;
let block_header: BlockHeader = block_response.result.header.try_into()?;

println!("Hash: {:?} ", block_header.hash());
println!(
"Hash: {:?}",
BorshSerialize::try_to_vec(&block_header.hash())?
);

let computed_hash = compute_hash(
*block_header.prev_hash(),
&block_header.inner_lite_bytes(),
&block_header.inner_rest_bytes(),
);

println!("Computed hash: {:#?}", computed_hash);

println!(
"computed block hash in bytes {:?}\n\n",
BorshSerialize::try_to_vec(&computed_hash)?,
);

Ok(())
pub fn compute_hash(prev_hash: CryptoHash, inner_lite: &[u8], inner_rest: &[u8]) -> CryptoHash {
let hash_inner = compute_inner_hash(inner_lite, inner_rest);
combine_hash(&hash_inner, &prev_hash)
}

pub fn combine_hash(hash1: &MerkleHash, hash2: &MerkleHash) -> MerkleHash {
CryptoHash::hash_borsh((hash1, hash2))
}

pub fn compute_inner_hash(inner_lite: &[u8], inner_rest: &[u8]) -> CryptoHash {
let hash_lite = hash(inner_lite);
let hash_rest = hash(inner_rest);
combine_hash(&hash_lite, &hash_rest)
}

pub fn prove_header_hash<
F: RichField + Extendable<D>,
C: GenericConfig<D, F = F>,
const D: usize,
>(
header_data: HeaderData,
header_hash: CryptoHash,
) -> Result<(CircuitData<F, C, D>, ProofWithPublicInputs<F, C, D>)> {
let timing = TimingTree::new("prove block hash", log::Level::Debug);
// proof for hash inner_lite
let hash_lite = hash(&header_data.inner_lite);
let hash_lite_bytes = BorshSerialize::try_to_vec(&hash_lite)?;
let (d1, p1) =
sha256_proof_set_pis::<F, C, D>(&header_data.inner_lite, &hash_lite_bytes, false)?;
d1.verify(p1.clone())?;
// proof for hash inner_rest
let hash_rest = hash(&header_data.inner_rest);
let hash_rest_bytes = BorshSerialize::try_to_vec(&hash_rest)?;
let (d2, p2) =
sha256_proof_set_pis::<F, C, D>(&header_data.inner_rest, &hash_rest_bytes, false)?;
d2.verify(p2.clone())?;
// proof for concatenation of inner_lite & inner_rest
let inner_data = BorshSerialize::try_to_vec(&(hash_lite, hash_rest))?;
let inner_hash = combine_hash(&hash_lite, &hash_rest);
let inner_hash_bytes = BorshSerialize::try_to_vec(&inner_hash)?;
let (d3, p3) = sha256_proof_set_pis::<F, C, D>(&inner_data, &inner_hash_bytes, false)?;
d3.verify(p3.clone())?;
// proof for concatenation of inner_hash & prev_hash
let computed_header_data = BorshSerialize::try_to_vec(&(inner_hash, header_data.prev_hash))?;
let computed_header_hash = combine_hash(&inner_hash, &header_data.prev_hash);
assert_eq!(computed_header_hash, header_hash);
let computed_header_hash_bytes = BorshSerialize::try_to_vec(&computed_header_hash)?;
let (d4, p4) = sha256_proof_set_pis::<F, C, D>(
&computed_header_data,
&BorshSerialize::try_to_vec(&header_hash)?,
true,
)?;
d4.verify(p4.clone())?;
timing.print();
Ok((d4, p4))
}
```




Edge cases
============
Our light client is designed to efficiently handle blockchain data, specifically focusing on epoch-based block
Expand Down

0 comments on commit ff21759

Please sign in to comment.