// 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 }
// 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 }