GithubHelp home page GithubHelp logo

multiproof-rs's People

Contributors

axic avatar cdetrio avatar gballet avatar lightclient avatar s1na avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

multiproof-rs's Issues

Flat instructions encoding

Currently instructions are RLP-encoded like other data structures. That's not strictly necessary as after reading each opcode (1 byte) we'd know how many bytes of data to read for that opcode. So it could be a simple flat encoding of the opcodes and their operands without any metadata. This would eliminate the need for decoding them first on the verifier's side. This is also what @cdetrio is doing in turbo-mpas.

I could start working on a PR if you think this makes sense.

Keys are not truncated when parsing an Extension

In make_multiproof I think the goal had been to truncate keys of keyvals when parsing an Extension, but the key is simply being cloned:

multiproof-rs/src/lib.rs

Lines 492 to 499 in 269211e

let mut truncated = vec![];
for (k, v) in keyvals.iter() {
if extkey.factor_length(&NibbleKey::new(k.clone())) != extkey.len() {
return Err(
format!("One of the keys isn't present in the tree: {:?}", k).to_string(),
);
}
truncated.push((k.to_vec(), v.to_vec()));

Drop LEAF's operand

Leaves are sent in the multiproof slightly different than how they are actually stored in the trie. The difference lies in the key. In the multiproof the first part of a leaf is the full path from root to leaf, instead of the partial path from previous node to leaf. The LEAF opcode has an operand digit which specifies how to get this partial path by cutting a prefix of the full path.

This incurs some overhead on the verifier. If the leaf was sent "normally" verifier could simply hash it without any modifications. But now, they have to decode the leaf, decode hex prefix of key, split it, encode via hex prefix, encode RLP and then hash.

My question is what's the trade-off here? what will we lose if we send leaves "normally" and not send the full path as their keys?

Make the encryption algorithm a trait

We use Keccak256 in an Eth1 context, but future Eth1x and Eth2 evolutions might make us prefer e.g. blake2 or anything else. The encryption-related code should be made a trait.

Re-constructing paths of leaves during verification

This is more related to an EE wanting to do token transfers using this multiproof algorithm. I'm not sure if it makes sense to merge it in the repo.

EE receives an array of txes which include among other things a signature from sender and the address of the recipient. The EE also receives a multiproof. In order to make sure addresses of the sender and recipient of the tx corresponds to the leaves sent in the multiproof, the EE needs to re-construct the path to those leaves when it's verifying the multiproof. Here's my attempt at how one could do this:

  • Initialize an array of addrs with same length as leaves
  • When a leaf is read in via LEAF add its partial path to corresponding index of addrs, and add this index to the leaf node being pushed on stack
  • In BRANCH, EXTENSION or ADD:
    • if the node popped from stack is a leaf, read its index and prepend a partial path to its addrs entry. Also add its addrs index (for the leaf) to the node being pushed on stack
    • else, read list of indices for all leaves this node is pointing to and prepend their paths with the partial path (e.g. branch idx, or extkey)
  • After verification is done, all these paths need to be encoded form their nibbles form to get the addresses

re-enable linter in circleCI

rustfmt is not available on ARM, so I can't run it. Now that the code is going to become a bit more stable, the linter in circle CI needs to be re-enabled and cargo fmt needs to be run in nightly mode.

Return a Result in rebuild

Right now rebuild will panic, make that interface a bit more user friendly by returning a Result<Node, ...>

Make instruction parsing a trait

There are currently two instructions sets for multiproof. The repository currently uses the most ancient, as the second one is still largely unspecified at this time.

It would be nice to be able to easily switch between instructions sets. To achieve this, interaction with the instruction set should be abstracted through a trait.

Proof generator should not modify leaf values

make_multiproof takes as parameters the root of the trie and a list of key values (leaves). A list of keys should be sufficient and the values are not necessary. If a values different than the actual value of the leaf is passed to make_multiproof the verifier cannot verify the proof against the pre state root because after executing the instructions it will get a different state root.

Proof of missing key fails if missing key has the same prefix as existing key

For example, if the trie has the following keys:

  • [0, 0, 0]
  • [1, 0, 0]

then the structure will be like:

root(branch(leaf([0,0]), leaf([0, 0]), empty, empty, ...)

If then make_multiproof is called with values...

  • [1, 0, 0]
  • [1, 1, 0]

...it will fail because of the following check:

            // This is the simplest case: the key that is found at this 
            // level in the recursion needs to match the unique one in 
            // the list of keys that belong to the proof. 
            if keys.len() != 1 { 
                return Err(format!( 
                    "Expecting exactly 1 key in leaf, got {}: {:?}", 
                    keys.len(), 
                    keys 
                )); 
            }

Instead, it should encode the fact that at most one value is present.

Tree's new_* methods are MPT-specific

This is a tracker for @s1na's question on #44

These new_* methods seem to be specific to the MPT tree. Is there maybe a way in Rust to only define them on Node and then cast a Tree to a Node when these methods are needed?

AFAIK, there isn't. This being said, indeed a difference should be made, e.g. by introducing an inherited TreeWithExtension : Tree trait.

Make the tree implementation a trait

The current hexary Patricia Tree structure used in Ethereum poses some challenges and dropping it for another more manageable structure like binary or balanced trees is often discussed.

As a result, we want to abstract all tree interactions through a trait to be able to easily change the underlying tree implementation.

Add HASH opcode

Right now rebuild returns the root Node. In order to compute the root hash, the partial trie has to be walked down and up once. To improve the efficiency of verifiers we could either add a new opcode or change the semantic of the existing ones to allow the verifier to produce the correct hash once every instruction has been processed.

LEAF and EXTENSION opcodes could be modified to directly hash the node and push the hash on the stack. HASHER just reads in a hash from the sequence and doesn't need to be modified. The only question is how to handle branches, because it's not exactly clear when all the children have been added to the branch. One simple option is to introduce a HASH opcode which expects a branch node on top of stack and hashes it. There are other options too.

Proving keys not in the trie

Currently if a given key has not been inserted in the trie, the proof generator throws, which makes sense for most use-cases. But there are use-cases for proving the absence of a node. A simple one would be in the context of a token transfer EE when no node has been added for the recipient. If there's no proof, EE can't be certain the recipient has no account, and additionally to add the account it needs the path to the root for that key.

Maybe we could just relax the keyvals in the proof to also include nulls.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.