Beispiel #1
0
// Update updates balloon with the slice of events, producing the next snapshot.
// Run by the author on trusted input.
func (balloon *Balloon) Update(events []Event, current *Snapshot,
	sk []byte) (next *Snapshot, err error) {
	if len(events) == 0 {
		return nil, errors.New("you need to add at least one event")
	}
	if !util.Equal(current.Roots.History, balloon.history.Root()) ||
		!util.Equal(current.Roots.Treap, balloon.treap.Root()) {
		return nil, errors.New("provided snapshot is not current")
	}

	sort.Sort(ByKey(events))

	// attempt to add events
	treap := balloon.treap
	ht := balloon.history.Clone()
	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
		}
	}

	// attempt to create next snapshot
	next = new(Snapshot)
	next.Index = current.Index + 1
	next.Roots.History = ht.Root()
	next.Roots.Treap = treap.Root()
	next.Roots.Version = ht.LatestVersion()
	next.Previous = current.Signature
	signature, err := util.Sign(balloon.sk,
		append(append([]byte("snapshot"), next.Roots.History...), append(next.Roots.Treap, next.Previous...)...))
	if err != nil {
		panic(err)
	}
	next.Signature = signature

	// all is OK, save result
	err = balloon.Storage.Store(events, *next)
	if err != nil {
		return nil, err
	}
	balloon.latestsnapshot = *next
	if len(events) > 0 {
		balloon.latesteventkey = events[len(events)-1].Key
	}
	balloon.treap = treap
	balloon.history = ht

	return
}
Beispiel #2
0
// Setup creates a new balloon based on the slice of events (may be empty or nil). Returns the
// first snapshot. Run by the author on trusted input.
func Setup(events []Event, sk, vk []byte, storage EventStorage) (balloon *Balloon, snap *Snapshot, err error) {
	balloon = NewBalloon(storage)
	balloon.sk = sk
	balloon.vk = vk

	// do same as update, allow events to be empty
	if len(events) > 0 {
		sort.Sort(ByKey(events))

		// add events
		for i := 0; i < len(events); i++ {
			// add the hash of the entire event to the history tree
			_, err = balloon.history.Add(util.Hash(append(events[i].Key, events[i].Value...)))
			if err != nil {
				return nil, nil, err
			}

			// add to the treap the hash of the key pointing to the index (version) of the
			// hash of the event in the history tree
			balloon.treap, err = balloon.treap.Add(util.Hash(events[i].Key),
				util.Itob(balloon.history.LatestVersion()))
			if err != nil {
				return nil, nil, err
			}
		}
	}

	// create first snapshot
	snap = new(Snapshot)
	snap.Index = 0
	snap.Roots.History = balloon.history.Root()
	snap.Roots.Treap = balloon.treap.Root()
	snap.Roots.Version = balloon.history.LatestVersion()
	snap.Previous = nil

	signature, err := util.Sign(balloon.sk,
		append(append([]byte("snapshot"), snap.Roots.History...), append(snap.Roots.Treap, snap.Previous...)...))
	if err != nil {
		panic(err)
	}
	snap.Signature = signature

	// actually store events
	err = balloon.Storage.Store(events, *snap)
	if err != nil {
		return nil, nil, err
	}
	balloon.latestsnapshot = *snap
	if len(events) > 0 {
		balloon.latesteventkey = events[len(events)-1].Key
	}

	return
}
Beispiel #3
0
func TestEqualSnapshot(t *testing.T) {
	size := 10
	sk, vk, err := Genkey()
	if err != nil {
		t.Fatalf("failed to generate keys: %s", err)
	}
	balloon, s0, err := Setup(nil, sk, vk, NewTestEventStorage())
	if err != nil {
		t.Fatalf("failed to setup balloon: %s", err)
	}
	events := make([]Event, size)
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}

	s1, err := balloon.Update(events, s0, sk)
	if err != nil {
		t.Fatalf("failed to update to s1: %s", err)
	}

	if !s1.Equal(s1) {
		t.Fatal("the smae snapshot is not equal with itself")
	}
	if s1.Equal(s0) {
		t.Fatal("two different snapshots are equal")
	}
}
Beispiel #4
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 #5
0
// QueryPrune performs a prune query for a slice of events. Returns an answer indicating
// if the events can be added and a proof.
// Run by the server on untrusted input. The minimalProof flag trades a small amount
// of computation for a significantly smaller proof (the more events, the bigger the reduction).
func (balloon *Balloon) QueryPrune(events []Event, vk []byte,
	minimalProof bool) (answer bool, proof PruneProof) {
	// query hash treap
	treapKeys := make([][]byte, len(events))
	for i := 0; i < len(events); i++ {
		treapKeys[i] = util.Hash(events[i].Key)
	}
	answer, proof.TreapProof = balloon.treap.QueryPrune(treapKeys, minimalProof)

	// if we found a member among the keys, then the proof is done shows that it is not
	// posssible to insert the set of events
	if !answer {
		return
	}

	// we only need/can extract the latest event, whose membership query fixes the history
	// tree, if there is at least one event in the Balloon
	if balloon.Size() > 0 {
		members, qevent, qproof, err := balloon.QueryMembership(balloon.latesteventkey,
			&balloon.latestsnapshot, vk)
		if err != nil {
			panic(err)
		}
		if !members {
			panic("an event that should be a member is not")
		}
		if !util.Equal(balloon.latesteventkey, qevent.Key) {
			panic("events differ")
		}
		proof.QueryProof = qproof
		proof.Event = *qevent
	}

	return
}
Beispiel #6
0
func (t *HashTreap) verifiablyGet(key []byte) (value []byte, valid bool) {
	n := t.root
	for n != nil {
		// verify the node we are at
		var left, right []byte
		left = NoNodeHash
		right = NoNodeHash
		if n.left != nil {
			left = n.left.hash
		}
		if n.right != nil {
			right = n.right.hash
		}
		// verify the hash
		if !util.Equal(n.hash, util.Hash(n.key, n.value, left, right)) {
			return nil, false
		}

		c := bytes.Compare(key, n.key)
		if c < 0 {
			n = n.left
		} else if c > 0 {
			n = n.right
		} else {
			return n.value, true
		}
	}
	return nil, true
}
Beispiel #7
0
func (t *HashTreap) upsert(key, value []byte) *HashTreap {
	r := t.union(t.root, &node{
		key:      key,
		value:    value,
		priority: util.Hash(key),
		taint:    true,
	})
	return &HashTreap{root: r, size: t.Size() + 1}
}
Beispiel #8
0
// Update creates the next snapshot from adding the provided events in the balloon
// fixed by the current snapshot. This function depends on that the provided prune proof has
// been successfully verified for the answer true.
// Run by the author on input that should have been verified before by using Verify.
func (proof *PruneProof) Update(events []Event, current *Snapshot,
	sk []byte) (next *Snapshot, err error) {

	sort.Sort(ByKey(events))

	// calculate balloon internal keys and values based on events
	startIndex := current.Roots.Version + 1
	values := make([][]byte, len(events))
	treapKeys := make([][]byte, len(events))
	treapValues := make([][]byte, len(events))
	for i := 0; i < len(events); i++ {
		values[i] = util.Hash(append(events[i].Key, events[i].Value...))
		treapKeys[i] = util.Hash(events[i].Key)
		treapValues[i] = util.Itob(startIndex + i)
	}

	// calculate updated commitment on the history tree
	c, version, err := proof.QueryProof.HistoryProof.Update(values)
	if err != nil {
		return nil, err
	}

	// calculate updated hash treap root
	root, err := proof.TreapProof.Update(treapKeys, treapValues)
	if err != nil {
		return nil, err
	}

	next = new(Snapshot)
	next.Index = current.Index + 1
	next.Roots.History = c
	next.Roots.Treap = root
	next.Roots.Version = version
	next.Previous = current.Signature
	signature, err := util.Sign(sk,
		append(append([]byte("snapshot"), next.Roots.History...),
			append(next.Roots.Treap, next.Previous...)...))
	if err != nil {
		panic(err)
	}
	next.Signature = signature

	return
}
Beispiel #9
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 #10
0
// layeR, Index, Version
// See Figure 5 in "Efficient Data Structures for Tamper-Evident Logging"
func (t *Tree) getHashedNode(index, layer, version int, proofMode bool) (value []byte, err error) {
	// always prefer frozen hashes, if we have calculated them
	if proofMode || version >= index+util.Pow(2, layer)-1 {
		if t.isFrozenHash(index, layer) {
			return t.getFrozenHash(index, layer)
		}
	}

	// special case for child nodes
	if layer == 0 && version >= index {
		event, err := t.getEvent(index)
		if err != nil {
			return nil, errors.New("no event with the provided index")
		}

		value = util.Hash(prefixZero, event)
		// have version determine if the right node is there or not
	} else if version >= index+util.Pow(2, layer-1) {
		a1, err := t.getHashedNode(index, layer-1, version, proofMode)
		if err != nil {
			return nil, errors.New("failed to get internal node with index " + strconv.Itoa(index))
		}
		a2, err := t.getHashedNode(index+util.Pow(2, layer-1), layer-1, version, proofMode)
		if err != nil {
			return nil, errors.New("failed to get internal node with index " + strconv.Itoa(index))
		}

		value = util.Hash(prefixOne, a1, a2)
	} else {
		a, err := t.getHashedNode(index, layer-1, version, proofMode)
		if err != nil {
			return nil, errors.New("failed to get internal node with index " + strconv.Itoa(index))
		}
		value = util.Hash(prefixOne, a)
	}

	// should we add this to the frozen hash cache?
	if version >= index+util.Pow(2, layer)-1 {
		t.setFrozenHash(index, layer, value)
	}

	return
}
Beispiel #11
0
func TestPrune(t *testing.T) {
	size := 3
	runs := 4
	sk, vk, err := Genkey()
	if err != nil {
		t.Fatalf("failed to generate keys: %s", err)
	}
	_, current, err := Setup(nil, sk, vk, NewTestEventStorage())
	if err != nil {
		t.Fatalf("failed to setup balloon: %s", err)
	}

	server := NewBalloon(NewTestEventStorage())
	if !server.RefreshVerify(nil, nil, current, vk) {
		t.Fatal("failed to refresh to s0")
	}

	for i := 1; i <= runs; i++ {
		events := make([]Event, size)
		for j := 0; j < size; j++ {
			k := make([]byte, util.HashOutputLen)
			_, err = rand.Read(k)
			if err != nil {
				t.Fatalf("failed to read random bytes: %s", err)
			}
			events[j].Key = k
			events[j].Value = util.Hash(k)
		}

		answer, proof := server.QueryPrune(events, vk, true)
		if !answer {
			t.Fatalf("cannot update a prune proof on run %d", i)
		}

		if !proof.Verify(events, answer, current, vk) {
			t.Fatalf("failed to verify prune proof on run %d", i)
		}

		next, err := proof.Update(events, current, sk)
		if err != nil {
			t.Fatalf("failed to update on run %d, error %s", i, err)
		}

		if !server.RefreshVerify(events, current, next, vk) {
			t.Fatalf("failed to refresh on run %d", i)
		}
		current = next
	}
}
Beispiel #12
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 #13
0
func (t *HashTreap) update(node *node) {
	if node.taint {
		left := NoNodeHash
		right := NoNodeHash
		if node.left != nil {
			t.update(node.left)
			left = node.left.hash
		}
		if node.right != nil {
			t.update(node.right)
			right = node.right.hash
		}

		node.hash = util.Hash(node.key, node.value, left, right)
		node.taint = false
	}
}
Beispiel #14
0
func (t *HashTreap) addProofNode(n *node, proofNode *ProofNode) *node {
	if n == nil {
		t.size++
		return &node{
			key:      proofNode.Key,
			value:    proofNode.Value,
			hash:     proofNode.Hash,
			priority: util.Hash(proofNode.Key),
			taint:    false,
		}
	}

	c := bytes.Compare(proofNode.Key, n.key)
	if c < 0 {
		n.left = t.addProofNode(n.left, proofNode)
	} else if c > 0 {
		n.right = t.addProofNode(n.right, proofNode)
	}

	return n
}
Beispiel #15
0
// Update updates the root hash of the hash treap to cover all nodes
// in the treap.
func (t *HashTreap) Update() {
	if t.root == nil {
		return
	}
	if t.root.left != nil {
		t.update(t.root.left)
	}
	if t.root.right != nil {
		t.update(t.root.right)
	}

	left := NoNodeHash
	right := NoNodeHash
	if t.root.left != nil {
		left = t.root.left.hash
	}
	if t.root.right != nil {
		right = t.root.right.hash
	}
	t.root.hash = util.Hash(t.root.key, t.root.value, left, right)
	t.root.taint = false
}
Beispiel #16
0
func TestClone(t *testing.T) {
	size := 10
	sk, vk, err := Genkey()
	if err != nil {
		t.Fatalf("failed to generate keys: %s", err)
	}
	balloon, s0, err := Setup(nil, sk, vk, NewTestEventStorage())
	if err != nil {
		t.Fatalf("failed to setup balloon: %s", err)
	}

	clone0 := balloon.Clone()
	if !clone0.latestsnapshot.Equal(s0) {
		t.Fatal("clone has different snapshot")
	}

	events := make([]Event, size)
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}
	s1, err := balloon.Update(events, s0, sk)
	if err != nil {
		t.Fatalf("failed to update to s1: %s", err)
	}
	s1c, err := clone0.Update(events, s0, sk)
	if err != nil {
		t.Fatalf("failed to update to s1: %s", err)
	}
	if !s1c.Equal(s1) {
		t.Fatal("clone has different snapshot")
	}
}
Beispiel #17
0
func TestPruneQueryProofFlip(t *testing.T) {
	/*
		Create a Balloon with size events.
	*/
	size := 10
	sk, vk, err := Genkey()
	if err != nil {
		t.Fatalf("failed to generate keys: %s", err)
	}
	balloon, s0, err := Setup(nil, sk, vk, NewTestEventStorage())
	if err != nil {
		t.Fatalf("failed to setup balloon: %s", err)
	}
	events := make([]Event, size)
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}
	s1, err := balloon.Update(events, s0, sk)
	if err != nil {
		t.Fatalf("failed to update to s1: %s", err)
	}

	// a prune query for new random events, to get paths in both the hash treap
	// and the history tree
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}
	answer, proof := balloon.QueryPrune(events, vk, true)
	if !proof.Verify(events, answer, s1, vk) {
		t.Fatal("failed to verify a valid query prune proof")
	}
	if !answer {
		t.Fatal("got a false reply to a prune query with old events")
	}

	/*
		OK, now we start systematically tampering with the proof and arguments
		to Verify to make sure that any changes are detected
	*/

	// flip answer
	if proof.Verify(events, !answer, s1, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}

	// flip every byte in the root of the history tree in the snapshot
	for i := range s1.Roots.History {
		s1.Roots.History[i] ^= 0x40
		if proof.Verify(events, answer, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Roots.History[i] ^= 0x40
	}

	// flip every byte in the root of the hash treap in the snapshot
	for i := range s1.Roots.Treap {
		s1.Roots.Treap[i] ^= 0x40
		if proof.Verify(events, answer, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Roots.Treap[i] ^= 0x40
	}

	// flip every byte in the signature of the snapshot
	for i := range s1.Signature {
		s1.Signature[i] ^= 0x40
		if proof.Verify(events, answer, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Signature[i] ^= 0x40
	}

	// flip every byte in the previous signature of the snapshot
	for i := range s1.Previous {
		s1.Previous[i] ^= 0x40
		if proof.Verify(events, answer, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Previous[i] ^= 0x40
	}

	// change the version of the snapshot
	s1.Roots.Version++
	if proof.Verify(events, answer, s1, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}
	s1.Roots.Version--

	// flip every byte in the verification key
	for i := range vk {
		vk[i] ^= 0x40
		if proof.Verify(events, answer, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		vk[i] ^= 0x40
	}

	// flip every byte in the event key in the proof
	for i := range proof.Event.Key {
		proof.Event.Key[i] ^= 0x40
		if proof.Verify(events, answer, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.Event.Key[i] ^= 0x40
	}

	// flip every byte in the event value in the proof
	for i := range proof.Event.Value {
		proof.Event.Value[i] ^= 0x40
		if proof.Verify(events, answer, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.Event.Value[i] ^= 0x40
	}

	// flip every byte in the key of the treap part of the proof
	for i := range proof.TreapProof.Key {
		proof.TreapProof.Key[i] ^= 0x40
		if proof.Verify(events, answer, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.TreapProof.Key[i] ^= 0x40
	}

	// for each node in the hash treap proof
	for i := range proof.TreapProof.Nodes {

		// flip every byte in the hash of the node
		for j := range proof.TreapProof.Nodes[i].Hash {
			proof.TreapProof.Nodes[i].Hash[j] ^= 0x40
			if proof.Verify(events, answer, s1, vk) {
				t.Fatal("verified an invalid proof and/or argument")
			}
			proof.TreapProof.Nodes[i].Hash[j] ^= 0x40
		}

		// Note that we _cannot_ detect flips in a proof node's key and value when
		// the node's key and value are only used to place the node's hash either
		// left or right along the verified authenticated path in the hash treap.
		// This is not a security issue for the queries that make up Balloon,
		// but very well may be for other types of queries not specified in the
		// design of Balloon.
	}

	// always possible to add no events
	if !proof.Verify(nil, true, s1, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}
}
Beispiel #18
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
}
Beispiel #19
0
func TestAdd(t *testing.T) {
	tree := NewTree()
	event0 := util.Hash([]byte("event 0"))
	event1 := util.Hash([]byte("event 1"))
	event2 := util.Hash([]byte("event 2"))
	event3 := util.Hash([]byte("event 3"))
	event4 := util.Hash([]byte("event 4"))

	c, err := tree.Add(event0)
	if err != nil {
		t.Fatalf("failed to add event to empty tree, error: %s", err)
	}

	// should be that c == H(0||event0)
	if !bytes.Equal(c, util.Hash(prefixZero, event0)) {
		t.Fatalf("the returned root for the first event is invalid")
	}

	c, err = tree.Add(event1)
	if err != nil {
		t.Fatalf("failed to add event to tree of size %d, error: %s", tree.Size(), err)
	}

	// should be that c == H(1||H(0||event0)||H(0||event1))
	if !bytes.Equal(c, util.Hash(prefixOne, util.Hash(prefixZero, event0),
		util.Hash(prefixZero, event1))) {
		t.Fatalf("the returned root for the second event is invalid, %d, %d",
			tree.getDepth(), tree.Size()-1)
	}
	c, err = tree.Add(event2)
	if err != nil {
		t.Fatalf("failed to add event to tree of size %d, error: %s", tree.Size(), err)
	}

	// should be that c == H(1||H(1||H(0||event0)||H(0||event1))||H(1||H(0||event2)))
	if !bytes.Equal(c, util.Hash(prefixOne,
		util.Hash(prefixOne, util.Hash(prefixZero, event0), util.Hash(prefixZero, event1)),
		util.Hash(prefixOne, util.Hash(prefixZero, event2)))) {
		t.Fatalf("the returned root for the third event is invalid, %d, %d",
			tree.getDepth(), tree.Size()-1)
	}

	c, err = tree.Add(event3)
	if err != nil {
		t.Fatalf("failed to add event to tree of size %d, error: %s", tree.Size(), err)
	}

	// should be that c == H(1||H(1||H(0||event0)||H(0||event1))
	// 						  ||H(1||H(0||event2)||H(0||event3)))
	if !bytes.Equal(c, util.Hash(prefixOne,
		util.Hash(prefixOne, util.Hash(prefixZero, event0),
			util.Hash(prefixZero, event1)),
		util.Hash(prefixOne, util.Hash(prefixZero, event2),
			util.Hash(prefixZero, event3)))) {
		t.Fatalf("the returned root for the fourth event is invalid, %d, %d",
			tree.getDepth(), tree.Size()-1)
	}

	c, err = tree.Add(event4)
	if err != nil {
		t.Fatalf("failed to add event to tree of size %d, error: %s", tree.Size(), err)
	}

	// should be that c == H(1||x||y), where
	// x = H(1||H(1||H(0||event0)||H(0||event1))
	// 		  ||H(1||H(0||event2)||H(0||event3)))
	// y = H(1||H(1||H(0||event4)))
	x := util.Hash(prefixOne,
		util.Hash(prefixOne, util.Hash(prefixZero, event0), util.Hash(prefixZero, event1)),
		util.Hash(prefixOne, util.Hash(prefixZero, event2), util.Hash(prefixZero, event3)))
	y := util.Hash(prefixOne, util.Hash(prefixOne, util.Hash(prefixZero, event4)))
	if !bytes.Equal(c, util.Hash(prefixOne, x, y)) {
		t.Fatalf("failed to add event to tree of size %d, error: %s", tree.Size(), err)
	}
}
Beispiel #20
0
func TestBalloonDetails(t *testing.T) {
	// More specific tests for test coverage
	// setup for an initially empty Balloon for an author
	sk, vk, err := Genkey()
	if err != nil {
		t.Fatalf("failed to generate keys: %s", err)
	}
	author, s0, err := Setup(nil, sk, vk, NewTestEventStorage())
	if err != nil {
		t.Fatalf("failed to setup balloon: %s", err)
	}

	// update the Balloon with some events
	size := 10
	events := make([]Event, size)
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}
	snapUpdate, err := author.Update(events, s0, sk)
	if err != nil {
		t.Fatalf("failed to update to s1: %s", err)
	}

	// create a second balloon, but use Setup directly
	_, snapSetup, err := Setup(events, sk, vk, NewTestEventStorage())
	if err != nil {
		t.Fatalf("failed to setup balloon: %s", err)
	}
	if snapUpdate.Roots.Version != snapSetup.Roots.Version ||
		!util.Equal(snapUpdate.Roots.History, snapSetup.Roots.History) ||
		!util.Equal(snapUpdate.Roots.Treap, snapSetup.Roots.Treap) {
		t.Fatal("snapshots using Update and Setup differ")
	}

	// Refresh
	server := NewBalloon(NewTestEventStorage())
	err = server.Refresh(nil, nil, s0, vk)
	if err != nil {
		t.Fatalf("failed to do initial refresh: %s", err)
	}
	err = server.Refresh(events, nil, snapUpdate, vk)
	if err == nil {
		t.Fatalf("did Refresh with wrong current snapshot")
	}
	err = server.Refresh(events, s0, snapUpdate, vk)
	if err != nil {
		t.Fatalf("failed to refresh from s0 to snapSetup: %s", err)
	}
	err = server.Refresh(events, nil, snapUpdate, vk)
	if err == nil {
		t.Fatalf("did Refresh with wrong current snapshot")
	}
	err = server.Refresh(events, snapUpdate, snapUpdate, vk)
	if err == nil {
		t.Fatalf("did Refresh with wrong current snapshot")
	}
	err = server.Refresh(events, s0, snapUpdate, vk)
	if err == nil {
		t.Fatalf("did Refresh with wrong current snapshot")
	}

	// Setup
	events = make([]Event, size)
	_, _, err = Setup(events, sk, vk, NewTestEventStorage())
	if err == nil {
		t.Fatal("successfully Setup with nil event keys and values")
	}

	// Update
	_, err = author.Update(events, snapUpdate, sk)
	if err == nil {
		t.Fatal("successfully Update with nil event keys and values")
	}
	_, err = author.Update(events, s0, sk)
	if err == nil {
		t.Fatal("successfully Update with old snapshot")
	}
	events = make([]Event, 0, size)
	_, err = author.Update(events, snapUpdate, sk)
	if err == nil {
		t.Fatal("successfully Update with no events")
	}

	// QueryMembership
	_, _, _, err = author.QueryMembership([]byte("too short key"), s0, vk)
	if err == nil {
		t.Fatalf("membership query for too short key: %s", err)
	}
	// flip every byte in the signature of the snapshot
	for i := range s0.Signature {
		s0.Signature[i] ^= 0x40
		_, _, _, err = author.QueryMembership(util.Hash([]byte("a valid key")), s0, vk)
		if err == nil {
			t.Fatalf("membership query for invalid signature: %s", err)
		}
		s0.Signature[i] ^= 0x40
	}
}
Beispiel #21
0
func TestMembershipQueryProofFlip(t *testing.T) {
	/*
		Create a Balloon with size events.
	*/

	size := 10
	sk, vk, err := Genkey()
	if err != nil {
		t.Fatalf("failed to generate keys: %s", err)
	}
	balloon, s0, err := Setup(nil, sk, vk, NewTestEventStorage())
	if err != nil {
		t.Fatalf("failed to setup balloon: %s", err)
	}
	events := make([]Event, size)
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}
	s1, err := balloon.Update(events, s0, sk)
	if err != nil {
		t.Fatalf("failed to update to s1: %s", err)
	}

	// create a membership query for an event that exists, such that
	// the proof consists of nodes in both the hash treap and the
	// history tree
	answer, event, proof, err := balloon.QueryMembership(events[0].Key, s1, vk)
	if err != nil {
		t.Fatalf("failed to perform membership query: %s", err)
	}

	if !proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
		t.Fatal("failed to verify valid membership proof and arguments")
	}

	/*
		OK, now we start systematically tampering with the proof and arguments
		to Verify to make sure that any changes are detected
	*/

	// flip every byte in the key
	for i := range events[0].Key {
		events[0].Key[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		events[0].Key[i] ^= 0x40
	}

	// flip every byte in the root of the history tree in the snapshot
	for i := range s1.Roots.History {
		s1.Roots.History[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Roots.History[i] ^= 0x40
	}

	// flip every byte in the root of the hash treap in the snapshot
	for i := range s1.Roots.Treap {
		s1.Roots.Treap[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Roots.Treap[i] ^= 0x40
	}

	// flip every byte in the signature of the snapshot
	for i := range s1.Signature {
		s1.Signature[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		if proof.Verify(events[0].Key, s0, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Signature[i] ^= 0x40
	}

	// flip every byte in the previous signature of the snapshot
	for i := range s1.Previous {
		s1.Previous[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		if proof.Verify(events[0].Key, s0, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Previous[i] ^= 0x40
	}

	// change the version of the snapshot
	s1.Roots.Version++
	if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}
	s1.Roots.Version--

	// flip answer
	if proof.Verify(events[0].Key, s1, s1, !answer, event, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}

	// flip every byte in the event key
	for i := range event.Key {
		event.Key[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		event.Key[i] ^= 0x40
	}

	// flip every byte in the event value
	for i := range event.Value {
		event.Value[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		event.Value[i] ^= 0x40
	}

	// flip every byte in the verification key
	for i := range vk {
		vk[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		vk[i] ^= 0x40
	}

	// flip every byte in event of the history tree proof
	for i := range proof.HistoryProof.Event {
		proof.HistoryProof.Event[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.HistoryProof.Event[i] ^= 0x40
	}

	// flip every byte in root of the history tree proof
	for i := range proof.HistoryProof.Root {
		proof.HistoryProof.Root[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.HistoryProof.Root[i] ^= 0x40
	}

	// flip the index history tree proof
	proof.HistoryProof.Index++
	if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}
	proof.HistoryProof.Index--

	// flip the version history tree proof
	proof.HistoryProof.Version++
	if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}
	proof.HistoryProof.Version--

	// for each node in the history tree proof
	for i := range proof.HistoryProof.Nodes {

		// flip each byte in the hash of the node
		for j := range proof.HistoryProof.Nodes[i].Hash {
			proof.HistoryProof.Nodes[i].Hash[j] ^= 0x40
			if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
				t.Fatal("verified an invalid proof and/or argument")
			}
			proof.HistoryProof.Nodes[i].Hash[j] ^= 0x40
		}

		// flip index in position
		proof.HistoryProof.Nodes[i].Position.Index++
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.HistoryProof.Nodes[i].Position.Index--

		// flip layer in position
		proof.HistoryProof.Nodes[i].Position.Layer++
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.HistoryProof.Nodes[i].Position.Layer--
	}

	// flip every byte in the key of the hash treap proof
	for i := range proof.TreapProof.Key {
		proof.TreapProof.Key[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.TreapProof.Key[i] ^= 0x40
	}

	// flip every byte in the value of the hash treap proof
	for i := range proof.TreapProof.Value {
		proof.TreapProof.Value[i] ^= 0x40
		if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.TreapProof.Value[i] ^= 0x40
	}

	// for each node in the hash treap proof
	for i := range proof.TreapProof.Nodes {

		// flip every byte in the hash of the node
		for j := range proof.TreapProof.Nodes[i].Hash {
			proof.TreapProof.Nodes[i].Hash[j] ^= 0x40
			if proof.Verify(events[0].Key, s1, s1, answer, event, vk) {
				t.Fatal("verified an invalid proof and/or argument")
			}
			proof.TreapProof.Nodes[i].Hash[j] ^= 0x40
		}

		// Note that we _cannot_ detect flips in a proof node's key and value when
		// the node's key and value are only used to place the node's hash either
		// left or right along the verified authenticated path in the hash treap.
		// This is not a security issue for the queries that make up Balloon,
		// but very well may be for other types of queries not specified in the
		// design of Balloon.
	}

}
Beispiel #22
0
func TestAdd(t *testing.T) {
	value := util.Itob(42)
	tree := NewHashTreap()

	k0 := util.Itob(0) // priority 1b7409ccf0d5a34d3a77eaabfa9fe27427655be9297127ee9522aa1bf4046d4f
	t.Logf("priority of k0 is %s", hex.EncodeToString(util.Hash(k0)))
	k1 := util.Itob(1) // priority aa826d9d5f563309b4a9043987ff0d87e82d32d2ddc813aab7defe15f9062911
	t.Logf("priority of k1 is %s", hex.EncodeToString(util.Hash(k1)))
	k2 := util.Itob(2) // priority 8c7471bddfd31fa1e83a761a2f5bc2fc772a5567c85b3a753d3b8a2e8259386f
	t.Logf("priority of k2 is %s", hex.EncodeToString(util.Hash(k2)))
	k3 := util.Itob(3) // priority f6ec9d10ae03d32f6b31ae37322b629ec7caad83dd3c5dd870df8e6fd13a5a51
	t.Logf("priority of k3 is %s", hex.EncodeToString(util.Hash(k3)))
	k4 := util.Itob(4) // priority 2a364b052431533577431129ac1acce106dd019245de82ad97663290b5dbb9cc
	t.Logf("priority of k4 is %s", hex.EncodeToString(util.Hash(k4)))

	tree.Update()
	if tree.Root() != nil {
		t.Fatal("empty tree returned non-nil root")
	}

	tree, err := tree.Add(k0, value)
	if err != nil {
		t.Fatalf("failed to add key in empty tree: %s", err)
	}
	// should be that root == H(k0||value||NoNodeHash||NoNodeHash)
	if !bytes.Equal(tree.Root(), util.Hash(k0, value, NoNodeHash, NoNodeHash)) {
		t.Fatalf("the root of the tree of size %d is invalid", tree.Size())
	}

	tree, err = tree.Add(k1, value)
	if err != nil {
		t.Fatalf("failed to add key in tree of length %d: %s", tree.Size(), err)
	}
	tree.Update()
	// k1 > k0, and k0 has a smaller priority than k1, so the tree is:
	//      k1
	//     /
	//   k0
	// it should be that root = H(k1||value|| H(k0||value||NoNodeHash||NoNodeHash)|| NoNodeHash)
	if !bytes.Equal(tree.Root(), util.Hash(k1, value,
		util.Hash(k0, value, NoNodeHash, NoNodeHash), NoNodeHash)) {
		t.Fatalf("the root of the tree of size %d is invalid", tree.Size())
	}

	tree, err = tree.Add(k2, value)
	if err != nil {
		t.Fatalf("failed to add key in tree of length %d: %s", tree.Size(), err)
	}
	tree.Update()
	// k2 > k1 > k0, and priority is k1 > k2 > k0, so the tree is:
	//      k1
	//     /  \
	//   k0    k2
	// it should be that root = H(k1||value||
	//                          H(k0||value||NoNodeHash||NoNodeHash)||
	// 							H(k2||value||NoNodeHash||NoNodeHash))
	if !bytes.Equal(tree.Root(), util.Hash(k1, value,
		util.Hash(k0, value, NoNodeHash, NoNodeHash),
		util.Hash(k2, value, NoNodeHash, NoNodeHash))) {
		t.Fatalf("the root of the tree of size %d is invalid", tree.Size())
	}

	tree, err = tree.Add(k3, value)
	if err != nil {
		t.Fatalf("failed to add key in tree of length %d: %s", tree.Size(), err)
	}
	tree.Update()
	// k3 > k2 > k1 > k0, and priority is k3 > k1 > k2 > k0, so the tree is:
	//         k3
	//        /
	//      k1
	//     /  \
	//   k0    k2
	// it should be that root = H(k3||value||
	//                          H(k1||value||
	//                          H(k0||value||NoNodeHash||NoNodeHash)||
	// 							H(k2||value||NoNodeHash||NoNodeHash))||
	//                          NoNodeHash)
	if !bytes.Equal(tree.Root(), util.Hash(k3, value, util.Hash(k1, value,
		util.Hash(k0, value, NoNodeHash, NoNodeHash),
		util.Hash(k2, value, NoNodeHash, NoNodeHash)),
		NoNodeHash)) {
		t.Fatalf("the root of the tree of size %d is invalid", tree.Size())
	}

	tree, err = tree.Add(k4, value)
	if err != nil {
		t.Fatalf("failed to add key in tree of length %d: %s", tree.Size(), err)
	}
	tree.Update()
	// k4 > k3 > k2 > k1 > k0, and priority is k3 > k1 > k2 > k4 > k0, so the tree is:
	//         k3
	//        /  \
	//      k1    k4
	//     /  \
	//   k0    k2
	// it should be that root = H(k3||value||
	//                          H(k1||value||
	//                          H(k0||value||NoNodeHash||NoNodeHash)||
	// 							H(k2||value||NoNodeHash||NoNodeHash))||
	//                          H(k4||value||NoNodeHash||NoNodeHash))
	if !bytes.Equal(tree.Root(), util.Hash(k3, value, util.Hash(k1, value,
		util.Hash(k0, value, NoNodeHash, NoNodeHash),
		util.Hash(k2, value, NoNodeHash, NoNodeHash)),
		util.Hash(k4, value, NoNodeHash, NoNodeHash))) {
		t.Fatalf("the root of the tree of size %d is invalid", tree.Size())
	}

	_, err = tree.Add(nil, nil)
	if err == nil {
		t.Fatal("added (nil,nil) without an error")
	}
	_, err = tree.Add(k4, value)
	if err == nil {
		t.Fatal("successfully added a node with the same key twice")
	}

	if tree.Get([]byte("a key not there")) != nil {
		t.Fatal("got value for key not in the hash treap")
	}
}
Beispiel #23
0
func TestBalloon(t *testing.T) {
	/*
		Basics
	*/

	sk, vk, err := Genkey()
	if err != nil {
		t.Fatalf("failed to generate keys: %s", err)
	}

	// setup for an initially empty Balloon for the author
	author, s0, err := Setup(nil, sk, vk, NewTestEventStorage())
	if err != nil {
		t.Fatalf("failed to setup balloon: %s", err)
	}

	// update the Balloon with some events
	size := 10
	events := make([]Event, size)
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}
	s1, err := author.Update(events, s0, sk)
	if err != nil {
		t.Fatalf("failed to update to s1: %s", err)
	}

	// for the server, create an empty balloon
	server := NewBalloon(NewTestEventStorage())

	// refresh with the initial empty events
	err = server.Refresh(nil, nil, s0, vk)
	if err != nil {
		t.Fatalf("failed to do initial refresh: %s", err)
	}

	// refresh with events
	err = server.Refresh(events, s0, s1, vk)
	if err != nil {
		t.Fatalf("failed to do refresh from s0 to s1: %s", err)
	}

	// create some more events, update, and refresh
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}
	s2, err := author.Update(events[:1], s1, sk)
	if err != nil {
		t.Fatalf("failed to update to 2: %s", err)
	}
	// refresh with events
	err = server.Refresh(events[:1], s1, s2, vk)
	if err != nil {
		t.Fatalf("failed to do refresh from s1 to s2: %s", err)
	}

	/*
		Membership queries
	*/

	// check if the event we just inserted into the Balloon exists in the latest snapshot
	answer, event, proof, err := server.QueryMembership(events[0].Key, s2, vk)
	if err != nil {
		t.Fatalf("failed to perform a membership query: %s", err)
	}
	if !answer {
		t.Fatal("got a false answer for a membership query that should have answered true")
	}
	if event == nil {
		t.Fatal("got an empty event for a membership query that should have returned an event")
	}
	if !proof.Verify(events[0].Key, s2, s2, answer, event, vk) {
		t.Fatal("failed to verify valid membership proof")
	}
	if proof.Size() == 0 {
		t.Fatal("expected a non-zero sized membership proof")
	}

	// query for same event in previous snapshot, where it should not exist
	answer, event, proof, err = server.QueryMembership(events[0].Key, s1, vk)
	if err != nil {
		t.Fatalf("failed to perform a membership query: %s", err)
	}
	if answer {
		t.Fatal("got a true answer for a membership query that should have answered false")
	}
	if event != nil {
		t.Fatal("got an event for a membership query that should have not returned an event")
	}
	if !proof.Verify(events[0].Key, s1, s2, answer, event, vk) {
		t.Fatal("failed to verify valid membership proof")
	}

	// query for a random key in latest snapshot
	key := make([]byte, util.HashOutputLen)
	_, err = rand.Read(key)
	if err != nil {
		t.Fatalf("failed to read random bytes: %s", err)
	}
	answer, event, proof, err = server.QueryMembership(key, s2, vk)
	if err != nil {
		t.Fatalf("failed to perform a membership query: %s", err)
	}
	if answer {
		t.Fatal("got a true answer for a membership query that should have answered false")
	}
	if event != nil {
		t.Fatal("got an event for a membership query that should have not returned an event")
	}
	if !proof.Verify(key, s2, s2, answer, event, vk) {
		t.Fatal("failed to verify valid membership proof")
	}

	// query for the random key in a prior snapshot
	answer, event, proof, err = server.QueryMembership(key, s1, vk)
	if err != nil {
		t.Fatalf("failed to perform a membership query: %s", err)
	}
	if answer {
		t.Fatal("got a true answer for a membership query that should have answered false")
	}
	if event != nil {
		t.Fatal("got an event for a membership query that should have not returned an event")
	}
	if !proof.Verify(key, s1, s2, answer, event, vk) {
		t.Fatal("failed to verify valid membership proof")
	}

	/*
		Pruned queries
	*/

	// start with a prune query for events already inserted
	answer, pproof := server.QueryPrune(events, vk, true)
	if !pproof.Verify(events, answer, s2, vk) {
		t.Fatal("failed to verify a valid query prune proof")
	}
	if answer {
		t.Fatal("got a true reply to a prune query with old events")
	}
	if pproof.Size() == 0 {
		t.Fatal("expected a non-zero sized membership proof")
	}

	// randomise events
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}
	// query again
	answer, pproof = server.QueryPrune(events, vk, true)
	if !pproof.Verify(events, answer, s2, vk) {
		t.Fatal("failed to verify a valid query prune proof")
	}
	if !answer {
		t.Fatal("got a false reply to a prune query with random events")
	}

	/*
		Update using pruned queries
	*/

	s3u, err := pproof.Update(events, s2, sk)
	if err != nil {
		t.Fatalf("failed to update using prune: %s", err)
	}
	s3, err := author.Update(events, s2, sk)
	if err != nil {
		t.Fatalf("failed to update to 3: %s", err)
	}

	if !util.Equal(s3.Roots.History, s3u.Roots.History) {
		t.Fatal("Update (prune) produced a different history tree root")
	}
	if !util.Equal(s3.Roots.Treap, s3u.Roots.Treap) {
		t.Fatal("Update (prune) produced a different hash treap root")
	}
	if s3.Roots.Version != s3u.Roots.Version {
		t.Fatal("Update (prune) produced a different version")
	}

	/*
		Use RefreshVerify at the server
	*/

	if !server.RefreshVerify(events, s2, s3, vk) {
		t.Fatal("failed to refresh verify at server from 2 to 3")
	}
}
Beispiel #24
0
func TestPruneQuery(t *testing.T) {
	count := 1024
	treap := NewHashTreap()
	ints := mrand.Perm(count)
	var err error
	for i := 0; i < len(ints); i++ {
		treap, err = treap.Add(util.Itob(i), util.Itob(i))
		if err != nil {
			t.Fatalf("failed to add to hash treap: %s", err)
		}
	}
	treap.Update()

	// size new random events
	size := 42
	keys := make([][]byte, size)
	values := make([][]byte, size)
	for i := 0; i < size; i++ {
		keys[i] = make([]byte, util.HashOutputLen)
		_, err = rand.Read(keys[i])
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		values[i] = util.Hash(keys[i])
	}

	// query for new events
	possible, proof := treap.QueryPrune(keys, true)
	if !possible {
		t.Fatal("not possible to add random keys, highly unlikely")
	}
	if !proof.Verify(keys, possible, treap.Root()) {
		t.Fatal("failed to verify valid proof")
	}
	if proof.Size() <= 0 {
		t.Fatal("size of proof too small")
	}

	root, err := proof.Update(keys, values)
	if err != nil {
		t.Fatalf("failed to calculate an updated root from a pruned proof: %s", err)
	}

	// calculate root to compare with
	for i := 0; i < len(keys); i++ {
		treap, err = treap.Add(keys[i], values[i])
		if err != nil {
			t.Fatalf("failed to add to hash treap: %s", err)
		}
	}
	treap.Update()
	if !bytes.Equal(treap.Root(), root) {
		t.Fatal("pruned root and actual root differs")
	}

	// test when the prune query should prove that it is not possible
	possible, proof = treap.QueryPrune(keys, true)
	if possible {
		t.Fatal("possible to add key that was just added")
	}
	if !proof.Verify(keys, possible, treap.Root()) {
		t.Fatal("failed to verify valid proof")
	}
	if proof.Size() <= 0 {
		t.Fatal("size of proof too small")
	}
	// ignore what the proof said, try to update
	_, err = proof.Update(keys, values)
	if err == nil {
		t.Fatal("managed to calculate updated root when adding key already in place")
	}
	// all proofs show that we can add no keys
	if !proof.Verify(nil, true, treap.Root()) {
		t.Fatal("failed to verify valid proof")
	}

	// flip every byte in the key of the proof
	for i := range proof.Key {
		proof.Key[i] ^= 0x40
		if proof.Verify(keys, possible, treap.Root()) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		proof.Key[i] ^= 0x40
	}

	// treap.Root() and the hash in the first proof node point to the same slice,
	// so we need to make a copy, otherwise we change both...
	root = make([]byte, len(treap.Root()))
	copy(root, treap.Root())
	for i := range proof.Nodes {
		// flip every byte in the hash of the node
		for j := range proof.Nodes[i].Hash {
			proof.Nodes[i].Hash[j] ^= 0x40
			if proof.Verify(keys, possible, root) {
				t.Fatal("verified an invalid proof and/or argument")
			}
			proof.Nodes[i].Hash[j] ^= 0x40
		}
	}
}
Beispiel #25
0
func TestRefreshVerifyFlip(t *testing.T) {
	size := 10
	sk, vk, err := Genkey()
	if err != nil {
		t.Fatalf("failed to generate keys: %s", err)
	}
	balloon, s0, err := Setup(nil, sk, vk, NewTestEventStorage())
	if err != nil {
		t.Fatalf("failed to setup balloon: %s", err)
	}
	events := make([]Event, size)
	for i := 0; i < size; i++ {
		k := make([]byte, util.HashOutputLen)
		_, err = rand.Read(k)
		if err != nil {
			t.Fatalf("failed to read random bytes: %s", err)
		}
		events[i].Key = k
		events[i].Value = util.Hash(k)
	}

	s1, err := balloon.Update(events, s0, sk)
	if err != nil {
		t.Fatalf("failed to update to s1: %s", err)
	}

	server := NewBalloon(NewTestEventStorage())
	if !server.RefreshVerify(nil, nil, s0, vk) {
		t.Fatalf("failed to do initial refresh: %s", err)
	}
	clone := server.Clone()
	if !server.RefreshVerify(events, s0, s1, vk) {
		t.Fatalf("failed to do initial refresh: %s", err)
	}

	// flip events
	for i := range events {
		for j := range events[i].Key {
			// we need to do this since sort in RefreshVerify
			// may change the order of the slice based on key or value
			key := events[i].Key
			key[j] ^= 0x40
			if clone.RefreshVerify(events, s0, s1, vk) {
				t.Fatal("verified an invalid proof and/or argument")
			}
			key[j] ^= 0x40
		}

		for j := range events[i].Value {
			value := events[i].Value
			value[j] ^= 0x40
			if clone.RefreshVerify(events, s0, s1, vk) {
				t.Fatal("verified an invalid proof and/or argument")
			}
			value[j] ^= 0x40
		}
	}

	// flip snapshot s0
	s0.Index++
	if clone.RefreshVerify(events, s0, s1, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}
	s0.Index--
	s0.Roots.Version++
	if clone.RefreshVerify(events, s0, s1, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}
	s0.Roots.Version--
	for i := range s0.Roots.History {
		s0.Roots.History[i] ^= 0x40
		if clone.RefreshVerify(events, s0, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s0.Roots.History[i] ^= 0x40
	}
	for i := range s0.Roots.Treap {
		s0.Roots.Treap[i] ^= 0x40
		if clone.RefreshVerify(events, s0, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s0.Roots.Treap[i] ^= 0x40
	}
	for i := range s0.Signature {
		s0.Signature[i] ^= 0x40
		if clone.RefreshVerify(events, s0, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s0.Signature[i] ^= 0x40
	}

	// flip snapshot s1
	s1.Index++
	if clone.RefreshVerify(events, s0, s1, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}
	s1.Index--
	s1.Roots.Version++
	if clone.RefreshVerify(events, s0, s1, vk) {
		t.Fatal("verified an invalid proof and/or argument")
	}
	s1.Roots.Version--
	for i := range s1.Roots.History {
		s1.Roots.History[i] ^= 0x40
		if clone.RefreshVerify(events, s0, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Roots.History[i] ^= 0x40
	}
	for i := range s1.Roots.Treap {
		s1.Roots.Treap[i] ^= 0x40
		if clone.RefreshVerify(events, s0, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Roots.Treap[i] ^= 0x40
	}
	for i := range s1.Signature {
		s1.Signature[i] ^= 0x40
		if clone.RefreshVerify(events, s0, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Signature[i] ^= 0x40
	}
	for i := range s1.Previous {
		s1.Previous[i] ^= 0x40
		if clone.RefreshVerify(events, s0, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		s1.Previous[i] ^= 0x40
	}

	// flip verification key
	for i := range vk {
		vk[i] ^= 0x40
		if clone.RefreshVerify(events, s0, s1, vk) {
			t.Fatal("verified an invalid proof and/or argument")
		}
		vk[i] ^= 0x40
	}

	// see that the clone works
	if !clone.RefreshVerify(events, s0, s1, vk) {
		t.Fatal("broken clone")
	}
}