1 /*
2 * livehashtree.cpp
3 *
4 * Created by Arno Bakker, Victor Grishchenko
5 * Copyright 2009-2016 TECHNISCHE UNIVERSITEIT DELFT. All rights reserved.
6 *
7 */
8
9 #include "swift.h"
10 #include "bin_utils.h"
11
12 using namespace swift;
13
14
15 #define tree_debug false
16
17
18 const SigTintTuple SigTintTuple::NOSIGTINT = SigTintTuple();
19 const BinHashSigTuple BinHashSigTuple::NOBULL = BinHashSigTuple(bin_t::NONE,Sha1Hash::ZERO,SigTintTuple::NOSIGTINT);
20
21
22 /*
23 * Node
24 */
25
Node()26 Node::Node() : parent_(NULL), leftc_(NULL), rightc_(NULL), b_(bin_t::NONE), h_(Sha1Hash::ZERO), stptr_(NULL),
27 verified_(false)
28 {
29 }
30
~Node()31 Node::~Node()
32 {
33 if (stptr_ != NULL)
34 delete stptr_;
35 }
36
SetParent(Node * parent)37 void Node::SetParent(Node *parent)
38 {
39 parent_ = parent; // TODOinline
40 }
41
GetParent()42 Node *Node::GetParent()
43 {
44 return parent_; // TODOinline
45 }
46
47
SetChildren(Node * leftc,Node * rightc)48 void Node::SetChildren(Node *leftc, Node *rightc)
49 {
50 leftc_ = leftc;
51 rightc_ = rightc;
52 }
53
GetLeft()54 Node *Node::GetLeft()
55 {
56 return leftc_;
57 }
58
GetRight()59 Node *Node::GetRight()
60 {
61 return rightc_;
62 }
63
64
GetHash()65 Sha1Hash &Node::GetHash()
66 {
67 return h_;
68 }
69
SetHash(const Sha1Hash & hash)70 void Node::SetHash(const Sha1Hash &hash)
71 {
72 h_ = hash;
73 }
74
GetBin()75 bin_t &Node::GetBin()
76 {
77 return b_;
78 }
79
SetBin(bin_t b)80 void Node::SetBin(bin_t b)
81 {
82 b_ = b;
83 }
84
GetVerified()85 bool Node::GetVerified()
86 {
87 return verified_;
88 }
89
SetVerified(bool val)90 void Node::SetVerified(bool val)
91 {
92 verified_ = val;
93 }
94
GetSigTint()95 SigTintTuple *Node::GetSigTint()
96 {
97 return stptr_;
98 }
99
SetSigTint(SigTintTuple * stptr)100 void Node::SetSigTint(SigTintTuple *stptr)
101 {
102 stptr_ = stptr;
103 }
104
105
106
107 /*
108 * LiveHashTree
109 */
110
LiveHashTree(Storage * storage,KeyPair & keypair,uint32_t chunk_size,uint32_t nchunks_per_sig)111 LiveHashTree::LiveHashTree(Storage *storage, KeyPair &keypair, uint32_t chunk_size,uint32_t nchunks_per_sig) :
112 HashTree(), state_(LHT_STATE_SIGN_EMPTY), root_(NULL), addcursor_(NULL), keypair_(keypair), peak_count_(0), size_(0),
113 sizec_(0), complete_(0), completec_(0),
114 chunk_size_(chunk_size), storage_(storage),
115 source_last_munro_(bin_t::NONE),nchunks_per_sig_(nchunks_per_sig)
116 {
117 }
118
LiveHashTree(Storage * storage,KeyPair & pubkeypair,uint32_t chunk_size)119 LiveHashTree::LiveHashTree(Storage *storage, KeyPair &pubkeypair, uint32_t chunk_size) :
120 HashTree(), state_(LHT_STATE_VER_AWAIT_PEAK), root_(NULL), addcursor_(NULL), keypair_(pubkeypair), peak_count_(0),
121 size_(0), sizec_(0), complete_(0), completec_(0),
122 chunk_size_(chunk_size), storage_(storage),
123 source_last_munro_(bin_t::NONE), nchunks_per_sig_(0)
124 {
125 }
126
~LiveHashTree()127 LiveHashTree::~LiveHashTree()
128 {
129 if (root_ == NULL)
130 return;
131 else {
132 FreeTree(root_);
133 }
134 }
135
FreeTree(Node * n)136 void LiveHashTree::FreeTree(Node *n)
137 {
138 if (tree_debug)
139 fprintf(stderr,"umt: FreeTree: %s\n", n->GetBin().str().c_str());
140 if (n->GetLeft() != NULL) {
141 FreeTree(n->GetLeft());
142 }
143 if (n->GetRight() != NULL) {
144 FreeTree(n->GetRight());
145 }
146 delete n;
147 }
148
149
PruneTree(bin_t pos)150 void LiveHashTree::PruneTree(bin_t pos)
151 {
152 Node *n = FindNode(pos);
153 if (n != NULL) {
154 // Disconnect from parent
155 Node *par = n->GetParent();
156 if (par != NULL) {
157 if (par->GetLeft() == n)
158 par->SetChildren(NULL,par->GetRight());
159 else
160 par->SetChildren(par->GetLeft(),NULL);
161 }
162 // Deallocate subtree
163 FreeTree(n);
164 }
165 }
166
167
168 /*
169 * Live source specific
170 */
171
AddData(const char * data,size_t length)172 bin_t LiveHashTree::AddData(const char* data, size_t length)
173 {
174 // Source adds new data
175
176 if (tree_debug) {
177 if (addcursor_ == NULL)
178 fprintf(stderr,"umt: AddData: addcursor_ NULL\n");
179 else
180 fprintf(stderr,"umt: AddData: addcursor_: %s\n", addcursor_->GetBin().str().c_str());
181 }
182
183 Sha1Hash hash(data,length);
184 Node *next = CreateNext();
185 next->SetHash(hash);
186 next->SetVerified(true); // Mark node as computed
187
188 if (tree_debug)
189 fprintf(stderr,"umt: AddData: set %s hash %s\n", next->GetBin().str().c_str(), next->GetHash().hex().c_str());
190
191 // Calc new peaks
192 size_ += length;
193 sizec_++;
194 complete_ += length;
195 completec_++;
196 peak_count_ = gen_peaks(size_in_chunks(),peak_bins_);
197
198 state_ = LHT_STATE_SIGN_DATA;
199
200 return next->GetBin();
201 }
202
203
CreateNext()204 Node *LiveHashTree::CreateNext()
205 {
206 if (addcursor_ == NULL) {
207 if (tree_debug)
208 fprintf(stderr,"umt: CreateNext: create root\n");
209 root_ = new Node();
210 root_->SetBin(bin_t(0,0));
211 addcursor_ = root_;
212 } else if (addcursor_->GetBin().is_left()) {
213 // Left child, create sibling
214 Node *newright = new Node();
215 newright->SetBin(addcursor_->GetBin().sibling());
216
217 if (tree_debug)
218 fprintf(stderr,"umt: CreateNext: create sibling %s\n", newright->GetBin().str().c_str());
219
220 Node *par = addcursor_->GetParent();
221 if (par == NULL) {
222 // We was root, create new parent
223 par = new Node();
224 par->SetBin(bin_t(addcursor_->GetBin().layer()+1,0));
225 root_ = par;
226
227 if (tree_debug)
228 fprintf(stderr,"umt: CreateNext: create new root %s\n", root_->GetBin().str().c_str());
229 }
230 par->SetChildren(addcursor_,newright);
231 newright->SetParent(par);
232 addcursor_->SetParent(par);
233 addcursor_ = newright;
234 } else {
235 if (tree_debug)
236 fprintf(stderr,"umt: CreateNext: create tree\n");
237
238 // We right child, need next
239 Node *iter = addcursor_;
240 while (true) {
241 iter = iter->GetParent();
242 if (tree_debug)
243 fprintf(stderr,"umt: CreateNext: create tree: check %s\n", iter->GetBin().str().c_str());
244
245 if (iter == root_) {
246 // Need new root
247 Node *newroot = new Node();
248 newroot->SetBin(bin_t(iter->GetBin().layer()+1,0));
249
250 if (tree_debug)
251 fprintf(stderr,"umt: CreateNext: create tree: new root %s\n", newroot->GetBin().str().c_str());
252
253 newroot->SetChildren(iter,NULL);
254 root_ = newroot;
255 iter->SetParent(newroot);
256 iter = newroot;
257 }
258 if (iter->GetRight() == NULL) { // not elsif
259 // Create new subtree
260 Node *newright = new Node();
261 newright->SetBin(iter->GetBin().right());
262
263 if (tree_debug)
264 fprintf(stderr,"umt: CreateNext: create tree: new right %s\n", newright->GetBin().str().c_str());
265
266 iter->SetChildren(iter->GetLeft(),newright);
267 newright->SetParent(iter);
268
269 // Need tree down to base layer
270 int depth = iter->GetBin().layer()-1;
271
272 iter = newright;
273 Node *newleft = NULL;
274 for (int i=0; i<depth; i++) {
275 newleft = new Node();
276 newleft->SetBin(iter->GetBin().left());
277
278 if (tree_debug)
279 fprintf(stderr,"umt: CreateNext: create tree: new left down %s\n", newleft->GetBin().str().c_str());
280
281 iter->SetChildren(newleft,NULL);
282 newleft->SetParent(iter);
283
284 iter = newleft;
285 }
286 addcursor_ = newleft;
287 break;
288 }
289 // if left, continue
290 }
291 }
292 return addcursor_;
293
294 }
295
296
GetLastMunro()297 bin_t LiveHashTree::GetLastMunro()
298 {
299 if (source_last_munro_ != bin_t::NONE)
300 return source_last_munro_;
301 else
302 return GetClientLastMunro();
303 }
304
305
GetClientLastMunro()306 bin_t LiveHashTree::GetClientLastMunro()
307 {
308 if (peak_count_ == 0)
309 return bin_t::NONE;
310
311 bin_t lastpeak = peak_bins_[peak_count_-1];
312 int nchunks_per_sign_layer = (int)log2((double)nchunks_per_sig_);
313
314 bin_t newmunro = lastpeak;
315 while (newmunro.layer() > nchunks_per_sign_layer)
316 newmunro = newmunro.right();
317
318 return newmunro;
319 }
320
321
322
AddSignedMunro()323 BinHashSigTuple LiveHashTree::AddSignedMunro()
324 {
325 bin_t newmunro = GetClientLastMunro();
326
327 if (tree_debug)
328 fprintf(stderr,"umt: AddSignedMunro: %s\n", newmunro.str().c_str());
329 Node *n = FindNode(newmunro);
330 if (n == NULL) {
331 fprintf(stderr,"umt: AddSignedMunro: cannot find munro in tree?!\n");
332 return BinHashSigTuple::NOBULL;
333 }
334 ComputeTree(n);
335
336 // Hash of new munro known, now sign and store for transmission
337 Sha1Hash hash = n->GetHash();
338
339 Signature *sig = keypair_.Sign(hash.bytes(),Sha1Hash::SIZE);
340 if (sig == NULL)
341 return BinHashSigTuple::NOBULL;
342
343 SigTintTuple *sigtintptr = new SigTintTuple(*sig,NOW);
344
345 // Store in tree
346 n->SetSigTint(sigtintptr);
347
348 source_last_munro_ = newmunro;
349
350 return BinHashSigTuple(newmunro,hash,*sigtintptr);
351 }
352
353
ComputeTree(Node * start)354 void LiveHashTree::ComputeTree(Node *start)
355 {
356 if (tree_debug)
357 fprintf(stderr,"umt: ComputeTree: start %s %s\n", start->GetBin().str().c_str(),
358 start->GetVerified() ? "true" : "false");
359 if (!start->GetVerified()) {
360 ComputeTree(start->GetLeft());
361 ComputeTree(start->GetRight());
362 if (!start->GetLeft()->GetVerified())
363 fprintf(stderr,"umt: ComputeTree: left failed to become verified!");
364 if (!start->GetRight()->GetVerified())
365 fprintf(stderr,"umt: ComputeTree: right failed to become verified!");
366 Sha1Hash h(start->GetLeft()->GetHash(),start->GetRight()->GetHash());
367 start->SetHash(h);
368 start->SetVerified(true);
369 }
370 }
371
372
DeriveRoot()373 Sha1Hash LiveHashTree::DeriveRoot()
374 {
375 // From MmapHashTree
376
377 int c = peak_count_-1;
378 bin_t p = peak_bins_[c];
379 Sha1Hash hash = this->hash(p);
380 c--;
381 // Arno, 2011-10-14: Root hash = top of smallest tree covering content IMHO.
382 //while (!p.is_all()) {
383 while (c >= 0) {
384 if (p.is_left()) {
385 p = p.parent();
386 hash = Sha1Hash(hash,Sha1Hash::ZERO);
387 } else {
388 if (c<0 || peak_bins_[c]!=p.sibling())
389 return Sha1Hash::ZERO;
390 hash = Sha1Hash(this->hash(peak_bins_[c]),hash);
391 p = p.parent();
392 c--;
393 }
394 }
395
396 //fprintf(stderr,"umt: DeriveRoot: root hash is %s\n", hash.hex().c_str() );
397 //fprintf(stderr,"umt: DeriveRoot: bin is %s\n", p.str().c_str() );
398 return hash;
399 }
400
401
InitFromCheckpoint(BinHashSigTuple lastmunrotup)402 bool LiveHashTree::InitFromCheckpoint(BinHashSigTuple lastmunrotup)
403 {
404 fprintf(stderr,"umt: InitFromCheckpoint: %s %s %" PRIi64 " %s\n", lastmunrotup.bin().str().c_str(),
405 lastmunrotup.hash().hex().c_str(), lastmunrotup.sigtint().time(), lastmunrotup.sigtint().sig().hex().c_str());
406
407 // Build fake tree to hold lastmunrotup
408 bin_t fbin = lastmunrotup.bin();
409 uint64_t fsize = (fbin.layer_offset()+1) * fbin.base_length();
410 bin_t fpeaks[64];
411 int fcount = gen_peaks(fsize,fpeaks);
412 for (int i=0; i<fcount; i++) {
413 OfferHash(fpeaks[i],lastmunrotup.hash()); // bad hash
414 }
415
416 // Add lastmunrotup hash to tree
417 OfferHash(lastmunrotup.bin(),lastmunrotup.hash());
418
419 // Add lastmunrotup sig to tree
420 if (!OfferSignedMunroHash(lastmunrotup.bin(),lastmunrotup.sigtint())) {
421 fprintf(stderr,"umt: InitFromCheckpoint: failed!\n");
422 return false;
423 }
424
425 // Create fake right ridge to set addcursor_
426 bin_t baseright = lastmunrotup.bin().base_right();
427 CreateAndVerifyNode(baseright,Sha1Hash::ZERO,true);
428 addcursor_ = FindNode(baseright);
429
430 return true;
431 }
432
433
GetMunro(bin_t pos)434 bin_t LiveHashTree::GetMunro(bin_t pos)
435 {
436 if (nchunks_per_sig_ == 0)
437 return bin_t::NONE;
438
439 int nchunks_per_sign_layer = (int)log2((double)nchunks_per_sig_);
440
441 if (pos.layer() == nchunks_per_sign_layer)
442 return pos;
443
444 bin_t p = pos.base_left();
445 for (int i=0; i<nchunks_per_sign_layer; i++)
446 p = p.parent();
447
448 //fprintf(stderr,"umt: GetMunro: %s nchunks %" PRIu32 " layer %d computed %" PRIu32 "\n", pos.str().c_str(), nchunks_per_sig_, nchunks_per_sign_layer, p.layer() );
449
450 return p;
451 }
452
453
GetSignedMunro(bin_t munro)454 BinHashSigTuple LiveHashTree::GetSignedMunro(bin_t munro)
455 {
456 Node *n = FindNode(munro);
457 if (n == NULL)
458 return BinHashSigTuple::NOBULL;
459 SigTintTuple *stptr = n->GetSigTint();
460 if (stptr == NULL)
461 return BinHashSigTuple::NOBULL;
462
463 BinHashSigTuple bhst(munro,n->GetHash(),*stptr);
464 return bhst;
465 }
466
467
468
469 /*
470 * Live client specific
471 */
472
OfferSignedMunroHash(bin_t pos,SigTintTuple & sigtint)473 bool LiveHashTree::OfferSignedMunroHash(bin_t pos, SigTintTuple &sigtint)
474 {
475 if (tree_debug)
476 fprintf(stderr,"umt: OfferSignedMunroHash: munro %s\n", pos.str().c_str());
477
478 if (pos != cand_munro_bin_) {
479 // Ignore duplicate (or message mixup)
480 if (tree_debug)
481 fprintf(stderr,"umt: OfferSignedMunroHash: message mixup! %s %s\n", pos.str().c_str(), cand_munro_bin_.str().c_str());
482 return false;
483 }
484
485 // Check if new munro
486 int i=0;
487 for (i=0; i<peak_count_; i++) { // SUMMITTODO: not really peak anymore
488 if (pos == peak_bins_[i]) {
489 if (tree_debug)
490 fprintf(stderr,"umt: OfferSignedMunroHash: peak known\n");
491 return false;
492 }
493 }
494
495 // New munro
496
497 // MUNROTODO: source RESTART
498
499 bool sigok = keypair_.Verify(cand_munro_hash_.bytes(),cand_munro_hash_.SIZE,sigtint.sig());
500 if (!sigok) {
501 //if (tree_debug)
502 fprintf(stderr,"umt: OfferSignedMunroHash: signature wrong! %s\n", pos.str().c_str());
503 return false;
504 }
505
506 // Check if sane
507 bin_t oldmunro = GetLastMunro();
508 if (oldmunro != bin_t::NONE && oldmunro.layer_offset()+1 != pos.layer_offset()) {
509 if (tree_debug)
510 fprintf(stderr,"umt: OfferSignedMunroHash: SKIP old munro %s layer off %llu new %llu\n", oldmunro.str().c_str(),
511 oldmunro.layer_offset(), pos.layer_offset());
512 }
513
514 // Bootstrap tree if this is the first
515 if (state_ == LHT_STATE_VER_AWAIT_PEAK) {
516 state_ = LHT_STATE_VER_AWAIT_DATA;
517 // nchunks_per_sig known from trusted source
518 SetNChunksPerSig(cand_munro_bin_.base_length());
519
520 // Grow tree such that munro fits in it, and other peers can send
521 // other munros (e.g. older)
522 // NOTE: recursive call, InitFromCheckpoint calls OfferSignedMunroHash
523 InitFromCheckpoint(BinHashSigTuple(cand_munro_bin_,cand_munro_hash_,sigtint));
524 return true;
525 }
526
527 sizec_ = (pos.layer_offset()+1) * pos.base_length();
528 size_ = sizec_ * chunk_size_;
529
530 // Recalculate peaks
531 peak_count_ = gen_peaks(size_in_chunks(),peak_bins_);
532
533
534 if (state_ == LHT_STATE_VER_AWAIT_PEAK)
535 state_ = LHT_STATE_VER_AWAIT_DATA;
536
537 CreateAndVerifyNode(cand_munro_bin_,cand_munro_hash_,true);
538
539 Node *n = FindNode(cand_munro_bin_);
540 if (n == NULL) {
541 if (tree_debug)
542 fprintf(stderr,"umt: OfferSignedMunroHash: Added verified node, now can't find it?!\n");
543 return false;
544 } else {
545 SigTintTuple *stptr = new SigTintTuple(sigtint);
546 n->SetSigTint(stptr);
547
548 // Could recalc root hash here, but never really used. Doing it on-demand
549 // in root_hash() conflicts with const def :-(
550 //root_->SetHash(DeriveRoot());
551
552 return true; // signal new
553 }
554 }
555
556
CreateAndVerifyNode(bin_t pos,const Sha1Hash & hash,bool verified)557 bool LiveHashTree::CreateAndVerifyNode(bin_t pos, const Sha1Hash &hash, bool verified)
558 {
559 // This adds hashes on client side
560 if (tree_debug)
561 fprintf(stderr,"umt: OfferHash: %s %s\n", pos.str().c_str(), hash.hex().c_str());
562
563 // Find or create node
564 Node *iter = root_;
565 Node *parent = NULL;
566 while (true) {
567 if (tree_debug) {
568 if (iter == NULL)
569 fprintf(stderr,"umt: OfferHash: iter NULL\n");
570 else
571 fprintf(stderr,"umt: OfferHash: iter %s\n", iter->GetBin().str().c_str());
572 }
573
574 if (iter == NULL) {
575 // Need to create some tree for it
576 if (parent == NULL) {
577 // No root
578 root_ = new Node();
579 root_->SetBin(pos);
580
581 if (tree_debug)
582 fprintf(stderr,"umt: OfferHash: new root %s %s\n", root_->GetBin().str().c_str(), hash.hex().c_str());
583
584 root_->SetHash(hash);
585 root_->SetVerified(verified);
586 return false;
587 } else {
588 // Create left or right tree
589 if (pos.toUInt() < parent->GetBin().toUInt()) {
590 // Need node on left
591 Node *newleft = new Node();
592 newleft->SetBin(parent->GetBin().left());
593
594 if (tree_debug)
595 fprintf(stderr,"umt: OfferHash: create left %s\n", newleft->GetBin().str().c_str());
596
597 newleft->SetParent(parent);
598
599 parent->SetChildren(newleft,parent->GetRight());
600 iter = newleft;
601 } else {
602 // Need new node on right
603 Node *newright = new Node();
604 newright->SetBin(parent->GetBin().right());
605
606 if (tree_debug)
607 fprintf(stderr,"umt: OfferHash: create right %s\n", newright->GetBin().str().c_str());
608
609 newright->SetParent(parent);
610
611 parent->SetChildren(parent->GetLeft(),newright);
612 iter = newright;
613 }
614 }
615 } else if (!iter->GetBin().contains(pos)) {
616 // Offered pos not a child, error or create new root
617 Node *newroot = new Node();
618 newroot->SetBin(iter->GetBin().parent());
619
620 if (tree_debug)
621 fprintf(stderr,"umt: OfferHash: new root no cover %s\n", newroot->GetBin().str().c_str());
622
623 if (pos.layer_offset() < iter->GetBin().layer_offset())
624 newroot->SetChildren(NULL,iter);
625 else
626 newroot->SetChildren(iter,NULL);
627 root_ = newroot;
628 iter->SetParent(newroot);
629 iter = newroot;
630 parent = NULL;
631 // Arno, 2013-03-14: New root may not be high enough, retest from start
632 continue;
633 }
634
635 if (pos.toUInt() == iter->GetBin().toUInt()) {
636 // Found it
637 if (tree_debug)
638 fprintf(stderr,"umt: OfferHash: found node %s\n", iter->GetBin().str().c_str());
639 break;
640 } else if (pos.toUInt() < iter->GetBin().toUInt()) {
641 if (tree_debug)
642 fprintf(stderr,"umt: OfferHash: go left\n");
643
644 parent = iter;
645 iter = iter->GetLeft();
646 } else {
647 if (tree_debug)
648 fprintf(stderr,"umt: OfferHash: go right\n");
649
650 parent = iter;
651 iter = iter->GetRight();
652 }
653 }
654
655
656 if (iter == NULL) {
657 if (tree_debug)
658 fprintf(stderr,"umt: OfferHash: internal error, couldn't find or create node\n");
659 return false;
660 }
661
662 if (state_ == LHT_STATE_VER_AWAIT_PEAK) {
663 if (tree_debug)
664 fprintf(stderr,"umt: OfferHash: No peak yet, can't verify!\n");
665 return false;
666 }
667
668
669 //
670 // From MmapHashTree::OfferHash
671 //
672
673 if (tree_debug)
674 fprintf(stderr,"umt: OfferHash: found node %s isverified %d\n",iter->GetBin().str().c_str(),iter->GetVerified());
675
676 bin_t munro = GetMunro(pos);
677 if (munro.is_none())
678 return false;
679 if (munro==pos) {
680 // Diff from MmapHashTree: store munro here
681 if (verified) {
682 if (tree_debug)
683 fprintf(stderr,"umt: OfferHash: setting munro %s %s\n",pos.str().c_str(),hash.hex().c_str());
684
685 iter->SetHash(hash);
686 iter->SetVerified(verified);
687 }
688 return hash == iter->GetHash();
689 }
690
691 // LESSHASH
692 // Arno: if we already verified this hash against the root, don't replace
693 if (iter->GetVerified())
694 return hash == iter->GetHash();
695
696 iter->SetHash(hash);
697
698 if (tree_debug)
699 fprintf(stderr,"umt: OfferHash: setting hash %s %s\n",pos.str().c_str(),hash.hex().c_str());
700
701 Node *piter = iter;
702 Sha1Hash uphash = hash;
703
704 if (tree_debug)
705 fprintf(stderr,"umt: OfferHash: verifying %s\n", pos.str().c_str());
706 // Walk to the nearest proven hash
707 // Arno, 2013-03-11: Can't use is_empty as we may have verified some hashes
708 // under an old peak, but now that the tree has grown this doesn't indicate
709 // verified status anymore.
710 //
711 // while ( piter->GetBin()!=munro && ack_out_.is_empty(piter->GetBin()) && !piter->GetVerified() ) {
712 while (piter->GetBin()!=munro && !piter->GetVerified()) {
713 piter->SetHash(uphash);
714 piter = piter->GetParent();
715
716 // Arno: Prevent poisoning the tree with bad values:
717 // Left hand hashes should never be zero, and right
718 // hand hash is only zero for the last packet, i.e.,
719 // layer 0. Higher layers will never have 0 hashes
720 // as SHA1(zero+zero) != zero (but b80de5...)
721 //
722
723 if (tree_debug)
724 fprintf(stderr,"umt: OfferHash: squirrel %s %p %p\n", piter->GetBin().str().c_str(), piter->GetLeft(),
725 piter->GetRight());
726
727 if (piter->GetLeft() == NULL || piter->GetRight() == NULL) {
728 if (tree_debug) {
729 if (piter->GetLeft() == NULL)
730 fprintf(stderr,"umt: OfferHash: Error! Missing left child of %s\n", piter->GetBin().str().c_str());
731 if (piter->GetRight() == NULL)
732 fprintf(stderr,"umt: OfferHash: Error! Missing right child of %s\n", piter->GetBin().str().c_str());
733 }
734
735 return false; // tree still incomplete
736 }
737
738 if (tree_debug)
739 fprintf(stderr,"umt: OfferHash: hashsquirrel %s %s %s\n", piter->GetBin().str().c_str(),
740 piter->GetLeft()->GetHash().hex().c_str(), piter->GetRight()->GetHash().hex().c_str());
741
742 if (piter->GetLeft()->GetHash() == Sha1Hash::ZERO || piter->GetRight()->GetHash() == Sha1Hash::ZERO)
743 break;
744 uphash = Sha1Hash(piter->GetLeft()->GetHash(),piter->GetRight()->GetHash());
745 }
746
747 if (tree_debug) {
748 fprintf(stderr,"umt: OfferHash: while %d %d %d\n", piter->GetBin()!=munro, ack_out_.is_empty(piter->GetBin()),
749 !piter->GetVerified());
750 fprintf(stderr,"umt: OfferHash: %s computed %s truth %s\n", piter->GetBin().str().c_str(), uphash.hex().c_str(),
751 piter->GetHash().hex().c_str());
752 }
753
754 if (piter->GetHash() == Sha1Hash::ZERO)
755 return false; // missing hashes
756
757 bool success = (uphash==piter->GetHash());
758 // LESSHASH
759 if (success) {
760 // Arno: The hash checks out. Mark all hashes on the uncle path as
761 // being verified, so we don't have to go higher than them on a next
762 // check.
763
764 // Arno, 2013-05-07: uncle path = sibling + uncles
765 // Find sibling
766 piter = iter;
767 if (piter->GetParent() != NULL) {
768 if (pos.is_left())
769 piter = piter->GetParent()->GetRight();
770 else
771 piter = piter->GetParent()->GetLeft();
772
773 if (SetVerifiedIfNot0(piter,pos,0))
774 return true;
775 }
776
777 // Find uncles
778 bin_t p = pos;
779 piter = iter;
780 piter->SetVerified(true);
781 // Arno, 2013-05-13: Not too high
782 while (p.layer() != (munro.layer()-1)) {
783 p = p.parent().sibling();
784 if (piter->GetParent() == NULL)
785 break;
786 if (piter->GetParent()->GetParent() == NULL)
787 break;
788 if (piter->GetParent()->GetBin().is_left())
789 piter = piter->GetParent()->GetParent()->GetRight();
790 else
791 piter = piter->GetParent()->GetParent()->GetLeft();
792
793 if (SetVerifiedIfNot0(piter,p,1))
794 return true;
795 }
796 // Also mark hashes on direct path to root as verified. Doesn't decrease
797 // #checks, but does increase the number of verified hashes faster.
798 // Arno, 2013-03-08: Only holds if hashes are permanent (i.e., not
799 // parents of peaks while live streaming with Unified Merkle Trees.
800 p = pos;
801 piter = iter;
802 while (p != munro) {
803 p = p.parent();
804 piter = piter->GetParent();
805
806 if (SetVerifiedIfNot0(piter,p,2))
807 return true;
808 }
809 }
810 return success;
811 }
812
813
814
SetVerifiedIfNot0(Node * piter,bin_t p,int verclass)815 bool LiveHashTree::SetVerifiedIfNot0(Node *piter, bin_t p, int verclass)
816 {
817 if (piter == NULL) {
818 if (tree_debug)
819 fprintf(stderr,"umt: OfferHash: SetVerified%" PRIu32 " %s has NULL node!!!\n", verclass, p.str().c_str());
820 return true; // had success
821 } else {
822 if (piter->GetHash() == Sha1Hash::ZERO) {
823 if (tree_debug)
824 fprintf(stderr,"umt: OfferHash: SetVerified%" PRIu32 " %s has ZERO hash!!!\n", verclass, piter->GetBin().str().c_str());
825 } else {
826 if (tree_debug)
827 fprintf(stderr,"umt: OfferHash: SetVerified%" PRIu32 " %s\n", verclass, piter->GetBin().str().c_str());
828 piter->SetVerified(true);
829 }
830 }
831 return false; // = continue
832 }
833
834
835
836 /*
837 * HashTree interface
838 */
839
OfferHash(bin_t pos,const Sha1Hash & hash)840 bool LiveHashTree::OfferHash(bin_t pos, const Sha1Hash& hash)
841 {
842 if (hash == Sha1Hash::ZERO) {
843 if (tree_debug)
844 fprintf(stderr,"umt: OfferHash: zero\n");
845 return false;
846 }
847
848 // SIGNED_INTEGRITY follows INTEGRITY, so store till we process that.
849 // In the future atomic processing of the whole datagram would be better
850 cand_munro_bin_ = pos;
851 cand_munro_hash_ = hash;
852
853 bin_t munro = GetMunro(pos);
854 if (munro.is_none()) {
855 if (tree_debug)
856 fprintf(stderr,"umt: OfferHash: no munro\n");
857 return false;
858 } else {
859 if (tree_debug)
860 fprintf(stderr,"umt: OfferHash: %s has munro %s\n", pos.str().c_str(), munro.str().c_str());
861 return CreateAndVerifyNode(pos,hash,false);
862 }
863 }
864
865
OfferData(bin_t pos,const char * data,size_t length)866 bool LiveHashTree::OfferData(bin_t pos, const char* data, size_t length)
867 {
868 if (state_ == LHT_STATE_VER_AWAIT_PEAK) {
869 if (tree_debug)
870 fprintf(stderr,"umt: OfferData: await munro\n");
871 return false;
872 }
873 if (!pos.is_base()) {
874 if (tree_debug)
875 fprintf(stderr,"umt: OfferData: not base\n");
876 return false;
877 }
878 if (length<chunk_size_ && pos!=bin_t(0,sizec_-1)) {
879 if (tree_debug)
880 fprintf(stderr,"umt: OfferData: bad len " PRISIZET "\n", length);
881 return false;
882 }
883 if (ack_out_.is_filled(pos)) {
884 if (tree_debug)
885 fprintf(stderr,"umt: OfferData: already have\n");
886 return true; // to set data_in_
887 }
888 bin_t munro = GetMunro(pos);
889 if (munro.is_none()) {
890 if (tree_debug)
891 fprintf(stderr,"umt: OfferData: couldn't find munro\n");
892 return false;
893 }
894
895 Sha1Hash data_hash(data,length);
896 if (tree_debug)
897 fprintf(stderr,"umt: OfferData: %s hash %s\n", pos.str().c_str(), data_hash.hex().c_str());
898
899 if (!OfferHash(pos, data_hash)) {
900 //printf("invalid hash for %s: %s\n",pos.str(bin_name_buf),data_hash.hex().c_str()); // paranoid
901 //fprintf(stderr,"umt: INVALID HASH FOR %" PRIi64 " layer %d\n", pos.toUInt(), pos.layer() );
902 // Ric: TODO it's not necessarily a bug.. it happens if a pkt was lost!
903 dprintf("%s hashtree check failed (bug TODO) %s\n",tintstr(),pos.str().c_str());
904 return false;
905 }
906
907 //printf("g %" PRIi64 " %s\n",(uint64_t)pos,hash.hex().c_str());
908 if (tree_debug)
909 fprintf(stderr,"umt: OfferData: set ack_out_ %s\n", pos.str().c_str());
910
911 ack_out_.set(pos);
912
913 // Arno,2011-10-03: appease g++
914 if (storage_->Write(data,length,pos.base_offset()*chunk_size_) < 0)
915 print_error("pwrite failed");
916
917 complete_ += length;
918 completec_++;
919
920 return true;
921
922 }
923
924
peak_count() const925 int LiveHashTree::peak_count() const
926 {
927 return peak_count_; // TODOinline
928 }
929
peak(int i) const930 bin_t LiveHashTree::peak(int i) const
931 {
932 return peak_bins_[i]; // TODOinline
933 }
934
peak_hash(int i) const935 const Sha1Hash& LiveHashTree::peak_hash(int i) const
936 {
937 return hash(peak(i)); // TODOinline
938 }
939
peak_for(bin_t pos) const940 bin_t LiveHashTree::peak_for(bin_t pos) const
941 {
942 for (int i=0; i<peak_count_; i++) {
943 if (peak_bins_[i].contains(pos))
944 return peak_bins_[i];
945 }
946 return bin_t::NONE;
947 }
948
hash(bin_t pos) const949 const Sha1Hash& LiveHashTree::hash(bin_t pos) const
950 {
951 // This API may not be fastest with dynamic tree.
952 Node *n = FindNode(pos);
953 if (n == NULL)
954 return Sha1Hash::ZERO;
955 else {
956 if (!n->GetVerified()) {
957 if (tree_debug)
958 fprintf(stderr,"umt::hash %s not verified SENDING!\n", pos.str().c_str());
959 dprintf("%s umt::hash %s SENDING unverified!\n", tintstr(), pos.str().c_str());
960 }
961 return n->GetHash();
962 }
963 }
964
FindNode(bin_t pos) const965 Node *LiveHashTree::FindNode(bin_t pos) const
966 {
967 Node *iter = root_;
968 while (true) {
969 if (iter == NULL)
970 return NULL;
971 else if (pos.toUInt() == iter->GetBin().toUInt())
972 return iter;
973 else if (pos.toUInt() < iter->GetBin().toUInt())
974 iter = iter->GetLeft();
975 else
976 iter = iter->GetRight();
977 }
978 }
979
980
root_hash() const981 const Sha1Hash& LiveHashTree::root_hash() const
982 {
983 if (root_ == NULL)
984 return Sha1Hash::ZERO;
985 else
986 return root_->GetHash();
987 }
988
size() const989 uint64_t LiveHashTree::size() const
990 {
991 return size_;
992 }
993
size_in_chunks() const994 uint64_t LiveHashTree::size_in_chunks() const
995 {
996 return size_/chunk_size_; // TODOinline
997 }
998
999
complete() const1000 uint64_t LiveHashTree::complete() const
1001 {
1002 return complete_;
1003 }
1004
chunks_complete() const1005 uint64_t LiveHashTree::chunks_complete() const
1006 {
1007 return completec_;
1008 }
1009
seq_complete(int64_t offset)1010 uint64_t LiveHashTree::seq_complete(int64_t offset)
1011 {
1012 return 0;
1013 }
is_complete()1014 bool LiveHashTree::is_complete()
1015 {
1016 return false;
1017 }
ack_out()1018 binmap_t *LiveHashTree::ack_out()
1019 {
1020 return &ack_out_;
1021 }
1022
chunk_size()1023 uint32_t LiveHashTree::chunk_size()
1024 {
1025 return chunk_size_; // TODOinline
1026 }
1027
1028
get_storage()1029 Storage *LiveHashTree::get_storage()
1030 {
1031 return storage_;
1032 }
set_size(uint64_t)1033 void LiveHashTree::set_size(uint64_t)
1034 {
1035 }
1036
sane_tree()1037 void LiveHashTree::sane_tree()
1038 {
1039 if (root_ == NULL)
1040 return;
1041 else {
1042 sane_node(root_,NULL);
1043 }
1044 }
1045
1046
sane_node(Node * n,Node * parent)1047 void LiveHashTree::sane_node(Node *n, Node *parent)
1048 {
1049 //fprintf(stderr,"umt: Sane: %s\n", n->GetBin().str().c_str() );
1050 assert(n->GetParent() == parent);
1051 if (n->GetLeft() != NULL) {
1052 assert(n->GetLeft()->GetParent() == n);
1053 assert(n->GetLeft()->GetBin() == n->GetBin().left());
1054 sane_node(n->GetLeft(),n);
1055 }
1056 if (n->GetRight() != NULL) {
1057 assert(n->GetRight()->GetParent() == n);
1058 assert(n->GetRight()->GetBin() == n->GetBin().right());
1059 sane_node(n->GetRight(),n);
1060 }
1061 }
1062
GetSigSizeInBytes()1063 uint16_t LiveHashTree::GetSigSizeInBytes()
1064 {
1065 return keypair_.GetSigSizeInBytes();
1066 }
1067