0.0
No commit activity in last 3 years
No release in over 3 years
A simple implementation of a Merkle Tree backed Dictionary
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.15
~> 5.8.4
>= 0
~> 10.0
 Project Readme

MurkyWaters

Murky Waters Gem Version Downloads

MurkyWaters is a simple implementation of a merkle tree backed dictionary.

You can use this as an you would any ordinary dictionary structure with the added functionality that you can generate verifiable proofs of the dictionary structure and presence of leaf nodes in the dictionary. Proofs for individual leaves can exist with zero-knowledge of the contents of other leaves in the dictionary.

In short, this can allow you to provide proof of knowledge of some subset of a larger set of data without leaking any information.

Installation

Add this line to your application's Gemfile:

gem 'murky_waters'

And then execute:

$ bundle

Or install it yourself as:

$ gem install murky_waters

Usage

To construct a new Merkle tree backed ordered dictionary

Basics

    # A new, empty Merkle tree dictionary
    dict = Murky::Dict()

    # Specify a custom backing dictionary, default implementation is Hash
    dict = Murky::Dict(data: acts_like_a_dictionary)

    # Specify a custom digest class, must #respond_to?(:digest)
    dict = Murky::Dict(digest: Digest::SHA256)

To accesss, add and remove data to be indexed in our dict

  dict["hello"] = "world"  # Add data
  dict.delete("hello")     # Delete data
  dict["hello"]            # Retrieve data
  dict.siblings("hello")   # => [
                           #   "\xB0\x1F0Ji\ri\xE3\xFBMI\x9FU:=\xFF\xC3t\xD1\xCA6v\x11}'Q\x8E\xCD\x16t\xF4{",
                           #   "C\xEE\x89iS$s\xA9\xBE\xCD:\xD3ob\xE5\x8C\xBC\xE3g\x04\x00\x85Z\xBE@\x8Bu\xE4(\eR\xB4",
                           #   "\xC9\xDCj6\xC3g\f\xB2\xCEr\x05\xFB\xA4[\x06\xF5--q\xFA\xA4\xE9\x95c\xB0\xC8]\xB5\xBD\x1D\xC5\x12"
                           # ]
  dict.root                # "anajKi18I3C9TlVEcU//hZsw9i4sknlYCTspTQXxCr0=\n" # The merkle root/signature of our entire dictionary contents

Proofs

  # Generate a proof that "hello" exists inside of our dictionary and a merkle root/signature for our entire dictionary contents
  dict.proof("hello")
  # => #<Murky::Proof:0x007fc9c2f1ef30
  # @digest=#<Digest::SHA256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855>,
  # @root="\x80\xF5\x9F\xFF\xAD\xC2-\x85t\xCCY\xC8\x90\xBB\x9D\xC2\x16@\x02-\x1C&k\xB8>\xA6\xC3[\x8C'I\xE6",
  # @siblings=
  #  ["\xB0\x1F0Ji\ri\xE3\xFBMI\x9FU:=\xFF\xC3t\xD1\xCA6v\x11}'Q\x8E\xCD\x16t\xF4{",
  #   "C\xEE\x89iS$s\xA9\xBE\xCD:\xD3ob\xE5\x8C\xBC\xE3g\x04\x00\x85Z\xBE@\x8Bu\xE4(\eR\xB4",
  #   "}q\x80\xE0:\xD1Am\xDB.@g\xDE\xE8u\xC1h\xD92\x8F\x19l\xAD]\x02)I\rn\xC1z\x96"],
  # @signature="\x90\xE3\xC8\xFCn\x86\x15\"\x94\x84`\xEC\xFB\xC2\xEE^;\xDD\x9B\xF1\x89\v\xE04u\r\xE4\b\xA5\xE0$l",
  # @valid=true>
  #

Verification

  # Perform a verification for a root, and a merkle path/sibling list and some value.
  It verifies that this value resides in the dictionary represented by our root signature. From this we can conclude that the size, shape and order of the tree for this merkle root are unchanged from when this proof was generated and that our value does indeed exist within the dictionary.

  # Murky.verify(root, siblings, data) # => true/false
  Murky.verify(
    root,
    siblings,
    data
  ) # => true if verification passes

A tree can optionally be backed by any dictionary like data structure to store the real leaf data. The prerequisites of this structure are that:

  • It is hash-like (implements #[]= and #[])
  • It is ordered
  • It implements #keys
  • It implements #values

You can pass this structure into the constuctor of the Murky::Dict. E.g

Murky::Dict(data: {foo: :bar})

Saving and restoring proofs

Proofs can be saved to, and restored from a file. E.g

  dict.proof(:my_value).output("/Users/pico/Desktop/proof.txt")

  proof = Murky::Proof.from_file("/Users/pico/Desktop/proof.txt")
  proof.valid? #=> true

Development

After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/wouterken/murky_waters. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

Code of Conduct

Everyone interacting in the MurkyWaters project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.