Example #1
0
// QueryMembership queries for an event with a key in a particular snapshot in the balloon.
// Returns an answer (is member?), an event (if the answer is true), and a proof (always).
// Run by the server with untrusted input (key and queried).
func (balloon *Balloon) QueryMembership(key []byte, queried *Snapshot,
	vk []byte) (answer bool, event *Event, proof QueryProof, err error) {
	answer = false

	// verify the queried snapshot
	if !util.Verify(vk,
		append(append([]byte("snapshot"), queried.Roots.History...),
			append(queried.Roots.Treap, queried.Previous...)...),
		queried.Signature) {
		return answer, nil, proof, errors.New("invalid signature")
	}

	// verify the length of the key
	if len(key) != util.HashOutputLen {
		return answer, nil, proof, errors.New("invalid key length")
	}

	// check hash treap for hash of key
	proof.TreapProof = balloon.treap.MembershipQuery(util.Hash(key))

	// if not in treap, then a non-membership is done
	if proof.TreapProof.Value == nil {
		return
	}

	// the position (index) of the event in the history tree
	index := util.Btoi(proof.TreapProof.Value)

	// was the event added _after_ the queried for snapshot was created?
	if index > queried.Roots.Version {
		return
	}

	// ok, now we know it's a membership proof, so we query the history tree
	proof.HistoryProof, err = balloon.history.MembershipProof(index, queried.Roots.Version)
	if err != nil {
		panic(err)
	}

	// get the event from storage
	e, err := balloon.Storage.LookupEvent(key)
	if err != nil {
		return
	}

	return true, e, proof, nil
}
Example #2
0
// Verify verifies a proof and answer from QueryMembership. Returns true if the
// answer and proof are correct and consistent, otherwise false.
// Run by a client on input that should be verified.
func (proof *QueryProof) Verify(key []byte, queried, current *Snapshot,
	answer bool, event *Event, vk []byte) (valid bool) {

	// verify the snapshots
	if !util.Verify(vk,
		append(append([]byte("snapshot"), queried.Roots.History...),
			append(queried.Roots.Treap, queried.Previous...)...),
		queried.Signature) {
		return false
	}
	if !util.Verify(vk,
		append(append([]byte("snapshot"), current.Roots.History...),
			append(current.Roots.Treap, current.Previous...)...),
		current.Signature) {
		return false
	}

	// check the authenticated path in the hash treap
	if !proof.TreapProof.Verify(util.Hash(key), current.Roots.Treap) {
		return false
	}

	// a non-membership proof where there is no event in the treap
	if !answer && proof.TreapProof.Value == nil && event == nil {
		return true
	}

	// a non-membership proof where the event was added _after_ the queried for snapshot
	index := util.Btoi(proof.TreapProof.Value)
	if !answer && index > queried.Roots.Version {
		return true
	}

	// a membership proof
	if answer && event != nil && util.Equal(event.Key, key) && proof.HistoryProof.Verify() &&
		proof.HistoryProof.Index == index && proof.HistoryProof.Version == queried.Roots.Version &&
		util.Equal(proof.HistoryProof.Root, queried.Roots.History) &&
		util.Equal(proof.HistoryProof.Event, util.Hash(event.Key, event.Value)) {
		return true
	}

	// otherwise the proof is invalid
	return false
}