GithubHelp home page GithubHelp logo

antani's Introduction

Antani

Antani is a library for efficiently proving solvency and delegated off-chain voting.

The first data-structure is a merkle tree expressed in JSON, that proves solvency, by writing account balances to leaf nodes / "buckets", and recursively summing these up, with the root note containing the total number of coins contained. This should be externally verifiable on a blockchain.

To protect user privacy, the account balance is split into "buckets" that are randomly sampled proportional to the total balance. Each bucket is signed with a key pair that the account holder is granted access to. The balance file can be distributed publicly by any means, while the key pairs are provided to account holders in privacy. The account holder can then verify that the balance file contains his total amount and that the key pairs are unique and used once. The account holder can check their balance efficiently, given a set of keys, without the complete tree. With the secret key a account holder can choose to prove ownership of buckets.

To achieve delegated off-chain voting another data structure is included, to do ballots for account holders. Each of them can use their secret key once to cast a vote and have this vote count towards a ballot. Each bucket can vote once and is weighted by the bucket's balance. A ballot is identified by a public key, and upon successful voting, the voter will receive a receipt, which can be verified by the ballot public key.

Read more about Antani's purpose on Bitfinex's BIP 001.

Usage

const antani = require('antani')

const ws = antani.tree.createWriteStream('balances.json')

const keypair = antani.tree.keygen()
ws.write({
  key: keypair.key,
  secretKey: keypair.secretKey,
  balance: 42
})

// ... write a ton more

ws.end(function () {
  const tree = antani.tree('balances.json')

  tree.root(console.log) // prints the root of the merkle tree
})

API

Merkle Balances Tree

const writeStream = antani.tree.createWriteStream(filename)

Create a new balances data structure. A merkle tree will be stored in filename as valid JSON but white space padded to support efficient lookups.

Expects a stream of buckets looking like this

{
  balance: aBalance,
  key: anEd25519PublicKey,
  secretKey: correspondingSecretKey
}

See antani.tree.keyPair() with info on how to generate the keypairs.

Written to it. The final JSON file will contain these buckets (minus the secretKeys) and a signature for each, as well as a merkle tree that be used to sum all of the together.

const balanceTree = antani.tree(filename)

Create a new balance tree. Filename should be one of the files produced above.

const keyPair = antani.tree.keygen()

Produces a valid ed25519 keypair encoded as base64.

const buckets = antani.tree.buckets(balance)

Splits a balance into an array of random buckets. Use this to anonymise the data written to the balance tree.

balanceTree.bucket(key, cb)

Lookup a bucket by public key in the balances file.

balanceTree.vote(key, secretKey, vote, cb)

Use bucket identified by key and sign a vote with choice vote. This can be .pushed to antani.ballot.

balanceTree.node(index, cb)

Lookup a merkle tree node (flat-tree indexed) in the balances file.

balanceTree.root(cb)

Lookup the merkle root. The hash stored here will verify the entire merkle tree so you want to sign that yourself so people can trust the balances file

balanceTree.proof(key, cb)

Looks up a bucket by key and verifies it contents by

  1. Verifying it's signature
  2. Rebuilding it's merkle parent nodes until it hits the root.
  3. Verifies that the hash of the root is the same as the hash stored in the root node.

This proof is returned in the callback as well as an array of all the nodes needed to verify it.

If it does not verify it will return an error instead.

balanceTree.signMessage(buckets, message, cb)

Sign a generic text message using the buckets you pass in.

The buckets will be verified that they are in the tree before signing and will return an error if not. You must pass at least one bucket. A bucket looks like this:

{
  key: pubKeyInBase64,
  secretKey: secKeyInBase64
}

The object returned looks like this:

{
  message: 'the message',
  signatures: [arrayOfBase64Sigs]
}

balanceTree.verifyMessage(buckets, signedMessage, cb)

Verify a signed message produced above. buckets should just be an array of public keys in base64. When verifying it will check that the public keys are indeed in the tree as well as verifying the message itself.

Returns null if everything is good and an error if not.

Voting

const ballot = antani.ballot(filename, keypair, tree, candidates)

Create a new ballot. Takes the following arguments:

  • filename for where to store the log of votes.
  • keypair used to sign incoming votes so voters can get a receipt. Use antani.ballot.keygen() to produce a key pair
  • tree must be a antani.tree used to lookup incoming votes to check their validity.
  • candidates must be an array of strings for validating votes

ballot.push(vote, cb)

Cast a vote and commit it to the ballot log. If successful cb will get a receipt for proving that a vote was committed to the log. Note that each bucket from antani.tree can only vote once.

Vote must look like (can be produced with antani.trees .vote):

{
  // These are all from the bucket
  key: …,
  signature: …,
  hash: …,
  index: …,
  balance: …,
  // these are special vote properties
  vote: …,
  voteSignature: …
}

The receipt looks like:

{
  receipt: 'base64 encoded signature'
  vote: {
    // above object
  }
}

ballot.verifyVote(vote, cb)

Check that vote is valid, calling cb with an error if anything is invalid. ballot.push will call this function before committing any votes to the log.

ballot.tally(cb)

Tally the votes after .finalize has been called. Will error if any votes contain a .vote that is not in the list candidates. Calls cb with the counts where each vote is weighted by it's balance.

ballot.finalize(cb)

End the vote log so it can be tallied.

License

MIT

antani's People

Contributors

emilbayes avatar mafintosh avatar prdn avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

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.