3 from common import NeedMoreDataError
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 if len(data) < o['share_hash_chain']:
39 raise NeedMoreDataError(o['share_hash_chain'],
40 o['enc_privkey'], o['EOF']-o['enc_privkey'])
42 pubkey_s = data[HEADER_LENGTH:o['signature']]
43 signature = data[o['signature']:o['share_hash_chain']]
45 return (seqnum, root_hash, IV, k, N, segsize, datalen,
46 pubkey_s, signature, prefix)
48 def unpack_share(data):
49 assert len(data) >= HEADER_LENGTH
55 k, N, segsize, datalen,
57 o['share_hash_chain'],
61 o['EOF']) = struct.unpack(HEADER, data[:HEADER_LENGTH])
64 if len(data) < o['EOF']:
65 raise NeedMoreDataError(o['EOF'],
66 o['enc_privkey'], o['EOF']-o['enc_privkey'])
68 pubkey = data[HEADER_LENGTH:o['signature']]
69 signature = data[o['signature']:o['share_hash_chain']]
70 share_hash_chain_s = data[o['share_hash_chain']:o['block_hash_tree']]
71 share_hash_format = ">H32s"
72 hsize = struct.calcsize(share_hash_format)
73 assert len(share_hash_chain_s) % hsize == 0, len(share_hash_chain_s)
75 for i in range(0, len(share_hash_chain_s), hsize):
76 chunk = share_hash_chain_s[i:i+hsize]
77 (hid, h) = struct.unpack(share_hash_format, chunk)
78 share_hash_chain.append( (hid, h) )
79 share_hash_chain = dict(share_hash_chain)
80 block_hash_tree_s = data[o['block_hash_tree']:o['share_data']]
81 assert len(block_hash_tree_s) % 32 == 0, len(block_hash_tree_s)
83 for i in range(0, len(block_hash_tree_s), 32):
84 block_hash_tree.append(block_hash_tree_s[i:i+32])
86 share_data = data[o['share_data']:o['enc_privkey']]
87 enc_privkey = data[o['enc_privkey']:o['EOF']]
89 return (seqnum, root_hash, IV, k, N, segsize, datalen,
90 pubkey, signature, share_hash_chain, block_hash_tree,
91 share_data, enc_privkey)
93 def unpack_share_data(verinfo, hash_and_data):
94 (seqnum, root_hash, IV, segsize, datalength, k, N, prefix, o_t) = verinfo
96 # hash_and_data starts with the share_hash_chain, so figure out what the
99 o_share_hash_chain = 0
100 o_block_hash_tree = o['block_hash_tree'] - o['share_hash_chain']
101 o_share_data = o['share_data'] - o['share_hash_chain']
102 o_enc_privkey = o['enc_privkey'] - o['share_hash_chain']
104 share_hash_chain_s = hash_and_data[o_share_hash_chain:o_block_hash_tree]
105 share_hash_format = ">H32s"
106 hsize = struct.calcsize(share_hash_format)
107 assert len(share_hash_chain_s) % hsize == 0, len(share_hash_chain_s)
108 share_hash_chain = []
109 for i in range(0, len(share_hash_chain_s), hsize):
110 chunk = share_hash_chain_s[i:i+hsize]
111 (hid, h) = struct.unpack(share_hash_format, chunk)
112 share_hash_chain.append( (hid, h) )
113 share_hash_chain = dict(share_hash_chain)
114 block_hash_tree_s = hash_and_data[o_block_hash_tree:o_share_data]
115 assert len(block_hash_tree_s) % 32 == 0, len(block_hash_tree_s)
117 for i in range(0, len(block_hash_tree_s), 32):
118 block_hash_tree.append(block_hash_tree_s[i:i+32])
120 share_data = hash_and_data[o_share_data:o_enc_privkey]
122 return (share_hash_chain, block_hash_tree, share_data)
125 def pack_checkstring(seqnum, root_hash, IV):
126 return struct.pack(PREFIX,
132 def unpack_checkstring(checkstring):
133 cs_len = struct.calcsize(PREFIX)
134 version, seqnum, root_hash, IV = struct.unpack(PREFIX, checkstring[:cs_len])
135 assert version == 0 # TODO: just ignore the share
136 return (seqnum, root_hash, IV)
138 def pack_prefix(seqnum, root_hash, IV,
139 required_shares, total_shares,
140 segment_size, data_length):
141 prefix = struct.pack(SIGNED_PREFIX,
154 def pack_offsets(verification_key_length, signature_length,
155 share_hash_chain_length, block_hash_tree_length,
156 share_data_length, encprivkey_length):
157 post_offset = HEADER_LENGTH
159 o1 = offsets['signature'] = post_offset + verification_key_length
160 o2 = offsets['share_hash_chain'] = o1 + signature_length
161 o3 = offsets['block_hash_tree'] = o2 + share_hash_chain_length
162 o4 = offsets['share_data'] = o3 + block_hash_tree_length
163 o5 = offsets['enc_privkey'] = o4 + share_data_length
164 o6 = offsets['EOF'] = o5 + encprivkey_length
166 return struct.pack(">LLLLQQ",
167 offsets['signature'],
168 offsets['share_hash_chain'],
169 offsets['block_hash_tree'],
170 offsets['share_data'],
171 offsets['enc_privkey'],
174 def pack_share(prefix, verification_key, signature,
175 share_hash_chain, block_hash_tree,
176 share_data, encprivkey):
177 share_hash_chain_s = "".join([struct.pack(">H32s", i, share_hash_chain[i])
178 for i in sorted(share_hash_chain.keys())])
179 for h in block_hash_tree:
181 block_hash_tree_s = "".join(block_hash_tree)
183 offsets = pack_offsets(len(verification_key),
185 len(share_hash_chain_s),
186 len(block_hash_tree_s),
189 final_share = "".join([prefix,