3 from common import NeedMoreDataError, UnknownVersionError
5 PREFIX = ">BQ32s16s" # each version has a different prefix
6 SIGNED_PREFIX = ">BQ32s16s BBQQ" # this is covered by the signature
7 SIGNED_PREFIX_LENGTH = struct.calcsize(SIGNED_PREFIX)
8 HEADER = ">BQ32s16s BBQQ LLLLQQ" # includes offsets
9 HEADER_LENGTH = struct.calcsize(HEADER)
11 def unpack_header(data):
17 k, N, segsize, datalen,
19 o['share_hash_chain'],
23 o['EOF']) = struct.unpack(HEADER, data[:HEADER_LENGTH])
24 return (version, seqnum, root_hash, IV, k, N, segsize, datalen, o)
26 def unpack_prefix_and_signature(data):
27 assert len(data) >= HEADER_LENGTH, len(data)
28 prefix = data[:SIGNED_PREFIX_LENGTH]
34 k, N, segsize, datalen,
35 o) = unpack_header(data)
38 raise UnknownVersionError("got mutable share version %d, but I only understand version 0" % version)
40 if len(data) < o['share_hash_chain']:
41 raise NeedMoreDataError(o['share_hash_chain'],
42 o['enc_privkey'], o['EOF']-o['enc_privkey'])
44 pubkey_s = data[HEADER_LENGTH:o['signature']]
45 signature = data[o['signature']:o['share_hash_chain']]
47 return (seqnum, root_hash, IV, k, N, segsize, datalen,
48 pubkey_s, signature, prefix)
50 def unpack_share(data):
51 assert len(data) >= HEADER_LENGTH
57 k, N, segsize, datalen,
59 o['share_hash_chain'],
63 o['EOF']) = struct.unpack(HEADER, data[:HEADER_LENGTH])
66 raise UnknownVersionError("got mutable share version %d, but I only understand version 0" % version)
68 if len(data) < o['EOF']:
69 raise NeedMoreDataError(o['EOF'],
70 o['enc_privkey'], o['EOF']-o['enc_privkey'])
72 pubkey = data[HEADER_LENGTH:o['signature']]
73 signature = data[o['signature']:o['share_hash_chain']]
74 share_hash_chain_s = data[o['share_hash_chain']:o['block_hash_tree']]
75 share_hash_format = ">H32s"
76 hsize = struct.calcsize(share_hash_format)
77 assert len(share_hash_chain_s) % hsize == 0, len(share_hash_chain_s)
79 for i in range(0, len(share_hash_chain_s), hsize):
80 chunk = share_hash_chain_s[i:i+hsize]
81 (hid, h) = struct.unpack(share_hash_format, chunk)
82 share_hash_chain.append( (hid, h) )
83 share_hash_chain = dict(share_hash_chain)
84 block_hash_tree_s = data[o['block_hash_tree']:o['share_data']]
85 assert len(block_hash_tree_s) % 32 == 0, len(block_hash_tree_s)
87 for i in range(0, len(block_hash_tree_s), 32):
88 block_hash_tree.append(block_hash_tree_s[i:i+32])
90 share_data = data[o['share_data']:o['enc_privkey']]
91 enc_privkey = data[o['enc_privkey']:o['EOF']]
93 return (seqnum, root_hash, IV, k, N, segsize, datalen,
94 pubkey, signature, share_hash_chain, block_hash_tree,
95 share_data, enc_privkey)
97 def unpack_share_data(verinfo, hash_and_data):
98 (seqnum, root_hash, IV, segsize, datalength, k, N, prefix, o_t) = verinfo
100 # hash_and_data starts with the share_hash_chain, so figure out what the
103 o_share_hash_chain = 0
104 o_block_hash_tree = o['block_hash_tree'] - o['share_hash_chain']
105 o_share_data = o['share_data'] - o['share_hash_chain']
106 o_enc_privkey = o['enc_privkey'] - o['share_hash_chain']
108 share_hash_chain_s = hash_and_data[o_share_hash_chain:o_block_hash_tree]
109 share_hash_format = ">H32s"
110 hsize = struct.calcsize(share_hash_format)
111 assert len(share_hash_chain_s) % hsize == 0, len(share_hash_chain_s)
112 share_hash_chain = []
113 for i in range(0, len(share_hash_chain_s), hsize):
114 chunk = share_hash_chain_s[i:i+hsize]
115 (hid, h) = struct.unpack(share_hash_format, chunk)
116 share_hash_chain.append( (hid, h) )
117 share_hash_chain = dict(share_hash_chain)
118 block_hash_tree_s = hash_and_data[o_block_hash_tree:o_share_data]
119 assert len(block_hash_tree_s) % 32 == 0, len(block_hash_tree_s)
121 for i in range(0, len(block_hash_tree_s), 32):
122 block_hash_tree.append(block_hash_tree_s[i:i+32])
124 share_data = hash_and_data[o_share_data:o_enc_privkey]
126 return (share_hash_chain, block_hash_tree, share_data)
129 def pack_checkstring(seqnum, root_hash, IV):
130 return struct.pack(PREFIX,
136 def unpack_checkstring(checkstring):
137 cs_len = struct.calcsize(PREFIX)
138 version, seqnum, root_hash, IV = struct.unpack(PREFIX, checkstring[:cs_len])
139 if version != 0: # TODO: just ignore the share
140 raise UnknownVersionError("got mutable share version %d, but I only understand version 0" % version)
141 return (seqnum, root_hash, IV)
143 def pack_prefix(seqnum, root_hash, IV,
144 required_shares, total_shares,
145 segment_size, data_length):
146 prefix = struct.pack(SIGNED_PREFIX,
159 def pack_offsets(verification_key_length, signature_length,
160 share_hash_chain_length, block_hash_tree_length,
161 share_data_length, encprivkey_length):
162 post_offset = HEADER_LENGTH
164 o1 = offsets['signature'] = post_offset + verification_key_length
165 o2 = offsets['share_hash_chain'] = o1 + signature_length
166 o3 = offsets['block_hash_tree'] = o2 + share_hash_chain_length
167 o4 = offsets['share_data'] = o3 + block_hash_tree_length
168 o5 = offsets['enc_privkey'] = o4 + share_data_length
169 offsets['EOF'] = o5 + encprivkey_length
171 return struct.pack(">LLLLQQ",
172 offsets['signature'],
173 offsets['share_hash_chain'],
174 offsets['block_hash_tree'],
175 offsets['share_data'],
176 offsets['enc_privkey'],
179 def pack_share(prefix, verification_key, signature,
180 share_hash_chain, block_hash_tree,
181 share_data, encprivkey):
182 share_hash_chain_s = "".join([struct.pack(">H32s", i, share_hash_chain[i])
183 for i in sorted(share_hash_chain.keys())])
184 for h in block_hash_tree:
186 block_hash_tree_s = "".join(block_hash_tree)
188 offsets = pack_offsets(len(verification_key),
190 len(share_hash_chain_s),
191 len(block_hash_tree_s),
194 final_share = "".join([prefix,