Пример #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
}
Пример #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
}
Пример #3
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
}
Пример #4
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
		}
	}
}
Пример #5
0
func TestMembershipQuery(t *testing.T) {
	keys := 1024
	treap := NewHashTreap()

	// test in an empty hash treap
	proof := treap.MembershipQuery(util.Itob(keys + 42))
	if proof.Value != nil {
		t.Fatalf("a membership query for a non-member key %d returned a non-membership proof", keys+42)
	}
	if !proof.Verify(util.Itob(keys+42), treap.Root()) {
		t.Fatalf("failed to verify a membership query proof for key %d that was just added", keys+42)
	}

	// create a hash treap with a static number of keys in a random permutation
	// (note that a hash treap is set unique so the same hash treap is always tested)
	ints := mrand.Perm(keys)
	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()

	// test queries proving membership
	for _, i := range ints {
		proof := treap.MembershipQuery(util.Itob(i))
		if proof.Value == nil {
			t.Fatalf("a membership query for member key %d returned a non-membership proof", i)
		}
		if !proof.Verify(util.Itob(i), treap.Root()) {
			t.Fatalf("failed to verify a membership query proof for key %d that was just added", i)
		}
	}

	// test queries proving non-membership
	for i := keys; i < 2*keys; i++ {
		proof := treap.MembershipQuery(util.Itob(i))
		if proof.Value != nil {
			t.Fatalf("got a membership proof for a non-member key %d", i)
		}
		if !proof.Verify(util.Itob(i), treap.Root()) {
			t.Fatalf("failed to verify a non-membership query proof for a key %d that is not a member", i)
		}
		if proof.Size() <= 0 {
			t.Fatal("size of proof too small")
		}
	}

	// test bit-flips in queries proving membership
	for i := 0; i < 4; i++ {
		proof := treap.MembershipQuery(util.Itob(ints[i]))
		root := make([]byte, len(treap.Root()))
		copy(root, treap.Root())

		// flip every byte in the proof key
		for j := range proof.Key {
			proof.Key[j] ^= 0x40
			if proof.Verify(util.Itob(ints[i]), root) {
				t.Fatal("verified an invalid proof and/or argument")
			}
			proof.Key[j] ^= 0x40
		}

		// flip every byte in the proof value
		for j := range proof.Value {
			proof.Value[j] ^= 0x40
			if proof.Verify(util.Itob(ints[i]), root) {
				t.Fatal("verified an invalid proof and/or argument")
			}
			proof.Value[j] ^= 0x40
		}

		// for each node in the hash treap proof
		for j := range proof.Nodes {
			// flip every byte in the hash of the node
			for k := range proof.Nodes[j].Hash {
				proof.Nodes[j].Hash[k] ^= 0x40
				if proof.Verify(util.Itob(ints[i]), root) {
					t.Fatal("verified an invalid proof and/or argument")
				}
				proof.Nodes[j].Hash[k] ^= 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 an issue for the security of a membership query.
		}
	}
}
Пример #6
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")
	}
}
Пример #7
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
}