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 HEADER = ">BQ32s16s BBQQ LLLLQQ" # includes offsets
8 HEADER_LENGTH = struct.calcsize(HEADER)
10 def unpack_header(data):
16 k, N, segsize, datalen,
18 o['share_hash_chain'],
22 o['EOF']) = struct.unpack(HEADER, data[:HEADER_LENGTH])
23 return (version, seqnum, root_hash, IV, k, N, segsize, datalen, o)
25 def unpack_prefix_and_signature(data):
26 assert len(data) >= HEADER_LENGTH, len(data)
27 prefix = data[:struct.calcsize(SIGNED_PREFIX)]
33 k, N, segsize, datalen,
34 o) = unpack_header(data)
37 if len(data) < o['share_hash_chain']:
38 raise NeedMoreDataError(o['share_hash_chain'],
39 o['enc_privkey'], o['EOF']-o['enc_privkey'])
41 pubkey_s = data[HEADER_LENGTH:o['signature']]
42 signature = data[o['signature']:o['share_hash_chain']]
44 return (seqnum, root_hash, IV, k, N, segsize, datalen,
45 pubkey_s, signature, prefix)
47 def unpack_share(data):
48 assert len(data) >= HEADER_LENGTH
54 k, N, segsize, datalen,
56 o['share_hash_chain'],
60 o['EOF']) = struct.unpack(HEADER, data[:HEADER_LENGTH])
63 if len(data) < o['EOF']:
64 raise NeedMoreDataError(o['EOF'],
65 o['enc_privkey'], o['EOF']-o['enc_privkey'])
67 pubkey = data[HEADER_LENGTH:o['signature']]
68 signature = data[o['signature']:o['share_hash_chain']]
69 share_hash_chain_s = data[o['share_hash_chain']:o['block_hash_tree']]
70 share_hash_format = ">H32s"
71 hsize = struct.calcsize(share_hash_format)
72 assert len(share_hash_chain_s) % hsize == 0, len(share_hash_chain_s)
74 for i in range(0, len(share_hash_chain_s), hsize):
75 chunk = share_hash_chain_s[i:i+hsize]
76 (hid, h) = struct.unpack(share_hash_format, chunk)
77 share_hash_chain.append( (hid, h) )
78 share_hash_chain = dict(share_hash_chain)
79 block_hash_tree_s = data[o['block_hash_tree']:o['share_data']]
80 assert len(block_hash_tree_s) % 32 == 0, len(block_hash_tree_s)
82 for i in range(0, len(block_hash_tree_s), 32):
83 block_hash_tree.append(block_hash_tree_s[i:i+32])
85 share_data = data[o['share_data']:o['enc_privkey']]
86 enc_privkey = data[o['enc_privkey']:o['EOF']]
88 return (seqnum, root_hash, IV, k, N, segsize, datalen,
89 pubkey, signature, share_hash_chain, block_hash_tree,
90 share_data, enc_privkey)
92 def unpack_share_data(verinfo, hash_and_data):
93 (seqnum, root_hash, IV, segsize, datalength, k, N, prefix, o_t) = verinfo
95 # hash_and_data starts with the share_hash_chain, so figure out what the
98 o_share_hash_chain = 0
99 o_block_hash_tree = o['block_hash_tree'] - o['share_hash_chain']
100 o_share_data = o['share_data'] - o['share_hash_chain']
101 o_enc_privkey = o['enc_privkey'] - o['share_hash_chain']
103 share_hash_chain_s = hash_and_data[o_share_hash_chain:o_block_hash_tree]
104 share_hash_format = ">H32s"
105 hsize = struct.calcsize(share_hash_format)
106 assert len(share_hash_chain_s) % hsize == 0, len(share_hash_chain_s)
107 share_hash_chain = []
108 for i in range(0, len(share_hash_chain_s), hsize):
109 chunk = share_hash_chain_s[i:i+hsize]
110 (hid, h) = struct.unpack(share_hash_format, chunk)
111 share_hash_chain.append( (hid, h) )
112 share_hash_chain = dict(share_hash_chain)
113 block_hash_tree_s = hash_and_data[o_block_hash_tree:o_share_data]
114 assert len(block_hash_tree_s) % 32 == 0, len(block_hash_tree_s)
116 for i in range(0, len(block_hash_tree_s), 32):
117 block_hash_tree.append(block_hash_tree_s[i:i+32])
119 share_data = hash_and_data[o_share_data:o_enc_privkey]
121 return (share_hash_chain, block_hash_tree, share_data)
124 def pack_checkstring(seqnum, root_hash, IV):
125 return struct.pack(PREFIX,
131 def unpack_checkstring(checkstring):
132 cs_len = struct.calcsize(PREFIX)
133 version, seqnum, root_hash, IV = struct.unpack(PREFIX, checkstring[:cs_len])
134 assert version == 0 # TODO: just ignore the share
135 return (seqnum, root_hash, IV)
137 def pack_prefix(seqnum, root_hash, IV,
138 required_shares, total_shares,
139 segment_size, data_length):
140 prefix = struct.pack(SIGNED_PREFIX,
153 def pack_offsets(verification_key_length, signature_length,
154 share_hash_chain_length, block_hash_tree_length,
155 share_data_length, encprivkey_length):
156 post_offset = HEADER_LENGTH
158 o1 = offsets['signature'] = post_offset + verification_key_length
159 o2 = offsets['share_hash_chain'] = o1 + signature_length
160 o3 = offsets['block_hash_tree'] = o2 + share_hash_chain_length
161 o4 = offsets['share_data'] = o3 + block_hash_tree_length
162 o5 = offsets['enc_privkey'] = o4 + share_data_length
163 o6 = offsets['EOF'] = o5 + encprivkey_length
165 return struct.pack(">LLLLQQ",
166 offsets['signature'],
167 offsets['share_hash_chain'],
168 offsets['block_hash_tree'],
169 offsets['share_data'],
170 offsets['enc_privkey'],
173 def pack_share(prefix, verification_key, signature,
174 share_hash_chain, block_hash_tree,
175 share_data, encprivkey):
176 share_hash_chain_s = "".join([struct.pack(">H32s", i, share_hash_chain[i])
177 for i in sorted(share_hash_chain.keys())])
178 for h in block_hash_tree:
180 block_hash_tree_s = "".join(block_hash_tree)
182 offsets = pack_offsets(len(verification_key),
184 len(share_hash_chain_s),
185 len(block_hash_tree_s),
188 final_share = "".join([prefix,