Example #1
0
    def test_pack(self):
        data = {"stuff": "value", "size": 12, "needed_shares": 3, "big_hash": hashutil.tagged_hash("foo", "bar")}
        ext = uri.pack_extension(data)
        d = uri.unpack_extension(ext)
        self.failUnlessReallyEqual(d["stuff"], "value")
        self.failUnlessReallyEqual(d["size"], 12)
        self.failUnlessReallyEqual(d["big_hash"], hashutil.tagged_hash("foo", "bar"))

        readable = uri.unpack_extension_readable(ext)
        self.failUnlessReallyEqual(readable["needed_shares"], 3)
        self.failUnlessReallyEqual(readable["stuff"], "value")
        self.failUnlessReallyEqual(readable["size"], 12)
        self.failUnlessReallyEqual(readable["big_hash"], base32.b2a(hashutil.tagged_hash("foo", "bar")))
        self.failUnlessReallyEqual(readable["UEB_hash"], base32.b2a(hashutil.uri_extension_hash(ext)))
Example #2
0
    def make_client(self, i, write_config=True):
        clientid = hashutil.tagged_hash("clientid", str(i))[:20]
        clientdir = os.path.join(self.basedir, "clients",
                                 idlib.shortnodeid_b2a(clientid))
        fileutil.make_dirs(clientdir)

        tahoe_cfg_path = os.path.join(clientdir, "tahoe.cfg")
        if write_config:
            f = open(tahoe_cfg_path, "w")
            f.write("[node]\n")
            f.write("nickname = client-%d\n" % i)
            f.write("web.port = tcp:0:interface=127.0.0.1\n")
            f.write("[storage]\n")
            f.write("enabled = false\n")
            f.close()
        else:
            _assert(os.path.exists(tahoe_cfg_path), tahoe_cfg_path=tahoe_cfg_path)

        c = None
        if i in self.client_config_hooks:
            # this hook can either modify tahoe.cfg, or return an
            # entirely new Client instance
            c = self.client_config_hooks[i](clientdir)

        if not c:
            c = NoNetworkClient(clientdir)
            c.set_default_mutable_keysize(TEST_RSA_KEY_SIZE)

        c.nodeid = clientid
        c.short_nodeid = b32encode(clientid).lower()[:8]
        c._servers = self.all_servers # can be updated later
        c.setServiceParent(self)
        return c
Example #3
0
    def make_client(self, i, write_config=True):
        clientid = hashutil.tagged_hash(b"clientid", b"%d" % i)[:20]
        clientdir = os.path.join(self.basedir, "clients",
                                 idlib.shortnodeid_b2a(clientid))
        fileutil.make_dirs(clientdir)

        tahoe_cfg_path = os.path.join(clientdir, "tahoe.cfg")
        if write_config:
            from twisted.internet import reactor
            _, port_endpoint = self.port_assigner.assign(reactor)
            with open(tahoe_cfg_path, "w") as f:
                f.write("[node]\n")
                f.write("nickname = client-%d\n" % i)
                f.write("web.port = {}\n".format(port_endpoint))
                f.write("[storage]\n")
                f.write("enabled = false\n")
        else:
            _assert(os.path.exists(tahoe_cfg_path),
                    tahoe_cfg_path=tahoe_cfg_path)

        c = None
        if i in self.client_config_hooks:
            # this hook can either modify tahoe.cfg, or return an
            # entirely new Client instance
            c = self.client_config_hooks[i](clientdir)

        if not c:
            c = yield create_no_network_client(clientdir)
            c.set_default_mutable_keysize(TEST_RSA_KEY_SIZE)

        c.nodeid = clientid
        c.short_nodeid = b32encode(clientid).lower()[:8]
        c._servers = self.all_servers  # can be updated later
        c.setServiceParent(self)
        defer.returnValue(c)
