// Verify verifies a proof and answer from QueryPrune. Returns true if the answer // and proof is correct, otherwise false. Run by the author. func (proof *PruneProof) Verify(events []Event, answer bool, current *Snapshot, vk []byte) (valid bool) { valid = true if !util.Verify(vk, append(append([]byte("snapshot"), current.Roots.History...), append(current.Roots.Treap, current.Previous...)...), current.Signature) { return false } // always possible to add no events if len(events) == 0 { return answer // same as answer == true } // verify the prune proof in the hash treap treapKeys := make([][]byte, len(events)) for i := 0; i < len(events); i++ { treapKeys[i] = util.Hash(events[i].Key) } valid = proof.TreapProof.Verify(treapKeys, answer, current.Roots.Treap) if !valid { return } // check the query if needed if answer && current.Roots.Version >= 0 { valid = proof.QueryProof.Verify(proof.Event.Key, current, current, true, &proof.Event, vk) } return valid }
// 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 }
// 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 }
// Refresh updates balloon with the slice of events. Returns an error if the update // fails to produce a snapshot identical to the provided next one. // Run by the server on input (events and next) that will be verified. func (balloon *Balloon) Refresh(events []Event, current, next *Snapshot, vk []byte) (err error) { // current can be empty on the first run of Refresh if current == nil && balloon.Size() > 0 { return errors.New("current snapshot required for non-zero Balloon") } if current != nil { if !util.Equal(current.Roots.History, balloon.history.Root()) || !util.Equal(current.Roots.Treap, balloon.treap.Root()) { return errors.New("provided snapshot is not current") } if current.Roots.Version == -1 && next.Roots.Version != len(events)-1 { return errors.New("unexpected version in next snapshot") } if current.Roots.Version != -1 && current.Roots.Version+len(events) != next.Roots.Version { return errors.New("version in next snapshot inconsistent with current") } if !util.Verify(vk, append(append([]byte("snapshot"), current.Roots.History...), append(current.Roots.Treap, current.Previous...)...), current.Signature) { return errors.New("invalid signature in current snapshot") } } treap := balloon.treap ht := balloon.history.Clone() if len(events) > 0 { sort.Sort(ByKey(events)) // attempt to add events for i := 0; i < len(events); i++ { // add the hash of the entire event to the history tree _, err = ht.Add(util.Hash(append(events[i].Key, events[i].Value...))) if err != nil { return } // add to the treap the hash of the key pointing to the index (version) of the // hash of the event in the history tree treap, err = treap.Add(util.Hash(events[i].Key), util.Itob(ht.LatestVersion())) if err != nil { return } } } var prev []byte if current != nil { prev = current.Signature } // compare snapshot with next snapshot if !util.Equal(ht.Root(), next.Roots.History) || !util.Equal(treap.Root(), next.Roots.Treap) || ht.LatestVersion() != next.Roots.Version || !util.Equal(prev, next.Previous) { return errors.New("roots or version mismatch") } if current == nil { if next.Index != 0 { return errors.New("index not what expected in next snapshot") } } else if current.Index+1 != next.Index { return errors.New("index not what expected in next snapshot") } if !util.Verify(vk, append(append([]byte("snapshot"), next.Roots.History...), append(next.Roots.Treap, next.Previous...)...), next.Signature) { return errors.New("invalid signature") } // all is OK, store results err = balloon.Storage.Store(events, *next) if err != nil { return err } balloon.latestsnapshot = *next if len(events) > 0 { balloon.latesteventkey = events[len(events)-1].Key } balloon.treap = treap balloon.history = ht return }