Beispiel #1
0
// 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
}
Beispiel #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
}
Beispiel #3
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
}
Beispiel #4
0
// 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
}