Example #4
0
    def make_client(self, i, write_config=True):
        clientid = hashutil.tagged_hash("clientid", str(i))[:20]
        clientdir = os.path.join(self.basedir, "clients",
                                 idlib.shortnodeid_b2a(clientid))
        fileutil.make_dirs(clientdir)

        tahoe_cfg_path = os.path.join(clientdir, "tahoe.cfg")
        if write_config:
            from twisted.internet import reactor
            _, port_endpoint = self.port_assigner.assign(reactor)
            f = open(tahoe_cfg_path, "w")
            f.write("[node]\n")
            f.write("nickname = client-%d\n" % i)
            f.write("web.port = {}\n".format(port_endpoint))
            f.write("[storage]\n")
            f.write("enabled = false\n")
            f.close()
        else:
            _assert(os.path.exists(tahoe_cfg_path), tahoe_cfg_path=tahoe_cfg_path)

        c = None
        if i in self.client_config_hooks:
            # this hook can either modify tahoe.cfg, or return an
            # entirely new Client instance
            c = self.client_config_hooks[i](clientdir)

        if not c:
            c = yield create_no_network_client(clientdir)
            c.set_default_mutable_keysize(TEST_RSA_KEY_SIZE)

        c.nodeid = clientid
        c.short_nodeid = b32encode(clientid).lower()[:8]
        c._servers = self.all_servers # can be updated later
        c.setServiceParent(self)
        defer.returnValue(c)
Example #5
0
    def make_client(self, i, write_config=True):
        clientid = hashutil.tagged_hash("clientid", str(i))[:20]
        clientdir = os.path.join(self.basedir, "clients",
                                 idlib.shortnodeid_b2a(clientid))
        fileutil.make_dirs(clientdir)

        tahoe_cfg_path = os.path.join(clientdir, "tahoe.cfg")
        if write_config:
            f = open(tahoe_cfg_path, "w")
            f.write("[node]\n")
            f.write("nickname = client-%d\n" % i)
            f.write("web.port = tcp:0:interface=127.0.0.1\n")
            f.write("[storage]\n")
            f.write("enabled = false\n")
            f.close()
        else:
            _assert(os.path.exists(tahoe_cfg_path),
                    tahoe_cfg_path=tahoe_cfg_path)

        c = None
        if i in self.client_config_hooks:
            # this hook can either modify tahoe.cfg, or return an
            # entirely new Client instance
            c = self.client_config_hooks[i](clientdir)

        if not c:
            c = NoNetworkClient(clientdir)
            c.set_default_mutable_keysize(TEST_RSA_KEY_SIZE)

        c.nodeid = clientid
        c.short_nodeid = b32encode(clientid).lower()[:8]
        c._servers = self.all_servers  # can be updated later
        c.setServiceParent(self)
        return c
Example #6
0
 def test_sha256d_truncated(self):
     h1 = hashutil.tagged_hash(b"tag1", b"value", 16)
     h2 = hashutil.tagged_hasher(b"tag1", 16)
     h2.update(b"value")
     h2 = h2.digest()
     self.failUnlessEqual(len(h1), 16)
     self.failUnlessEqual(len(h2), 16)
     self.failUnlessEqual(h1, h2)
Example #7
0
 def make_server(self, i, readonly=False):
     serverid = hashutil.tagged_hash("serverid", str(i))[:20]
     serverdir = os.path.join(self.basedir, "servers",
                              idlib.shortnodeid_b2a(serverid), "storage")
     fileutil.make_dirs(serverdir)
     ss = StorageServer(serverdir, serverid, stats_provider=SimpleStats(),
                        readonly_storage=readonly)
     ss._no_network_server_number = i
     return ss
Example #8
0
 def make_server(self, i, readonly=False):
     serverid = hashutil.tagged_hash("serverid", str(i))[:20]
     serverdir = os.path.join(self.basedir, "servers",
                              idlib.shortnodeid_b2a(serverid), "storage")
     fileutil.make_dirs(serverdir)
     ss = StorageServer(serverdir, serverid, stats_provider=SimpleStats(),
                        readonly_storage=readonly)
     ss._no_network_server_number = i
     return ss
Example #9
0
 def test_sha256d(self):
     h1 = hashutil.tagged_hash(b"tag1", b"value")
     self.assertIsInstance(h1, bytes)
     h2 = hashutil.tagged_hasher(b"tag1")
     h2.update(b"value")
     h2a = h2.digest()
     h2b = h2.digest()
     self.assertIsInstance(h2a, bytes)
     self.failUnlessEqual(h1, h2a)
     self.failUnlessEqual(h2a, h2b)
