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