Example #10
0
    def test_pack(self):
        data = {"stuff": "value",
                "size": 12,
                "needed_shares": 3,
                "big_hash": hashutil.tagged_hash("foo", "bar"),
                }
        ext = uri.pack_extension(data)
        d = uri.unpack_extension(ext)
        self.failUnlessReallyEqual(d["stuff"], "value")
        self.failUnlessReallyEqual(d["size"], 12)
        self.failUnlessReallyEqual(d["big_hash"], hashutil.tagged_hash("foo", "bar"))

        readable = uri.unpack_extension_readable(ext)
        self.failUnlessReallyEqual(readable["needed_shares"], 3)
        self.failUnlessReallyEqual(readable["stuff"], "value")
        self.failUnlessReallyEqual(readable["size"], 12)
        self.failUnlessReallyEqual(readable["big_hash"],
                             base32.b2a(hashutil.tagged_hash("foo", "bar")))
        self.failUnlessReallyEqual(readable["UEB_hash"],
                             base32.b2a(hashutil.uri_extension_hash(ext)))
Example #11
0
 def test_create(self):
     # try out various sizes, since we pad to a power of two
     ht = make_tree(6)
     ht = make_tree(9)
     ht = make_tree(8)
     root = ht[0]
     self.failUnlessEqual(len(root), 32)
     self.failUnlessEqual(ht.get_leaf(0), tagged_hash("tag", "0"))
     self.failUnlessRaises(IndexError, ht.get_leaf, 8)
     self.failUnlessEqual(ht.get_leaf_index(0), 7)
     self.failUnlessRaises(IndexError, ht.parent, 0)
     self.failUnlessRaises(IndexError, ht.needed_for, -1)
Example #12
0
 def test_create(self):
     # try out various sizes, since we pad to a power of two
     ht = make_tree(6)
     ht = make_tree(9)
     ht = make_tree(8)
     root = ht[0]
     self.failUnlessEqual(len(root), 32)
     self.failUnlessEqual(ht.get_leaf(0), tagged_hash("tag", "0"))
     self.failUnlessRaises(IndexError, ht.get_leaf, 8)
     self.failUnlessEqual(ht.get_leaf_index(0), 7)
     self.failUnlessRaises(IndexError, ht.parent, 0)
     self.failUnlessRaises(IndexError, ht.needed_for, -1)
Example #13
0
def make_storagebroker(s=None, num_peers=10):
    if not s:
        s = FakeStorage()
    peerids = [tagged_hash("peerid", "%d" % i)[:20]
               for i in range(num_peers)]
    storage_broker = StorageFarmBroker(True, None)
    for peerid in peerids:
        fss = FakeStorageServer(peerid, s)
        ann = {"anonymous-storage-FURL": "pb://%s@nowhere/fake" % base32.b2a(peerid),
               "permutation-seed-base32": base32.b2a(peerid) }
        storage_broker.test_add_rref(peerid, fss, ann)
    return storage_broker
Example #14
0
def make_storagebroker(s=None, num_peers=10):
    if not s:
        s = FakeStorage()
    peerids = [tagged_hash("peerid", "%d" % i)[:20] for i in range(num_peers)]
    storage_broker = StorageFarmBroker(True)
    for peerid in peerids:
        fss = FakeStorageServer(peerid, s)
        ann = {
            "anonymous-storage-FURL":
            "pb://%s@nowhere/fake" % base32.b2a(peerid),
            "permutation-seed-base32": base32.b2a(peerid)
        }
        storage_broker.test_add_rref(peerid, fss, ann)
    return storage_broker
Example #15
0
    def __init__(self,
                 basedir,
                 num_clients=1,
                 num_servers=10,
                 client_config_hooks={}):
        service.MultiService.__init__(self)
        self.basedir = basedir
        fileutil.make_dirs(basedir)

        self.servers_by_number = {}  # maps to StorageServer instance
        self.wrappers_by_id = {}  # maps to wrapped StorageServer instance
        self.proxies_by_id = {}  # maps to IServer on which .rref is a wrapped
        # StorageServer
        self.clients = []

        for i in range(num_servers):
            ss = self.make_server(i)
            self.add_server(i, ss)
        self.rebuild_serverlist()

        for i in range(num_clients):
            clientid = hashutil.tagged_hash("clientid", str(i))[:20]
            clientdir = os.path.join(basedir, "clients",
                                     idlib.shortnodeid_b2a(clientid))
            fileutil.make_dirs(clientdir)
            f = open(os.path.join(clientdir, "tahoe.cfg"), "w")
            f.write("[node]\n")
            f.write("nickname = client-%d\n" % i)
            f.write("web.port = tcp:0:interface=127.0.0.1\n")
            f.write("[storage]\n")
            f.write("enabled = false\n")
            f.close()
            c = None
            if i in client_config_hooks:
                # this hook can either modify tahoe.cfg, or return an
                # entirely new Client instance
                c = client_config_hooks[i](clientdir)
            if not c:
                c = NoNetworkClient(clientdir)
                c.set_default_mutable_keysize(TEST_RSA_KEY_SIZE)
            c.nodeid = clientid
            c.short_nodeid = b32encode(clientid).lower()[:8]
            c._servers = self.all_servers  # can be updated later
            c.setServiceParent(self)
            self.clients.append(c)
Example #16
0
def derive_renewal_secret(lease_secret: bytes, storage_index: bytes,
                          tubid: bytes) -> bytes:
    assert len(lease_secret) == 32
    assert len(storage_index) == 16
    assert len(tubid) == 20

    bucket_renewal_tag = b"allmydata_bucket_renewal_secret_v1"
    file_renewal_tag = b"allmydata_file_renewal_secret_v1"
    client_renewal_tag = b"allmydata_client_renewal_secret_v1"

    client_renewal_secret = tagged_hash(lease_secret, client_renewal_tag)
    file_renewal_secret = tagged_pair_hash(
        file_renewal_tag,
        client_renewal_secret,
        storage_index,
    )
    peer_id = tubid

    return tagged_pair_hash(bucket_renewal_tag, file_renewal_secret, peer_id)
Example #17
0
    def __init__(self, basedir, num_clients=1, num_servers=10,
                 client_config_hooks={}):
        service.MultiService.__init__(self)
        self.basedir = basedir
        fileutil.make_dirs(basedir)

        self.servers_by_number = {} # maps to StorageServer instance
        self.wrappers_by_id = {} # maps to wrapped StorageServer instance
        self.proxies_by_id = {} # maps to IServer on which .rref is a wrapped
                                # StorageServer
        self.clients = []

        for i in range(num_servers):
            ss = self.make_server(i)
            self.add_server(i, ss)
        self.rebuild_serverlist()

        for i in range(num_clients):
            clientid = hashutil.tagged_hash("clientid", str(i))[:20]
            clientdir = os.path.join(basedir, "clients",
                                     idlib.shortnodeid_b2a(clientid))
            fileutil.make_dirs(clientdir)
            f = open(os.path.join(clientdir, "tahoe.cfg"), "w")
            f.write("[node]\n")
            f.write("nickname = client-%d\n" % i)
            f.write("web.port = tcp:0:interface=127.0.0.1\n")
            f.write("[storage]\n")
            f.write("enabled = false\n")
            f.close()
            c = None
            if i in client_config_hooks:
                # this hook can either modify tahoe.cfg, or return an
                # entirely new Client instance
                c = client_config_hooks[i](clientdir)
            if not c:
                c = NoNetworkClient(clientdir)
                c.set_default_mutable_keysize(TEST_RSA_KEY_SIZE)
            c.nodeid = clientid
            c.short_nodeid = b32encode(clientid).lower()[:8]
            c._servers = self.all_servers # can be updated later
            c.setServiceParent(self)
            self.clients.append(c)
Example #18
0
def make_peer(s, i):
    """
    Create a "peer" suitable for use with ``make_storagebroker_with_peers`` or
    ``make_nodemaker_with_peers``.

    :param IServer s: The server with which to associate the peers.

    :param int i: A unique identifier for this peer within the whole group of
        peers to be used.  For example, a sequence number.  This is used to
        generate a unique peer id.

    :rtype: ``Peer``
    """
    peerid = base32.b2a(tagged_hash("peerid", "%d" % i)[:20])
    fss = FakeStorageServer(peerid, s)
    ann = {
        "anonymous-storage-FURL": "pb://%s@nowhere/fake" % (peerid, ),
        "permutation-seed-base32": peerid,
    }
    return Peer(peerid=peerid, storage_server=fss, announcement=ann)
Example #19
0
def empty_leaf_hash(i):
    return tagged_hash('Merkle tree empty leaf', "%d" % i)
Example #20
0
    def test_check(self):
        # first create a complete hash tree
        ht = make_tree(6)
        # then create a corresponding incomplete tree
        iht = hashtree.IncompleteHashTree(6)

        # suppose we wanted to validate leaf[0]
        #  leaf[0] is the same as node[7]
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(0, True), set([7, 8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(1), set([7, 4, 2]))
        iht[0] = ht[0] # set the root
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(1), set([7, 4, 2]))
        iht[5] = ht[5]
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(1), set([7, 4, 2]))

        # reset
        iht = hashtree.IncompleteHashTree(6)

        current_hashes = list(iht)
        # this should fail because there aren't enough hashes known
        try:
            iht.set_hashes(leaves={0: tagged_hash("tag", "0")})
        except hashtree.NotEnoughHashesError:
            pass
        else:
            self.fail("didn't catch not enough hashes")

        # and the set of hashes stored in the tree should still be the same
        self.failUnlessEqual(list(iht), current_hashes)
        # and we should still need the same
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))

        chain = {0: ht[0], 2: ht[2], 4: ht[4], 8: ht[8]}
        # this should fail because the leaf hash is just plain wrong
        try:
            iht.set_hashes(chain, leaves={0: tagged_hash("bad tag", "0")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        # this should fail because we give it conflicting hashes: one as an
        # internal node, another as a leaf
        try:
            iht.set_hashes(chain, leaves={1: tagged_hash("bad tag", "1")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        bad_chain = chain.copy()
        bad_chain[2] = ht[2] + "BOGUS"

        # this should fail because the internal hash is wrong
        try:
            iht.set_hashes(bad_chain, leaves={0: tagged_hash("tag", "0")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        # this should succeed
        try:
            iht.set_hashes(chain, leaves={0: tagged_hash("tag", "0")})
        except hashtree.BadHashError, e:
            self.fail("bad hash: %s" % e)
Example #21
0
def write_root_cap(root_cap):
    write_config_file('private/root_dir.cap', root_cap+'\n')
    convergence = base32.b2a(hashutil.tagged_hash(CONVERGENCE_DOMAIN_TAG, root_cap))
    write_config_file('private/convergence', convergence+'\n')
Example #22
0
def make_tree(numleaves):
    leaves = ["%d" % i for i in range(numleaves)]
    leaf_hashes = [tagged_hash("tag", leaf) for leaf in leaves]
    ht = hashtree.HashTree(leaf_hashes)
    return ht
Example #23
0
    def test_check(self):
        # first create a complete hash tree
        ht = make_tree(6)
        # then create a corresponding incomplete tree
        iht = hashtree.IncompleteHashTree(6)

        # suppose we wanted to validate leaf[0]
        #  leaf[0] is the same as node[7]
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(0, True), set([7, 8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(1), set([7, 4, 2]))
        iht[0] = ht[0]  # set the root
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(1), set([7, 4, 2]))
        iht[5] = ht[5]
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(1), set([7, 4, 2]))

        # reset
        iht = hashtree.IncompleteHashTree(6)

        current_hashes = list(iht)
        # this should fail because there aren't enough hashes known
        try:
            iht.set_hashes(leaves={0: tagged_hash("tag", "0")})
        except hashtree.NotEnoughHashesError:
            pass
        else:
            self.fail("didn't catch not enough hashes")

        # and the set of hashes stored in the tree should still be the same
        self.failUnlessEqual(list(iht), current_hashes)
        # and we should still need the same
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))

        chain = {0: ht[0], 2: ht[2], 4: ht[4], 8: ht[8]}
        # this should fail because the leaf hash is just plain wrong
        try:
            iht.set_hashes(chain, leaves={0: tagged_hash("bad tag", "0")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        # this should fail because we give it conflicting hashes: one as an
        # internal node, another as a leaf
        try:
            iht.set_hashes(chain, leaves={1: tagged_hash("bad tag", "1")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        bad_chain = chain.copy()
        bad_chain[2] = ht[2] + "BOGUS"

        # this should fail because the internal hash is wrong
        try:
            iht.set_hashes(bad_chain, leaves={0: tagged_hash("tag", "0")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        # this should succeed
        try:
            iht.set_hashes(chain, leaves={0: tagged_hash("tag", "0")})
        except hashtree.BadHashError, e:
            self.fail("bad hash: %s" % e)
Example #24
0
class Incomplete(unittest.TestCase):
    def test_create(self):
        ht = hashtree.IncompleteHashTree(6)
        ht = hashtree.IncompleteHashTree(9)
        ht = hashtree.IncompleteHashTree(8)
        self.failUnlessEqual(ht[0], None)
        self.failUnlessEqual(ht.get_leaf(0), None)
        self.failUnlessRaises(IndexError, ht.get_leaf, 8)
        self.failUnlessEqual(ht.get_leaf_index(0), 7)

    def test_needed_hashes(self):
        ht = hashtree.IncompleteHashTree(8)
        self.failUnlessEqual(ht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(ht.needed_hashes(0, True), set([7, 8, 4, 2]))
        self.failUnlessEqual(ht.needed_hashes(1), set([7, 4, 2]))
        self.failUnlessEqual(ht.needed_hashes(7), set([13, 5, 1]))
        self.failUnlessEqual(ht.needed_hashes(7, False), set([13, 5, 1]))
        self.failUnlessEqual(ht.needed_hashes(7, True), set([14, 13, 5, 1]))
        ht = hashtree.IncompleteHashTree(1)
        self.failUnlessEqual(ht.needed_hashes(0), set([]))
        ht = hashtree.IncompleteHashTree(6)
        self.failUnlessEqual(ht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(ht.needed_hashes(0, True), set([7, 8, 4, 2]))
        self.failUnlessEqual(ht.needed_hashes(1), set([7, 4, 2]))
        self.failUnlessEqual(ht.needed_hashes(5), set([11, 6, 1]))
        self.failUnlessEqual(ht.needed_hashes(5, False), set([11, 6, 1]))
        self.failUnlessEqual(ht.needed_hashes(5, True), set([12, 11, 6, 1]))

    def test_depth_of(self):
        hashtree.IncompleteHashTree(8)
        self.failUnlessEqual(hashtree.depth_of(0), 0)
        for i in [1, 2]:
            self.failUnlessEqual(hashtree.depth_of(i), 1, "i=%d" % i)
        for i in [3, 4, 5, 6]:
            self.failUnlessEqual(hashtree.depth_of(i), 2, "i=%d" % i)
        for i in [7, 8, 9, 10, 11, 12, 13, 14]:
            self.failUnlessEqual(hashtree.depth_of(i), 3, "i=%d" % i)

    def test_large(self):
        # IncompleteHashTree.set_hashes() used to take O(N**2). This test is
        # meant to show that it now takes O(N) or maybe O(N*ln(N)). I wish
        # there were a good way to assert this (like counting VM operations
        # or something): the problem was inside list.sort(), so there's no
        # good way to instrument set_hashes() to count what we care about. On
        # my laptop, 10k leaves takes 1.1s in this fixed version, and 11.6s
        # in the old broken version. An 80k-leaf test (corresponding to a
        # 10GB file with a 128KiB segsize) 10s in the fixed version, and
        # several hours in the broken version, but 10s on my laptop (plus the
        # 20s of setup code) probably means 200s on our dapper buildslave,
        # which is painfully long for a unit test.
        self.do_test_speed(10000)

    def do_test_speed(self, SIZE):
        # on my laptop, SIZE=80k (corresponding to a 10GB file with a 128KiB
        # segsize) takes:
        #  7s to build the (complete) HashTree
        #  13s to set up the dictionary
        #  10s to run set_hashes()
        ht = make_tree(SIZE)
        iht = hashtree.IncompleteHashTree(SIZE)

        needed = set()
        for i in range(SIZE):
            needed.update(ht.needed_hashes(i, True))
        all = dict([(i, ht[i]) for i in needed])
        iht.set_hashes(hashes=all)

    def test_check(self):
        # first create a complete hash tree
        ht = make_tree(6)
        # then create a corresponding incomplete tree
        iht = hashtree.IncompleteHashTree(6)

        # suppose we wanted to validate leaf[0]
        #  leaf[0] is the same as node[7]
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(0, True), set([7, 8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(1), set([7, 4, 2]))
        iht[0] = ht[0]  # set the root
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(1), set([7, 4, 2]))
        iht[5] = ht[5]
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))
        self.failUnlessEqual(iht.needed_hashes(1), set([7, 4, 2]))

        # reset
        iht = hashtree.IncompleteHashTree(6)

        current_hashes = list(iht)
        # this should fail because there aren't enough hashes known
        try:
            iht.set_hashes(leaves={0: tagged_hash("tag", "0")})
        except hashtree.NotEnoughHashesError:
            pass
        else:
            self.fail("didn't catch not enough hashes")

        # and the set of hashes stored in the tree should still be the same
        self.failUnlessEqual(list(iht), current_hashes)
        # and we should still need the same
        self.failUnlessEqual(iht.needed_hashes(0), set([8, 4, 2]))

        chain = {0: ht[0], 2: ht[2], 4: ht[4], 8: ht[8]}
        # this should fail because the leaf hash is just plain wrong
        try:
            iht.set_hashes(chain, leaves={0: tagged_hash("bad tag", "0")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        # this should fail because we give it conflicting hashes: one as an
        # internal node, another as a leaf
        try:
            iht.set_hashes(chain, leaves={1: tagged_hash("bad tag", "1")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        bad_chain = chain.copy()
        bad_chain[2] = ht[2] + "BOGUS"

        # this should fail because the internal hash is wrong
        try:
            iht.set_hashes(bad_chain, leaves={0: tagged_hash("tag", "0")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        # this should succeed
        try:
            iht.set_hashes(chain, leaves={0: tagged_hash("tag", "0")})
        except hashtree.BadHashError, e:
            self.fail("bad hash: %s" % e)

        self.failUnlessEqual(ht.get_leaf(0), tagged_hash("tag", "0"))
        self.failUnlessRaises(IndexError, ht.get_leaf, 8)

        # this should succeed too
        try:
            iht.set_hashes(leaves={1: tagged_hash("tag", "1")})
        except hashtree.BadHashError:
            self.fail("bad hash")

        # this should fail because we give it hashes that conflict with some
        # that we added successfully before
        try:
            iht.set_hashes(leaves={1: tagged_hash("bad tag", "1")})
        except hashtree.BadHashError:
            pass
        else:
            self.fail("didn't catch bad hash")

        # now that leaves 0 and 1 are known, some of the internal nodes are
        # known
        self.failUnlessEqual(iht.needed_hashes(4), set([12, 6]))
        chain = {6: ht[6], 12: ht[12]}

        # this should succeed
        try:
            iht.set_hashes(chain, leaves={4: tagged_hash("tag", "4")})
        except hashtree.BadHashError, e:
            self.fail("bad hash: %s" % e)
Example #25
0
def empty_leaf_hash(i):
    return tagged_hash(b'Merkle tree empty leaf', b"%d" % i)
Example #26
0
def make_tree(numleaves):
    leaves = ["%d" % i for i in range(numleaves)]
    leaf_hashes = [tagged_hash("tag", leaf) for leaf in leaves]
    ht = hashtree.HashTree(leaf_hashes)
    return ht