From f7e4067282da6143a26fda4e22817ce15aa21051 Mon Sep 17 00:00:00 2001 From: zelig Date: Mon, 25 Apr 2016 18:52:18 +0100 Subject: [PATCH] expand smash about erasure and reliability minor rephasing and text cleanup redraw response type table add abstract --- swarm/docs/refs.bib | 82 ++++++++++++++- swarm/docs/smash/fig/response-types.pdf | Bin 28857 -> 27900 bytes swarm/docs/smash/fig/response-types.tex | 2 +- swarm/docs/smash/smash.rst | 129 +++++++++++++----------- 4 files changed, 150 insertions(+), 63 deletions(-) diff --git a/swarm/docs/refs.bib b/swarm/docs/refs.bib index c19db26b3913..7de7ff51cabf 100644 --- a/swarm/docs/refs.bib +++ b/swarm/docs/refs.bib @@ -22,15 +22,15 @@ @TECHREPORT{ethersphere2016sw3 } @TECHREPORT{ethersphere2016smash, - author = {Viktor Tron and Aron Fischer and Daniel Varga}, + author = {Viktor Tron and Aron Fischer}, title = {smash-proof: auditable storage in swarm secured by masked audit secret hash}, institution = {Ethersphere}, note = {Ethersphere Orange Papers 2}, year = {2016} } @TECHREPORT{ethersphere2016swap, - author = {Viktor Tron and Aron Fischer}, - title = {State channel networks: accounting and litigation on the blockchain (tentative title)}, + author = {Viktor Tron and Aron Fischer and Daniel A Nagy}, + title = {State channels on swap networks: claims and obligations on and off the blockchain (tentative title)}, institution = {Ethersphere}, note = {Ethersphere Orange Papers (to be published)}, year = {2016} @@ -245,6 +245,8 @@ @inproceedings{merkle1980protocols organization={IEEE} } +# routing p2p papers + @incollection{maymounkov2002kademlia, title={Kademlia: A peer-to-peer information system based on the xor metric}, author={Maymounkov, Petar and Mazieres, David}, @@ -253,3 +255,77 @@ @incollection{maymounkov2002kademlia year={2002}, publisher={Springer} } + +@inproceedings{roos2015determining, + title={Determining the Hop Count in Kademlia-type Systems}, + author={Roos, Stefanie and Salah, Hani and Strufe, Thorsten}, + booktitle={IEEE ICCCN}, + year={2015} +} + +@inproceedings{salah2014characterizing, + title={Characterizing graph-theoretic properties of a large-scale DHT: Measurements vs. simulations}, + author={Salah, Hani and Roos, Stefanie and Strufe, Thorsten}, + booktitle={Computers and Communication (ISCC), 2014 IEEE Symposium on}, + pages={1--7}, + year={2014}, + organization={IEEE} +} + + +@inproceedings{kaune2008embracing, + title={Embracing the peer next door: Proximity in kademlia}, + author={Kaune, Sebastian and Lauinger, Tobias and Kova{\v{c}}evi{\'c}, Aleksandra and Pussep, Konstantin}, + booktitle={Peer-to-Peer Computing, 2008. P2P'08. Eighth International Conference on}, + pages={343--350}, + year={2008}, + organization={IEEE} +} + +@inproceedings{heep2010r, + title={R/Kademlia: Recursive and topology-aware overlay routing}, + author={Heep, Bernhard}, + booktitle={Telecommunication Networks and Applications Conference (ATNAC), 2010 Australasian}, + pages={102--107}, + year={2010}, + organization={IEEE} +} +@inproceedings{varvello2009walkable, + title={A Walkable Kademlia network for virtual worlds.}, + author={Varvello, Matteo and Diot, Christophe and Biersack, Ernst}, + booktitle={IPTPS}, + pages={2}, + year={2009} +} +@inproceedings{guangmin2009improved, + title={An improved Kademlia routing algorithm for P2P network}, + author={Guangmin, Liang}, + booktitle={New Trends in Information and Service Science, 2009. NISS'09. International Conference on}, + pages={63--66}, + year={2009}, + organization={IEEE} +} +@inproceedings{wu2007kadstreaming, + title={KadStreaming: a novel Kademlia P2P network-based VoD streaming scheme}, + author={Wu, Jie and Liu, BiSheng and Zhang, ShiYong and Lu, ZhiHui and Zhong, YiPing}, + booktitle={Computer and Information Technology, 2007. CIT 2007. 7th IEEE International Conference on}, + pages={405--410}, + year={2007}, + organization={IEEE} +} +@inproceedings{einziger2013kaleidoscope, + title={Kaleidoscope: Adding colors to kademlia}, + author={Einziger, Gil and Friedman, Roy and Kibbar, Eyal}, + booktitle={Peer-to-Peer Computing (P2P), 2013 IEEE Thirteenth International Conference on}, + pages={1--10}, + year={2013}, + organization={IEEE} +} +@inproceedings{skodzik2014hartkad, + title={Hartkad: A hard real-time kademlia approach}, + author={Skodzik, Jan and Danielis, Peter and Altmann, Vlado and Timmermann, Dirk}, + booktitle={Consumer Communications and Networking Conference (CCNC), 2014 IEEE 11th}, + pages={309--314}, + year={2014}, + organization={IEEE} +} diff --git a/swarm/docs/smash/fig/response-types.pdf b/swarm/docs/smash/fig/response-types.pdf index f19d08d46b46ceb43c942ab0f5241870017fdadc..0401cd0a696b2d4e8efc4997cd42196b67f453a5 100644 GIT binary patch delta 15698 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 delta 16669 zcmV)9K*hiO*#WuX0gxjCG%%BJY$<=Om&M6RslG8rP%8#zo9N{gfw>ua0tiyA zz-K*a0~kk;V{V?;;5qsoeR#_?fr^v9)n=ZAno_&?VG`Xxn$0xSf(S5q0~~*9seo3H zPy!}%@Dk4wO5(+Iy-u_DG3+W4xhQ5uT0gToxNbHBqN&lKS_H9qd5b|*lO=omU_hvKshPO? zw#Eulio-!6w0>b~u7Q6cq=Xx=UCnnexU1cDx3zGC?rqX{Xbf66`KtRRGF;mM>}&V* zLz|ZWtDxg*u*Q{uC{0_ZI&HZlq? zOl59obZ9alF*7(ZH3~0GWo~D5Xfq%%3NK7$ZfA68ATcyKGB%SB11NvD18}5k*Qgy# zoQcg&Cbn(cwmMG7wrAprZF^!(CdS0JIWZ>I$;S8Y{eJ&nbxw6v_j4_;`(Ep*YH|`K zReE7FdlR69J;;TgnSqH1AS$oI%miR!Vr5`rVu2?oSF>`l1^z9DC)WTvIa}F-c>ZM| z>I5`)d6$V9yS&@U+k<}qGOo4&W>x?*2M;qR4-*rBg^7v#e+=!NcmQI?ZdPUhc?N)t zJqYLwPcCZj;OS&#Vd?Uo=6@amRHoDbW^QgyxD^p_-K;GEJ5@`3H(bU)$ zplWYw1$6QJuMkvxmM$(1JdBL)?(Pi6cFqj;P8I^xbO3iN7fXMD3eXwo{?Q`iA7S24 zSsY|0YHw!;1i3iF|52Zql@rkP{n$Mj|GHTlki9#|`)@F}0-2fr(S(_+1EV^~%Fz`l zE%vv`y9oXtnFY`Vz|O?P#L3MH06GGI9;TLze}q@_bO3+;sbu~`{N91Dw}ZU{!2G=l zps$rV@cjqg+u7I+2yk(71^RmbTk+on&&&)kvodu7m;f!TK=A)We-{JI|Kj({ce3&T z=rX;}9y5UHkI#Re^xwzJ%pPRx`H%UZ_sb|QE3c#=Mf+FB|Ivwv*n0rH>Dib7^epU5 z0Omi2jPrl}!S}zzC>dM*UBQDXuM{R6pW$XF3!TZp< zy1Xxdy#4zcfd03sCh)JNl?R$xx!V12t+b2r`yzh`gDh_5SGbJk*Q_H`m zN=f6{mgG}ws{#Y>< zb`F5ClasM0{QD)p6Fb10`F$77fF6GiF@TW)Wbg9s0(fuF7hrDh1pmj4a(Uf8l#3i+|yJILm+Gd;M1b!uLXK{)JosM%#bk zdtr9};QKx?g8qf?W!V1<-^+0L7ry6p`WJt`=XL%Uz8{>+zwo^b*ME@ZJ(0(s_+Phd z>gwe5{-XPH58p@NfB4V0DiG)aG=*Q9w>RYtv91g0xUUt)ccAd7equ91bb83q2t$4cdhV^6bs+3|h{_8?nq+T6o`+Xx1WcolTaQ zhdHmcN;MYeE?hEP9UMZ)8?@0W3U7ar!(gWR-xcqvzz{Q0)?&yr_g5f48Gavb*0_Ad6Tw$iyU+jRwF%a{Fg>~z%MJ4OD~BvIy}T0yX; zhp3UTU^{$slo&&GvB{Sz=t`{Oc_bn9Jl{|$Q8!;Fg^^^CYZ!l^mip>MWyZl|T*|>H zdc8TJ<2b&-e+tx??49g7o|~7N!%w)5WGwrMB(Y%OPAb8k80&ti`kBn9<}J`(nQ#1H zJOu$^%E+&YFN=tosmup9?TxSfm)&_o^TT51`mp82dTz)@)vo~9#>U#(48dVsBf)FV zZWFVZ#{8{=3o6xiOBUf9M1#v+S>Nn6xrNJbTbU^q}%dq&+BWRF$eZdBk`Cv z2rI7SWgg^nw3#YLW8J(tHgFQ>_3nEC5KcLc!|9}~xcq;2kcnAp)7r8OtFkyp!_?h$ z*pfeGy^TMM>WD~Ye}^X`^jx7rijbuY>t#`7n$bw9=8#q*BeQ+_^;p?LpMbro+l6yH z3mhAcydT7a#g!dhpkN`lNHnSO3cr&X#Z9AgwfB>+Wa-24T6c|4%MG99ph<71DgM~s z^RZ&;jr)JccK%OhW4~Qy4aTS;5q_a>zaLLYnBu#&^X$DI z$W9+7?*;?N`>K9S4P&}*t#7gD+n4ul0ICgN1f_p1N040)^F-{Xg#D67WeE{Y*i`I95NKA~pKxv(mn!YaE}6LO}dR4AH9qx55# zzPx{gjRZ#Xo8Bzj@8nA2EO|Uc8p717B65uTeC1eY?C9m9*}?@IcUiW))!rjr2vnci z7PX*2643Fau#sS?U?E)IDvS2P*i^fQnimiz!ms|aKKAkmhUoJ%DVnGouLNJe zfArjyKYZf|sL1_h@cqu%C7T#lNRjzCk1>A>OyZI_v5D1_=u_H`DYCr$!lY!s&dZuE zq+R7(o7Y5?gg-PKnr-<*1!<3rKsE5gqJ~JUrU-%Wfd+NlhgH>~6)Rl2yz{{Il5-U_ ztQM@I@9h%NgOKIlm9iKPzsr4?3h=o9P>f@!JFcbi85Mi*`nPg!%||t*w;Q+M+y{Sn z;7_`Ehu3AiU?+degvXWySFFppkSHTsTW>trJD~F2e4L?>IW`9?p45htvD=gvuKF0J zVQtPB#(+)*GZ9Vs?qD=pO{_fapov337_awQ`6ygql`<>Vp@s(UVqVAC=NY7rXw`}g zirJf1bRAq=74t;FC%s{z7CHQS{F{G5q!OEtvJ&@dc_vS(UpqAdV{EBxEvmb-mQALs zqSr`T4$J3~=SK9lULK6ul$o(>NBsa5+}n;CMJ*+xMSyr`1Dn%)XS0|L5R%u|ZdjPA zf`dYyc>=j?FI@c?)QfT_govX2@?bXwvCc?&NltDuX*sJ`iUi?B3;ZpREr)+6c(@E) ztb}6Y6`w5J-m%hHp<;}%FwRf6umu10Y1@2?gT{O9y@dwKrExIL<;lHZimrU7Kv}>m zE@nET6`a-5v@4uRHeQb?Jl9~Km#|dPTn;NZyeGqzZmvh`_L>W`uxnL$7NUdj1cNSH zf$AcQiF+cgDZr(y@Js=Shhu+9AU0aJhR{!%MndGbTfs}q>7ZBW?tzP@y)6lEu*NQ4 zJ+^w7fQd$sW4PLyEZKOsb@3~JibxpIwi$iujM-?F%a!5UmG*3BiS+SWfcJvV-)p#G ziX7g)y=EiV19FHd)j0@teh3#$lUc%J;%xRXWdmUGYWFp|(L=-Yrg486bt;Qg|C5&= zPD+V`+g10+EW)s_X}630r3_9Y++WBrK`q*%Riey~eJEL8HQ1l5JnlQ`6f0}Tof7u~ z_lZulGj}*RrO{3m(Z>^~Wz7d3g~XzhA?KN!!Ng`_A!zep#7qN1&9zVp7B+XZGFvZ% zeX>~=&2#iR_qEW06Gd*5w}L%V#o`?FpJST6G!kg~YmCK4p5=d0%HQBV4=3s=C-vY< z(3G!QsbO749~vkCZp{n}J{2#Ib&;JX;sqZPjsD%GM)N=Bl-AH2u8G@1^W#sa(5MZg2 zh2ZNBaz`f9;j0=I2)$(`8aGxh3~Vw?)_XulepshQay13|uq(!e>UrR;{oc=?(cHGr zsqTwj57HXv!z+WCLW?tVJoT-aw|mK07AWmqTTRsAzOC+s(ipxbN*EHuQ?b;r#@c&`?? zaRCVz?p%MN9enaiIF5z;5(x}E>^ef+WoQmWTGfNCy~zBp$^MKtB`T)b6`+>ezfzfrnYLtjc^=lKf9VsWbz$gc|56@_@48Xq*|8XfCPBbZ z`R;$bvQ{e@wA4n)0rIGebYWEood3`q!;&_^rO+Y>v%)DE#qjqDXf?10_G72w^Nx$K z0u;U6M^JKPiXfEXI+lT9=!ykKe4}4B)<7(8v=LG5Y`w@v;mziYbHoQN?z#rL*vg4ACusEn*vIfv;2pm%^f^u! z1q$v)PI@tms?v556euzG`Vj$#Ayiq$5Lhc@lI53wh9uciUCuO;!4kCrhn4pj?Hqp; z*kw7vHD7=cKGeM{i|fV_Qpr`DI;}G`Y_8GjzCZf=4tjr=LSv`{rbtGTwUbVcz#d3u z!KGnmwf9PAa&TqI4^4~2Yg$f-o-+7FmPV!Z@dH$$nePCfu4md%Es;ibmBZvL%eCqE zg8WpSUOkQ30rE=Pl4Wy~yhPj|q6vTWKa@>jYlC4$h6=F<#IJ2kQQ^VgXMPnx$m$Jl z9u||b4$nu~amIAQ4Dwh_hTmuC5m=s_uc^tKut}+2w(aAkNUr(Bcd(pZdj*W6HlNy+ z@X9c19&8rO-;p*26H=9;NalNk>WDx40CWR^aiIrhNdyt-?Pz=}XYIc>t`dJH@$~H2 z;klfl#mF`#De$;}N)9rakbj;3vc+ib%es-AaXeByxI-#gmW*0;Kxr=TJOwjLtfi^` z;`@Bt*xaJs*BEVp5HPzyZap?gBGq{wsVMaZJ3JOcZ1~U=$$J=HH-6>+bz7#zEf1+K zP=ECkJlPUVIr0jnsHI>adm4XVh$_wtVf*PwZTF>6LKRLHT)J^(LjXNSny|lVMA$D| zdrj~Ld8(^eXeY4dl20o}3zHyiZ|fB!Rv%jkH^OS8HcDyR+!z1NZzOvS&v`d9N4V&%uF z);iu4?6AX-iND99pJ9Iuxg)gNS&$N1jSDoN2!63?QDHdFxOs7-3>dUyK%*Q}-RTi) zA6>Hbd?v=>Ou))V)V`S)t*`30`_*XBR3quiZYY@nbKkhcT>OOW!WcD+@VXg2x_tq^ z$@b+Na~0^b;ggtvuLCsgzInL?w@6>Q1$3eN;Both zU1=xBbKz1}bK#&3ZB#4Q%7C7=-QKJ3Q|BksXxdIFzX-){Zh2y(m(7S^REi+i013h_ zsEEh(<#BWv)Z1;w<%Pp-mfI8Dy0ay&Z?LKdINY-FxFM*0YO-aa zKR@W3DD2N<{&Cf4>%Ro-!XE@Ta=jOV!1MV~c|wdizxw&GA$`DLnFIffG23(M$;kL3 z53P9UV}x$acm#^kbmypec0rFjUN_Wz-tP^Zl6Ix^`eTBJbB0oN(91HIf7#ZbW$Tn%iQ`dhMM;2qoyD@RD4HCIiX?(rtT92Moh4)TsA~oX_YW1=`U}wFcm&V z7MBtw(U*#~#7|0+QHB_fwn(}rdr4_z zR#Z8Wx|X$xYG4Ttq0X&WJ`z$)F9{#YAktRsfBw2ei z<H}J0MzmM$V!9qL6?!HJ_%X(XM>QXMwkc{NXphE#T&< zhM3HpPfA;x7P9YDiKtV=5cYuDknqqUf;r9$L~22NqLME!R0QcvhwSalr}3|9xy?ut zcaM4pcrSMbvk8!dc#sIZX>eUWM=Ag@y}o~-k5aC)9B<0~FO#X1S<0+KCcGY>T4IP< zuZdMhdCIL#P)}FLTU=zm!Y~T_%u{?j%OrHtSP$&M_0X?vh3*ib-agOiZqyI3&3b@j zx9>#JJ;;vD-x;SB*sRjYq{ zjp-X-C3U;yrsh0!;CD9jRtd3Y%h(l$#dN+V(x24gai6)6gPzrkG9TTkt1m3jBStVCXL&ZwtUndC)~sTFwuEsU zL@3JaaJK(Q-zpRjFAFKj8M{MT<)b_q4zXYUxChX=@^bbG4e~AMlbdT$MUQ_d;t4P> zpR?;I=@DiMN~y_g=KoOj1%zufb0W3;?il& zJT;IZeBksNfmz)(RsD)PD&y8eCrj)D4tLcMI+3KY9v7DhpZc7k9MYh>y3VKGt;Iv| zA!vC;(3JL;eDfRJsY3gzh$??Oci4S!cRhG?c{XY9d|zh0#i81-jLYgj*H`j;%^e9Eo++kX3ymIhlyJHJLxYW)ia zKP?Y>n-x2_PlXVISv^`E5!=IZJ0*;%dxN}2d^uG0ulbb>cTTYazci`=I+WEMl#3Kp zbW0-c6zvONG!;3@8O(nMwyN-iNDdZK4uuWys<97b5vo^3n|aAyR!8SU+ZmzuRcTu^ z2TXMF>P2im$9}TYTw&Bvs`uZ}q%+|!#Cr;`${q+ul8T2}8X{aYaf_+YwfEqY=1ly7ro`~!Sp{0bbQ0m15Z@DqzHtKZ* zj#*Gsyp~qB2^q!rKzpDg&Et#E{mF>+UF9?uI+~YsiF}^1q*gjTf7N=%w_+Y4$s@qp z_Vmlqi_}(f5InS%4#EWJJ^%y>GAKOx?g17FowW0j&7FVT;FdreKFBeB`A~?I8s~A$ z;Pskf$D;YwRzxfVV)<#++XMUn!Y6^{ z_Jv-dR; z98COcoTcTGaNT+LRCT1SswWhC_6NXFCjgmDcIv_J`8`ox*ecd)tX;8J-T zF3W$Ak%>;oQJa?sq(F{x*Dw31k*u`dyds~em}2~{aHGJ~Eq|?q*5xjG<*!n3v+n$Y zKk{Y~Rho;pxh`*>kf4o{812!1l-u_VuV=&ArAv7OC!El6xmnoaz+ohw;U9HWmoMeS zO08G5y?sV77u+;}(DJ$r_0TXnmCmBNq+`=}b*H@inwI)Rlu<_R?R#ZpWO4Rpfp0E4(uazhbuJ zsw-D~X#A0uF3tOugxyQ`JISDk$j^U6h=-rw^m08s9DgmZEd)n0JcX4U^Kbh^@0It2 zb5UkV6WN(5JRM`axdvJ%sa>|0-G~KuFZ7QuXzCZ2J!@3h2u{~Pl;VW-Ni@i|fYXlF z#BOt4oLFQNm>!aG!EhtcqYa7SvfDi&Gx+s5A_)SzaghlZ;nH~Gn@lNXPFsI=-L~~4 z)8-NBq{SjGQXori(ZM@(-G97(U4JRv4L!#p6C{PD3q@z|m+2F-?HfzVPcB(yC7p8* zVKaDijd%9e7YcnvFJFF)e`)S4o+A~ZU!ue=$&a0^Uc0}sMTwG%MO~`CU#Va_qYz^a z99j`9J%k9GSyk-bh7aDTb|!zSf;25@KjB4NYS!+_ZQJ+FB69kV`80)M1$VS zNy@{uEC3yS=0hs$LZ)zMusJu^X8K_U{MJy%xj|>n7dRP!mR0)J~<4xfu*WC2v&`L1JIw z&Mf%V@H1_87lU7N_&1&B_z=j@`HELV#wI)zV5+$tq&G%A;v^E?ok}msJeyhekVHhB zGbN?hhGrKMMS?f2WTT}4c-^Gm6ZnbOA`oRI97}Jw`lNqHT7e(5sSdM9VzFrMiG>#! zmlF|7ryF423?V@TFTBNVgm4)aC2pyTf?!(0V4ppZ!mlDdaKe>^7}a}Y5OYDo-;U%7 z$>7Ya?rWkR-Q4K`zG1=8_H%PY>-88}`^(6Vp$jORy@t9M-MI>6i zV;pB+7QycW$OJ^IyDq@x`a1;$NfTz+l7+rYZDYf0!GrrY&7wQtoca1zxQCPUQRIC? zRqZ@{eVkCB-^eo!Zd^Ktm5raDOc1LD)MA)no#1~MuR}q(j z6}B#-tjB7aXyK}o;jBx@msCwxJw)Vs|45M0p*lQ^!n`TFkC*v4YK$Dhpup6Pq8OS! z>;OH{(-`xqT;c~rjc5fIvT9Cm>^k#R@jlvhWgvN6Sq@5kLEs z-1I%Ar;~Z^0ZW^&yrLHBNCG*yR$*hJ+8}y_WvE^+ui$RVZT1TUruS7XCNd)u`|nAx zRq-)1sNHe)&K#yr$l8`y!rtwrP+x1Y8h)l5ZL^NdG8u;@c`fCiGLsS!f}9vFFsRbcUjmEz zvykJ-mNCkZ353v$xW-8FN7Z}X0H)-sXRrQRKH-}=6Bly<>vyY!gJEP`HsXYU51@Zi z@895^$-HsW;_l-^47P|0ZlUU9r|fLS8bo-yW+o%HYt}k*@Dv0U>`i$v^Bo*Q_2jUv zy4B8FH7?q8NxXAqBht;?L>ja8*HHDXik7^J9lMn9=hz>Tp1;Hn#!PB{Nu)(h&Ks0~CffZeb0)nwg#b#x&QS)z- zz}m+cCPQWrACm`xw48o)nkEk*J-IP7>Y+_sYE+7`gL-S8W1p0RCjV@Yn&f}}1_ka@ zib2vwCGHkKfmJ*QCt=IPgol|UB{{7}PCG)~&x58CYL|wijx=h8sYFcl1({qX^#@ii z%?QZWmYpt{8o1RkzC46fQmb`@m;IfqsW9u5=-`k6QJqRsG$@xNT<#&^3LK)WSNXN? z$ z0rIJ+ofxS|NRl^J+;%4^W|t;XQoN z&{|p1gj`EhPhNIz$PQ3N<5>u6LG@FmQ3xS#K}@onm zk7~&~=UBJuk#CNM(N9I0G<0Y~`gnH6FHahtPYGT8bYXYWes52*T?~GsIU?wuC(1sw zk>=6R>!=WRm1+aCR%)Yrm!I#ux{_b}bK>ZOYWzHa@ir9bR~g>aW(6AcG#@-5KsAaJ zlh|6FOZ*a&0sMcFtagKHa}uRnBYpf1))5NR5!+uZKW0usw^w+BIV2tH!RqN4Xlp3l z(f{O)!~4GQWPbzO{@MFg@h7Hd-v{c(XNGxJYE9CJwbs%S0)LN>U;8EHgf~Yy=Xj@` zWf)tBzhI_)2+5d*baoOJiem7eQmG!wi!gK zB!Z|AU@T##630?!WoPi(>M;jZE?W4dYfOe`(lX3 zomB{E{)_X!b#E*W+wXjASz2PRHQJN!qJ&SGC?2Q2gfrXJlw#J$bwFYkjW*|Jl#nEW z=;2FLRE!Iyn}bfskp#mk?_KPqG12o?GHcKsRQZ3SQoLnJAS(>?2&lH(c5v3|u5On@ zLUr~v>DcD1^zxYaHr{4nHdfV;65xc&3!*)uA+S>y&tm#?zZK(O_QYKt(b^fIZ<#Dg z2AJQ#7oP|Fhs>v7(Waq>SX3FJ>FkC}u@??D+1r^~7JdewC6sMoHY#BrtMC^7f_OR4BOm@$fu0mh!HoV z%{FLPnP@VVF4P5t#4|uiob*H1!tTB$eAV zu(hB1nRBw&(T4V5Z>KSg$s6+b@+#I{^ekh#<`^Z=}T4T_!BPbeP-eGGkSoWAjbwPpp+tworYFmg-ZPn8A$c z(~O>sXQ+(6^l^8+qbTYk5Q=|SUyDphSv%0PbprJ2m!1*(s#{Imn_W&gwBkda{x5Gdlwscb-^z3Wp_up39u)L5-&!J^L?E8;9AP_a%_M90u=mmbGI%u zDYmH>Gx59#m(uqw9b_H^+hD(xXDqt(oky)zjX=>vZ0*Vqgj-hp2fwJjDc(c=`jpyI_n z+kBfTtH{*_B1Gyd7t()H%Ft8?d&LE3z@P=nHmUYu3Z+TQIrEMh{rD4;@ovmbfxOo9SXK)tI#Jl<5?ukEv;Jw$zp4?iE!tVqOclNQVfraa=^rVs-u5v>cU4g}$BsUSIPl$g8=0*?J!TE&H2hx67 zoJT#2S3F{hUwCYywchbIc$N(b=cA1Yp+hQEOBY)R=j1Sd+_o{xD77gatdR^~{P6%b zmh!Aa%E2EJs95K$)0H8-!Ga%u;NxhV-x|NOBad=IW=r~_m_3wp;<10#6H@x4B5V>L zx@i3gRz|i+@1uVgPX&QdHe&`SeURp@rCg?AstB%{)@1>h{&ee z1@h&{@==-5S*sVK?iqq|z(YNJb(AA{h7Vm};Hr7AtDb)%Qa<`fdEQl09zul~BC}zo z8LM;#0|d;qRvj1j!qqG+EWpMtK{a~}#+#MVQpVaL=0I;mLy(Ciz;_vOuM7;X zRe8RvLjdiLUr2iiV`*f@cHIpb1l9SL#{vmOIW0bADZ6G-_i_&(UMF)1E0rRmj@I)s zWME58i(G7GwaH53mD&Xjok9`>yyK(x}lD{ah>#+lh&^v zb(X-E4Ymqmq1w!#fIM4S7z_6oD#>OO+0J^wgUD%!Q|t)UHv$ zXUKo#dSz65pfDpyut9RPJ1U>2;?R^T##D9{@OjnIR1-Im~kUsW%e>T%&-N*10 zn)j6z3$G@XxJ~ZtrBrL9Wtw5Bqa-~59o*y9LJC<*@m6tzuvsQc6xq|KagB1D*|Rphv}-o>scJ|9 zV4958T=opS{|OMS4$dZ+b>O>aoP69Qyx?pqVYSfpOI1;tW1T)>PvF-$g3f>4-*C{- zNLjp5BX&Ab;Y99EB`^)I)nndxMk|xik`XRwHHcoG;{9X*7RKPP@GF7y^DiMBiu|c0 zUol+RI-?i!?x~@6UBoJ>Y+j~)5=ZV<(!5X7WsusfUY7(&zRVShkFIsv5P`0Szxf_7 zHk*VfX)}qoK0G~ucV_QXCdhx;Ed!}lxh=^mMiV<@0GMa0K#Huzk}(2mq=%Nh>U^B8 zAm#I_p^C4!q`5mVoHXtTnV5{+vW|8_LqM+%^r=8FQU*lwCYuFv&Ytf}+vJ7vDB@4_ z2%@I$=z3&i;a!(Z7BD?G+)+~{ppu)wvD7_9X!!<3hfOu&pSM=O9VCCdzOGRR4G4DX zn#fq78d~kMCr&6GpXanfr~4C>R3FBsz^ZGqFamsLCl!r5fTw6EsWnJBwxdyRhZ zx(c(|tIVsX2C-uwCeNM@(xS>rI~Wa7qeKgrP#>AItQiHZuz0;aL`|;*C$`5{SV|2E zg~d7{>iC@q0m5FAwFn8|c~q9Mhg+=69aJ?H?zq+a@7LPfS5r$2Y{ z#KB`cW0oO^vccOR%;DP5JANZ?@Y$ro34+|%#=H30Axc@p@GBOS`kC{~1pNTP^s>`k zgMlQS!|yZ9oLggMJ(}GHX1=B_kz%uX7gnhzVPYJmD~-`KitK;J0)KvkY06qy!$aLS z{W>Z{gZpQ0@y{qnhKFR4!Zb)*HiFJP7+OO^Etdponq6KjRs1|6vJnjru zNmi@B@!!s;`0szBKHD#UB>5)8i)NCScNVW94DaM8dAVZ>#%e``2#!N}yp`Cu)3Kbt zZlE?$hD#JqiZh#Nwi3&Lv5EdgkU{a6g+m!HX2+K=Gu{1P{56GlQ$3G136m}VO^(189prJN;zz{wTVK$FRpv&qJl@->AgG{1QS zfy+jS9f43IZlsQ`G<^vghZ^mhz@g1aUCafPH;%jDX@7CjX~RwVFFp~ujqAGuVZp`5 z^Oj_fTx5Tgnbbz>O1mFhA60G&IAT7)1)th5*&J;qeWlD*6J=UPo_3$L3l&EV`zr5V zf-3Fvw5}mR0r4FbF8b!nwUkm^fjG-E?u#fRTFtrW=OT@++U(zVFdvO}&LOF;h!ncs z6a}(1(;^S+fWuJOW^giS-y+M zG!(qHbHpXfmlD`uJr)BIkInNm_hC87!t>XZXvR^R%J2l+18ROLyMSwKm5e28nw1{_HRV zM0J0HOBK3)1t|$8%tS;-E=w0=xoa|IEg6XsG2w71pXJ3sITYAcdKwBkb6VCUxt7=T zX8UJlXJ44(sFfgGXcp)if2dr{GCs>*_&M4Ub)eF) zNQc>87?O|-0duC;4{>X_b^Lv0U_s!Psmzy#h6zp&7_2O5O4fzO%l@b$2HEuq9kWz~ z==@b)aFGI^$JpO#VYB%NZ_qp6r{ADzyVT4O^Ao0heG!aMMhh$FwV$V&I=p``QfkMW zxIPcYRE)|M)sw2!+i6Kqr>s!hd4D-1eT#~Der%oL23{C;%dTL!2e5All4}%d?$H^1 zFJ=Ew1oAzpk%Z*{p#P+;esOS1g^4HLrFQVC62AI=x8DcO@y?c?X{LoIQi*Ga(R7asPhugmR;3E8K{JoKkveqrE5vh1aoXru>JNG}98 zY-ehMCzw)S2^>BBQJ3gbl;Kp%Ji&Qn#;6~TqnA@~$xxiIK?3x&)8at5x#rWJFkH2>r;3QdQ0S=07oo(w1Bo&?pIL)eJU#3|_EZ%=H&K7ynFJ55A$U&t-&8al! zA&=xdpfV-p6OBV(UV4Hd6@^|8a7a+)B4kE%B4-f>CuNa7WHrp_7}rC<$Lytsxl5l3 zYr_bnl%a&i){MRTYcjg4^{cWX6z$r0EH%Zlh*+%fUL(U8OvFM1Mhl0CRA@a;8d3|I zJ4BOhgob~Zn>OD1d~RD^8keE9^ECAx&Rql(2YUL9Yh*|0xz%ZbFQ$|V)rl>cvyX_j zfsI!jYec@K4d#e$5HjW@MaI5f6p_qsv=QL#c`(zO+9W;3pS`sy%0X)GPG@!Nl{|J8 zz1J{v@Wk3RzRf(K8-%jbY14jHmYBQINK%vMoo9dS-r99mrDeXWi?Vrp_sNDLUk2Zv zMw3s2asQb!3apc51*$>x{foZP1}=oV6mFEe4tmd5RqEcei3vGKcB3p`u4o&X03D5s zU2qrtTqo;1z1l9<8BqC$I@>%^A&NY=NpwF{W0jQdseix(Q_OIQE6njHu5pV6?y$rP zYutb1uaC{ihB?*atou8?CG_TYJh>l{(CNQ)D%R>`EPg|$e3woWcVtT5m3f6XIKo@J z!!b_r!OKpI%_hMG$^X%5z~-z4FDES!e{TVuVE?`LTjwO|eo|$A;=H=?la9G5=_lGS zFRR*}m&Ry-cS*b9oHTvS7yG(u(Z*l*@1##RDsa<1zw+*7iy-c@1$}YByFFuf2JTf? zQrde~T=Yy${j=pK9G#|z>NKl8wV3jsq3M6i%gLLwa{`PFogB?v4V;Z!oD9reObv|< zObyH(9W4xiLXNI(CUy!o1eL_Xw}P7)OwP}-_btBUn8T-##*~!iwyavgj(hRJ7=g1~ zN9Oe0Jjv7Z^DGa;(n+kBxKi^{ic5-86LUeV{G=?d;*!Lol8U0#G%h0xQxkJ8RaIAi GH!cA543_u+ diff --git a/swarm/docs/smash/fig/response-types.tex b/swarm/docs/smash/fig/response-types.tex index 19248cb22598..f89a76cafb78 100644 --- a/swarm/docs/smash/fig/response-types.tex +++ b/swarm/docs/smash/fig/response-types.tex @@ -8,7 +8,7 @@ \begin{tabular}{|l|l|l|l|} \hline \textbf{challenge} & \textbf{input} & \textbf{storer knows} & \textbf{response} \\ \hline \hline - MERKLE & smash chunk hash, segment index & & Merkle proof \\ \cline{1-1} \cline {4-4} + Merkle proof & smash chunk hash, segment index & & Merkle proof \\ \cline{1-1} \cline {4-4} ASH & smash chunk hash, seed & & audit secret hash \\ \cline{1-1} \cline {4-4} ASH proof & & & chunk segment, ASH proof \\ \hline MASH proof & smash chunk hash, seed, & mask ok & audit secret hash, MASH proof \\ \cline{3-4} diff --git a/swarm/docs/smash/smash.rst b/swarm/docs/smash/smash.rst index ed842a644a07..739c4015b06e 100644 --- a/swarm/docs/smash/smash.rst +++ b/swarm/docs/smash/smash.rst @@ -1,10 +1,14 @@ -.. ********************************************** -.. SMASH: secured by masked audit secret hash -.. ********************************************** -.. raw:: latex - \enlargethispage{-.4\pageheight} - \newpage +.. topic:: Abstract + + This paper [#]_ is the result of our research into securing decentralised storage and distribution in the context of implementing an incentive layer for swarm. + + Swarm is a distributed storage platform and content distribution service, a native base layer service of the Ethereum web 3 stack. The goal is a peer-to-peer serverless hosting, storage and serving solution that is DDOS-resistant, has zero-downtime, is fault-tolerant and censorship-resistant as well as self-sustaining due to a built-in incentive system. + + Users of swarm need make sure their content is preserved, even when it is rarely accessed. This kind of ensured archival necessitate integrity audits of documents and data collections without transferring the data itself. We present a family of proofs of custody that has properties ideal to serve these needs and allows flexible trade-offs in terms of compactness, repeatability, third party provability and outsourceability for the various scenarios in which audits are used. + +.. rubric:: Footnotes +.. [#] The authors are indebted to Gavin Wood, Vitalik Buterin and Jeffrey Wilcke for their daring vision of the next generation internet and for their original concepts of web 3 and swarm. We thank Vitalik Buterin, Nick Johnson, Daniel Varga for their comments and suggestions. Their names here by no means imply endorsement. All errors are ours. Introduction @@ -13,7 +17,7 @@ Introduction Proof of custody [#]_ is a construct that proves to an auditor that a storer has custody of data without the auditor having it. Such constructs can be used to audit the integrity of remotely stored documents trustlessly. In the context of a distributed file storage system, proof of custody schemes need to consider both storage and network communication overhead and offer flexible trade-offs between security and cost. .. rubric:: Footnotes -.. [#] profof of existence, proof of storage, proof of resource, proof of retrievability +.. [#] In place of custody, the terms existence, storage, resource, retrievability, integtity are often used in the literature. We see no semantic importance as to this choice of wording, but for consistency, will use custody. In the specific context of swarm, we need to make sure we have a scheme that best adapts to @@ -26,7 +30,7 @@ In the specific context of swarm, we need to make sure we have a scheme that bes * existing escalation to retributive measures: litigation on the ethereum blockchain -The proof of custody scheme proposed here draws on earlier work based on well understood basic cryptography (:cite:`shacham2013compact`, :cite:`bowers2009proofs`), but in light of the above considerations a novel approach was warranted. In what follows we spell out a proof of custody scheme and present audit schemes that use variants of the scheme depending on +The proof of custody scheme proposed here draws on earlier work based on well understood basic cryptography (:cite:`shacham2013compact`, :cite:`bowers2009proofs`), but in light of the above considerations a novel approach was warranted (inspired by :cite:`wilkinsonetal2014storj` and :cite:`buterin2014erasure`). Auditing chunks with pregenerated secrets ============================================ @@ -36,7 +40,7 @@ In this section we introduce the concept of audit by challenge and formally defi Audit by challenge and response -------------------------------------- -Auditing a particular chunk :math:`\chunk` is done via a :dfn:`challenge`. Who initiates this audit and how the challenge reaches the storer of the chunk is discussed in detail later. +Auditing a particular chunk :math:`\chunk` of data is done via a :dfn:`challenge`. Who initiates this audit and how the challenge reaches the storer of the chunk is discussed in detail later. To generate a challenge the original :dfn:`owner` only needs to reveal a :dfn:`seed`. Once the storer learns the seed for the challenge, they can use this seed to find the corresponding :dfn:`secret` by a procedure defined below which requires them to have the data. The secret itself is the response to the challenge in its simplest form. @@ -45,7 +49,7 @@ If the secret is not prematurely revealed by the original owner, the storers mus If the storer keeps the data they will always know that they will always be able to calculate a correct response. If a storer chooses not to preserve the data, it is impossible to be 100% sure that they give the right secret to a challange. Given these properties it is valid to say that *responding to a challenge with a valid secret can be considered a reliable positive proof of current custody*. -The auditors do not need to know the secret only be able to check that it is correct. This is achieved by :dfn:`masking` the secret by hashing it and make the mask public (:cite:`wilkinsonetal2014storj`). Thus the original owner publishes a hash of the secret and any third party auditor can verify that the secret the storer publishes in response to a challenge has the correct hash. Since unhashing is cryptogaphically impossible, verifying that the secret hashes to the mask is equivalent to checking the secret itself. +Whoever initiates an audit need not know the secret only be able to check that it is correct. This is achieved by :dfn:`masking` the secret by hashing it and make the mask public (:cite:`wilkinsonetal2014storj`). Thus the original owner publishes a hash of the secret and any third party can verify that the secret the storer provides in response to a challenge has the correct hash. Since unhashing is cryptogaphically impossible, verifying that the secret hashes to the mask is equivalent to checking the secret itself. If audits are to be repeated, several secrets and their corresponding masks need to be pregenerated by the owner. However not all masks need to be remembered in order for any third party to verify that the secret provided is correct. Instead the pregenerated masks can be organised in a :dfn:`Merkle tree` (:cite:`merkle1980protocols`) and the correctness of a mask can be proven by a :dfn:`Merkle proof` of the mask as long as the root hash of the Merkle tree is known and trusted. In other words the owner can pregenerate any number of audits secrets and outsource the storage of the mask to the storer allowing storer-side proofs of the secrets' validity. In the remainder of this section we formalise this approach. In the context of swarm and the discussion in this paper we use the following terminology: @@ -57,7 +61,7 @@ In the remainder of this section we formalise this approach. In the context of s node that accepted a store request and stores the content :dfn:`guardian` - the first node to accept a store request of a chunk/ + the first node to accept a store request of a chunk :dfn:`custodian` node that has no online peer that is closer to a chunk address @@ -85,7 +89,7 @@ In other words, the last :math:`\depth` bits of the seed map to :math:`j`. So given a chunk :math:`{\chunk}`, a seed :math:`{\seed}`, we construct the secret the following way. -1. First we make sure all chunks have lengths that are powers of 2 padding shorter chunks as necessary. If chunk :math:`{\minichunk}` is shorter than the predefined maximum chunk size (:math:`\MaxChunkSize=2^m`) then we append to it some padding to make the length of resulting data blob (:math:`{\Pad}({\minichunk})`) the smallest power of 2. In particular appending hashes until the length exceeds the first power of two and then finally we truncate [#]_ . +1. First we make sure all chunks have lengths that are powers of 2 padding shorter chunks as necessary. If chunk :math:`{\minichunk}` is shorter than the predefined maximum chunk size (:math:`\MaxChunkSize=2^m`) then we append to it some padding to make the length of resulting data blob (:math:`{\Pad}({\minichunk})`) the smallest power of 2 :math:`m^{\prime}` such that :math:`2^{m^{\prime}}>n`. In particular appending hashes until the length exceeds the first power of two and then finally we truncate [#]_ . .. rubric:: Footnotes .. [#] :math:`\concat` stands for concatenation, and the notation :math:`x[i:j]` stands for the byteslice :math:`x[i]\concat x[1]\concat \dotsb \concat x[j-1]` where :math:`x[i]` is the :math:`i^\mathrm{th}` byte of :math:`x`. :math:`\Hash` stands for a hash function of choice. To help readability, the variable :math:`\chunk` always stands for a chunk of data, :math:`\segment` for a segment of a chunk, :math:`\level` for levels of Merkle trees, :math:`\seed` for seed. @@ -99,16 +103,16 @@ So given a chunk :math:`{\chunk}`, a seed :math:`{\seed}`, we construct the secr Then we define the padded chunk as .. math:: - \Pad(\minichunk) \defeq \Pad(\minichunk, \seed, i)[0:\MaxChunkSize] + \Pad(\minichunk) \defeq \Pad(\minichunk, \seed, i)[0:2^{m^{\prime}}] where :math:`i` is chosen as the smallest index such that .. math:: - \Length{(\minichunk)} + i\cdot \HashSize >= \MaxChunkSize + \Length{(\minichunk)} + i\cdot \HashSize >= m^{\prime} -With this padding process defined, we will from now on assume that all chunks are of size :math:`\MaxChunkSize` when we refer to them in the context of audit. +With this padding process defined, we will from now on assume that all chunks have a length that is a power of 2, therefore the next step is well defined. -2. Chop the chunk into hash sized segments. Assume for convenience that hash size is a power of two: :math:`{\HashSize}= 2^h` and :math:`h < m`, then :math:`\chunk` is a concatenation of :math:`n` segments: +2. Chop the chunk into hash sized segments. Assume for convenience that hash size is a power of two: :math:`{\HashSize}= 2^h` and :math:`h < m`, then :math:`\chunk` is a concatenation of :math:`n` segments (for padded shorter chunks :math:`m < \MaxChunkSize`): .. math:: \chunk = \segment_0\concat \segment_1\concat \dots\concat \segment_{n-1} \mathrm{\ where\ } @@ -229,7 +233,7 @@ and Given a chunk hash, a seed, and the index, the audit secret hash for :math:`{\ASH(\chunk, \seed, j)}` can be calculated and verified using only the Merkle proof for the segment at the index. The left hand side is the Merkle structure of the original segmented chunk, the right hand side represents the corresponding Merkle proof for the audit secret. -If an auditor maliciously published a false ASH, then a storer would find that the ASH they calculated does not match the published one. In this case it is important that the storer can prove that they are innocent - that it is the published ASH that is fraudulent. The Merkle proof of the segmented chunk (:numref:`Figure %s `) proves that they really are storing the chunk and the corresponding ASH proof proves that the ASH they calculated is the correct one. +If an auditor maliciously published a false ASH, then a storer would find that the ASH they calculated does not match the published one. In this case it is important that the storer can prove that they are innocent - that it is the published ASH that is fraudulent. The Merkle proof of the segmented chunk (:numref:`Figure %s `) proves that they really are storing the chunk and the corresponding Merkle proof proves that the ASH they calculated is the correct one. Masked audit secret hash (MASH) tree @@ -301,7 +305,7 @@ This type is expected to be used very rarely, since the only way they come about .. figure:: fig/response-types.pdf - Challenges and responses: types of challenges, their input and the response storers can give. The first three types of challenge make no claim as to whether the auditor knows the secret. The MASH proof challenge presupposes the storer knows the mask. The storer always responds with the MASH proof, if they find that the mask matches they also include the audit secret hash in their response, otherwise they submit an ASH proof (from which the audit secret can be derived). + Challenges and responses: types of challenges, their input and the response storers can give. The first three types of challenge make no claim as to whether the auditor knows the secret. The MASH proof challenge presupposes the storer knows the mask. The storer always responds with the MASH proof, if they find that the mask matches they also include the audit secret hash in their response, otherwise they submit the relevant Merkle proof (from which the ASH can be derived). @@ -387,7 +391,7 @@ The resulting ordered set of chunks will be used to define the collection-level 1. Let :math:`M` be the manifest of a document collection and :math:`\Complement(M) = \{\chunk_0, \chunk_1, \dots\chunk_n\}` be the set of unique chunks such that :math:`\chunk_i<\chunk_j` for all :math:`0 \leq i < j \leq n`. The last chunk :math:`\chunk_n` is the root chunk of the manifest. 2. Let :math:`\seed` be the seed for :math:`M`. -3. Define the audit secret hash function for :math:`M` and and index as +3. Define the CRASH function for :math:`M` at index :math:`i` as .. math:: \CRASH(M, \seed, i) \defeq \begin{cases} @@ -400,23 +404,26 @@ The resulting ordered set of chunks will be used to define the collection-level .. math:: \CRASH(M, \seed) \defeq \CRASH(M, \seed, n) -In practice given a collection the owner wants to store, the secrets can be efficiently generated at the time the files are chunked. As the chunks are uploaded, and guardian addresses and their receipts are stored in a structure parallel to the chunktree anyway. +In practice given a collection the owner wants to store, the secrets can be efficiently generated at the time the files are chunked. As the chunks are uploaded, and guardian addresses and their receipts are stored in a structure parallel to the chunk tree anyway. This pattern can be applied to document collections covering entire sites or filesystem directories and therefore scales very well. Given the swarm parameters of :math:`m=12, h=5`, for a TTL requiring repeatability order :math:`r` (for :math:`2^r` independent audits without ever seeing the files again), the minimum data size to achieve a desired maximum storage overhead ratio :math:`k` is :math:`k\cdot 2^{r+5}` -Setting `r=128`, so the masks fit into one chunk, a 20-chunk file (80KB) would allow :math:`128` independent audits with a 5% storage overhead. +Setting `r=128`, so the masks fit into one chunk, a 20-chunk file (80KB) would allow :math:`128` independent audits with a 5% storage overhead [#]_ . + +.. rubric:: Footnotes +.. [#] If the audit frequencies are dependent of the TTL of chunks only, this scheme will provide a guarantees about the proportion of chunks that are expected lost over any given period of time. With the chunksize (hash and branching parameter) fixed, linear increase of resoures provide exponentially more reliability on the individual chunks. If the requirement is full integrity of an entire collection, the frequency of audits need to be adjusted to make up for the (likewise) exponential loss of reliability in the number of chunk tree nodes (i.e., size of the collection). This loss is the consequence of fixing the degree of redundancy as well as the size of the unit that encodes it (see :cite:`ethersphere2016sw3`). We are curerntly looking at the intricate interplay between integrity audits and redundant encoding and how it can be used in a :dfn:`divide and conquer` approach to the scaling of erasure codes. -This audit will not reveal the actual secret to the individual storers of chunks, therefore it can never be used to prove to third parties that a challenge is invalid. For the same reason it is not used for public litigation. +This audit will not reveal the actual secret to the individual storers of chunks, therefore it can never be used to prove to third parties that a fix limit challenge is invalid. For the same reason it is not used for public litigation. If we know nothing about the individual secrets used in the recursive formula, and we use ASH challenges to obtain :math:`\CRASH(M, \seed, i)`, the correctness of the secret is only verifiable after we calculate the final :math:`\CRASH(M, \seed)` and check it against the mask. If it does not match, we have no way of identifying at what index the error occurred. Requiring ASH proofs directly at every index, on the other hand, would incur an order of magnitude more network traffic. However, a reasonable middle ground is possible. The insight here is that we can use partial verification on the individual secrets. When auditing, every time a new ASH secret is given, :math:`\error` bits of the secret are checked. -If a mismatch is encountered, the audit enters into a second pass backtrack mode and actual ASH proofs are obtained from the nodes. +If a mismatch is encountered, the audit enters into a second pass backtrack mode and actual Merkle proofs are obtained from the nodes. Note that the audit secret hash from one chunk determines the seed for the next chunk's audit. Since an incorrect secret yields a new random seed and thus a new subsequent secret, and since secrets thus obtained have a uniform distribution, newly introduced errors can generate false positives on average 1 in :math:`2^\error` times. -As a result, the probability that any error remains undetected for :math:`n` steps is less than :math:`2^{-n\cdot \error}`. This property makes it efficient to follow a simple backtracking strategy: when a mismatch is encountered on :math:`\CRASH(M, \seed, i)`, proceed by requiring ASH proofs for past chunks in order of their recency, i.e., :math:`\chunk_i, \chunk_{i-1}, \chunk_{i-2}, \dots`. +As a result, the probability that any error remains undetected for :math:`n` steps is less than :math:`2^{-n\cdot \error}`. This property makes it efficient to follow a simple backtracking strategy: when a mismatch is encountered on :math:`\CRASH(M, \seed, i)`, proceed by requiring Merkle proofs for past chunks in order of their recency, i.e., :math:`\chunk_i, \chunk_{i-1}, \chunk_{i-2}, \dots`. This is all based on the premise that the bits the errors are checked against are precalculated and stored. This creates an extra overhead of :math:`\error` bits per chunk, modifying our minimum datasize requisite to :math:`k\cdot(2^{r+\error+8})` bits. @@ -448,40 +455,44 @@ Optimising the storage for owners to originate audits it is important that a ser These transparently indexed seeds are used to generate masks to submit together with the store request for a chunk. For entire collections, we use the transparently indexed seeds of the root chunk of the collection manifest [#]_ . .. rubric:: Footnotes -.. [#] It is rather unlikely that we ever need so high :math:`r` values that the security of the secret against bruteforcing is compromised. +.. [#] It is rather unlikely that we ever need so high :math:`r` values that the security of the secret against bruteforcing is compromised. This indexing scheme allows owners to generate a seed needed for an audit for any chunk without having any information whatsoever. In order to generate a seed in range though, they need to know the repeatability order of a chunk. We will most likely assume that :math:`r` is the logarithm of the TTL of an insured chunk [#]_ . .. rubric:: Footnotes -.. [#] The base of this log would set the clock tick for automated audits, making it a system constant will allow predictable audit traffic estimates given the size of the swarm. +.. [#] The base of this log would set the clock tick for automated audits, making it a system constant will allow predictable audit traffic estimates given the size of the swarm. Incidentally, this allows the owner to calculate the index of the previous seed used for the collection from the current time and time of the receipt, so repeated audits with the same seed can be avoided without the need to keep a cursor. Non-automated audits on chunks are expected to occur infrequently and since they count as anomalies, they are likely to be recorded for reasons of reputation etc. -SWINDLE -======================= +CRASH-proof auditing and litigation +========================================= + +In this section we define an incentive compatible auditing and litigation process that is encoded in the swarm protocol [#]_ . It relies on CRASH/SMASH challenges for proof of custody for integrity checking which also serve as evidence sent to the blockchain when initiating public litigation. + -SWINDLE (SWarm INsurance Driven Litigation Engine) is the part of the bzz protocol that handles the logic and communications relating to auditing and litigation. It relies on crash/smash challenges for proof of custody integrity checking and also serves as evidence sent to the blockchain for public litigation. +.. rubric:: Footnotes +.. [#] SWINDLE (SWarm INsurance Driven Litigation Engine) is the part of the bzz protocol that handles the logic and communications relating to auditing and litigation as well as the corresponding smart contract on the blockchain that handles the particular court procedure. Prerequisites for insured storage -------------------------------------------------- -Suppose an owner of a chunk wishes to have it stored and insured. The owner communicates directly with a registered peer who will act as :dfn:`guardian` of this insured chunk. When a store request for an insured chunk is sent from the owner to the guardian, the owner must include the smash chunk hash, as well as the MASH root and sign it together with the swarm hash of the chunk. The smash chunk hash is needed to verify positive ASH proofs, while the MASH root is needed to verify MASH proofs. Both are needed in order to provide negative proofs against an auditor sending frivolous audit requests. +Suppose an owner of a chunk wishes to have it stored and insured. The owner communicates directly with a registered peer who will act as :dfn:`guardian` of this insured chunk. When a store request for an insured chunk is sent from the owner to the guardian, the owner must include the smash chunk hash [#]_ , as well as the MASH root and sign it together with the swarm hash of the chunk. The smash chunk hash is needed to verify Merkle proofs, while the MASH root is needed to verify MASH proofs. Both are needed in order to provide negative proofs against an auditor sending frivolous audit requests. -Remember, the "swarm hash" used to identify a chunk in the swarm is simply its hash, while the "smash chunk hash" from the ASH proofs is the Merkle root of a binary tree that treats the chunk as :math:`n` segments of size :math:`2^h` (in our case 128 segments of 32 bytes). Both are calculated directly from the chunk itself but they are distinct and serve different purposes. -The question arises why we do not combine these two. In particular, we could simply use the smash chunk hash (the root of the binary Merkle tree over 32 byte sequences) instead of the simple swarm hash in the swarm chunker. This would have the benefit that smash chunk hashes would not need to be stored separately as part of the audit metadata. However, the smash chunk hash involves 255 hashing operations as opposed to the single one of the swarm hash, therefore, extensive benchmarks are needed before we pursue this option. +.. rubric:: Footnotes +.. [#] Remember, the "swarm hash" used to identify a chunk in the swarm is simply its hash, while the "smash chunk hash" from the Merkle proofs is the Merkle root of a binary tree that treats the chunk as :math:`n` segments of size :math:`2^h` (in our case 128 segments of 32 bytes). Both are calculated directly from the chunk itself but they are distinct and serve different purposes. The question arises why we do not combine these two. In particular, we could simply use the smash chunk hash (the root of the binary Merkle tree over 32 byte sequences) instead of the simple swarm hash in the swarm chunker. This would have the benefit that smash chunk hashes would not need to be stored separately as part of the audit metadata. However, the smash chunk hash involves 255 hashing operations as opposed to the single one of the swarm hash, therefore, extensive benchmarks are needed before we pursue this option. -When the store request is accepted by the guardian, they provide the owner with a receipt consisting of the store request signed by the author and counter-signed by the guardian. SWINDLE uses a court-case like system of public litigation on the blockchain, so the signatures are important in order for smart contracts to verify if a challenge is valid. +When the store request is accepted by the guardian, they provide the owner with a receipt consisting of the store request signed by the author and counter-signed by the guardian. We use a court-case like system of public litigation on the blockchain, so the signatures are important in order for smart contracts to verify if a challenge is valid. After the owner generates the MASH tree, calculated and remembered all verification bits and uniqueness bits, they have two options. One is to remember the data and store it along with the chunk hash. This allows them to launch and verify simple audit requests which are responded to by the relevant audit secret hash (ASH) value, and check that the hash of the ASH matches the entry in the MASH tree. The other option is not to store the MASH tree, but only to remember the MASH root. They would send off the masked audit secret hashes along with the store request. This enables owners to obtain proofs of custody without having any parts of the data whatsoever beyond the chunk hash, the MASH root and the signature of the receipt. -Even though querying a particular chunk is allowed and can be done manually, the automated audit and litigation process of SWINDLE start with audits on document collections and/or files instead. +Even though querying a particular chunk is allowed and can be done manually, the automated audit and litigation process launches audits on document collections and/or files instead. Document- or collection-level auditing and litigation -------------------------------------------------------------------- It is expected that auditing should happen not at the chunk-by-chunk level, but at a file or file-collection level that is semantic for the end users. The basic process for this is the following. -- The owner identifies a batch of chunks (document or collection of documents that contains files to be retrieved at similar very low frequences and stored for the same period) to store. The owner submits store requests for each chunk and collects receipts from the respective guardians. +- The owner identifies a batch of chunks (document or collection of documents that contains files to be retrieved at similar very low frequencies and stored for the same period) to store. The owner submits store requests for each chunk and collects receipts from the respective guardians. - The owner stores all the guardians' receipts in a parallel structure. @@ -494,21 +505,21 @@ It is expected that auditing should happen not at the chunk-by-chunk level, but - The owner calculates all the smash chunk hashes belonging to the chunks and records them in a parallel structure. -- Finally, the owner records a :dfn:`uniqueness bit` for each chunk. Since it it possible that the same chunk appears multiple times in a document collection, and since we want to avoid uneccessary repeated audits for such chunks, we must store one extra bit of information - this is the uniqueness bit belonging to each chunk in the collection. +- Finally, the owner records a :dfn:`uniqueness bit` (a boolean flag) for each chunk. Since it it possible that the same chunk appears multiple times in a document collection, and since we want to avoid uneccessary repeated audits for such chunks, we must store one extra bit of information - this is the uniqueness bit belonging to each chunk in the collection. - Once all these have been assembled, the owner can put them in a manifest. Let us assume that all chunks have been stored and the owner obtained a receipt for each from the respective guardians. Once a document collection is assembled, the manifest describing the collection is created. This :dfn:`collection audit manifest` will contain all the metadata needed for auditing and litigation, notably: 1. the guardian receipts of all the unique chunks, 2. the smash chunk hashes of all the unique chunks, - 3. the uniquness bits of all the chunk tree nodes, + 3. the uniqueness bits of all the chunk tree nodes, 4. the partial verification bits (the last two bits of the expected intermediate secrets) and 5. the MASH-es. -This audit manifest is a special structure that is sold to insurers who are obligated to store the metadata and be prepared to receive seeds from the owner at any time to initiate audit requests on the owners behalf. Alternatively insurers can take on the entire task of issuing seeds [#]_ . +This audit manifest is a special structure that is sold to insurers who are obligated to store the metadata and be prepared to receive seeds from the owner at any time to initiate audit requests on the owners behalf. Alternatively insurers can take on the entire task of issueing seeds [#]_ (and therefore generating all the metadata). .. rubric:: Footnotes -.. [#] This can be done trustlessly if insurer generates masks for the seeds themselves and publishes them (put it on the blockchain, or just publishes their own valid receipt). If the seed is leaked before it is due, or not relealed when it is due, the insurer stands to lose their deposit and compensate the owner. To catch the insurer caching results on their own beforehand, they need to collect signed audit responses from all nodes to show the nodes have seen the seed. Nodes are rewarded of they report leaked seeds. Therefore the auditor can cheat the audit only if they collude with the custodians of each chunk in the collection in advance, and precalculate their secrets. By keeping the reward for leaking significantly higher than what the insurer can afford as bribe will make this line of attack uneconomical. +.. [#] This can be done trustlessly if the insurer generates masks for the seeds themselves and publishes them (put it on the blockchain, or just publishes their own valid receipt). If the seed is leaked before it is due, or not revealed when it is due, the insurer stands to lose their deposit and compensate the owner. To catch the insurer caching results on their own beforehand, they need to collect signed audit responses from all nodes to show the nodes have seen the seed. Nodes are rewarded if they report leaked seeds or incorrect MASH-es. Therefore the auditor can cheat the audit only if they collude with the custodians of each chunk in the collection in advance, and precalculate their secrets. By keeping the reward for leaking significantly higher than what the insurer can afford as bribe will make this line of attack uneconomical. The :dfn:`audit request` for the document or collection is a tuple consisting of @@ -524,7 +535,7 @@ Audit request are sent out to the swarm, addressed by the swarm root hash of the Auditing an entire document collection requires audits of many chunks but the main auditor launches an audit of the first chunk only. Once the audit is thus initiated by the main auditor it proceeds automatically until it is complete or an error is found. -If any of the metadata is not available at the time of the audit, the main auditor will not be able to conduct a proper audit and therefore they cannot respond to owner. If this happens, the owner can escalate and start litigtion against them by sending the audit request in a transaction to the blockchain. +If any of the metadata is not available at the time of the audit, the main auditor will not be able to conduct a proper audit and therefore they cannot respond to the owner. If this happens, the owner can escalate the issue and start litigation against them by sending the audit request in a transaction to the blockchain. **Initiating the automated audit process:** @@ -536,7 +547,7 @@ If any of the metadata is not available at the time of the audit, the main audit 4. If all the data checks out, the main auditor then sends out the audit request to the top chunk (hashing to the collection swarm root hash) of the collection. -Recall that a chunk encodes a subtree, in particular a non-leaf chunk consists of 128 swarm hash segments. These are the hashes of chunks on the lower level of the chunk tree, each in turn encoding their subtree. In the initial round (and the only one in case of success) the audit involves sending out audit requests of the simple type. These requests are similar to retrieval requests except that in their response, proximate storers do not send back the chunk itself but instead they calculate the audit secret hash (ASH) and respond with that. Thus during simple audit, audit requests are broadcast from a node to its peers in the swarm and the swarm collectively forwards them all the way to storer nodes (i.e. the peers most proximate to chunk address). Responses travel back to parent auditors the same way (see :numref:`Figure %s `). +Recall that a chunk encodes a subtree, in particular a non-leaf chunk consists of 128 swarm hash segments. These are the hashes of chunks on the lower level of the chunk tree, each in turn encoding their subtree. In the initial round (and the only one in case of success) the audit involves sending out audit requests of the simple type. These requests are similar to retrieval requests except that in their response, proximate storers do not send back the chunk itself but instead they calculate the audit secret hash (ASH) and respond with that. Thus during simple audit, audit requests are broadcast from a node to its peers in the swarm and the swarm collectively forwards them all the way to custodian nodes. Responses travel back to parent auditors the same way (see :numref:`Figure %s `). .. _fig:crash: @@ -546,28 +557,28 @@ Recall that a chunk encodes a subtree, in particular a non-leaf chunk consists o :alt: audit :figclass: align-center - This figure zooms in on a chunk in a chunk tree of a document. The chunks represent their custodian nodes that act as auditors of the subtree their chunk encodes. The arrows represent the flow of information in the successive steps of calculating CRASH. The custodian of the non-leaf chunk receives a seed and iterates over the hashes of its chunk. It initiates a recursive audit challenge on their immediate child nodes. After receiving the response from the chunk's custodian, they perform validation against the error bits and calculate the next seed they then send on to the next child. In case the validation fails, the node backtracks and escalates the audit to ASH proof challenge (dashed lines). After piping the seed through the children's audits, it performs a self-challenge as if it was a leaf chunk and sends back the resulting audit secret to their parent auditor. + This figure zooms in on a chunk in a chunk tree of a document. The chunks represent their custodian nodes that act as auditors of the subtree their chunk encodes. The arrows represent the flow of information in the successive steps of calculating CRASH. The custodian of the non-leaf chunk receives a seed and iterates over the hashes of its chunk. It initiates a ASH challenge on their immediate child nodes in succession. After receiving the response from one chunk's custodian, they perform validation against the error bits and calculate the subsequent seed that they then send on to the following child as an ASH challenge. In case the validation fails, the node backtracks and escalates the audit to a Merkle proof challenge (dashed lines). After piping the seed through the children's audits and getting back valid ASH-es, the node performs a self-challenge as if it was a leaf chunk and sends back the resulting audit secret to their parent auditor. After the audit has been initiated, the *automated collective audit process* proceeds as follows. 5. The main auditor launches the collection/file audit. This means they send an audit request for the chunks represented by the hash segments in their own chunk one at a time proceeding from left to right skipping chunks that occurred before in the collection (as per the respective uniqueness bit). -6. These audit requests for a chunk are addressed by the swarm hash of the chunk, and get forwarded in the usual way to end up at a storer node proximate to the chunk in question. +6. These audit requests for a chunk are addressed by the swarm hash of the chunk, and get forwarded in the usual way to end up at the custodian of the chunk in question. In order to accelerate the process we make sure that peers that get involved in the collective audit get forwarded all the relevant data they need: 7. In addition to the audit request as specified above the parent auditors send the partial verification bits and uniqueness bits relevant to the subtree audited by the child auditor. -These storers that have just received an audit request are either storers of a data chunk (leaves), or they are storers of an intermediate chunk in the swarm tree just like their parent auditor. +These storers that have just received an audit request are either custodians of a data chunk (leaves), or they are custodians of an intermediate chunk in the swarm tree just like their parent auditor. This is just one off network traffic and need not be repeated for subsequent audits. -8. Storers of an intermediate chunk proceed in the same fashion as the top auditor and recursively spawn audit requests on the chunk/subtree defined by the successive hash segments of their chunk one at a time. +8. Custodians of an intermediate chunk proceed in the same fashion as the top auditor and recursively spawn audit requests on the chunk/subtree defined by the successive hash segments of their chunk one at a time. -9. Storers of leaf chunks simply calculate the audit secret hash for their chunk using the seed they received and return that if the partial verification bits match. If they do not match then something went wrong and they respond with a complete ASH proof instead. +9. Custodians of leaf chunks simply calculate the audit secret hash for their chunk using the seed they received and return that if the partial verification bits match. If they do not match then something went wrong and they respond with a complete Merkle proof instead. -10. Upon receiving the secret for a chunk (the simple ASH response) represented by a hash segment of their own chunk, the auditor also checks the secret against the corresponding partial verification mask. If no error is detected, the auditor generates the next seed needed for the audit of the next subtree addressed by the following hash segment. If errors are detected, the auditor starts backtracking to find the source -- see point 15. +10. Upon receiving the secret for a chunk (the simple ASH response) represented by a hash segment of their own chunk, the auditor also checks the secret against the corresponding partial verification bits. If no error is detected, the auditor generates the next seed needed for the audit of the next subtree addressed by the following hash segment. If errors are detected, the auditor starts backtracking to find the source -- see point 14. -11. After all subtree secrets are covered, i.e., the ASH for (the chunk hashing to) the rightmost hash segment is received, the auditor then uses the next seed to calculate their own ASH i.e. the secret for their own chunk. They check their verification bits and if that matches they respond to their parent auditor with this secret. If it does not match they know an error occured before, so they start backtracking to find the source -- see point 15. +11. After all subtree secrets are covered, i.e., the ASH for (the chunk hashing to) the rightmost hash segment is received, the auditor then uses the next seed to calculate their own ASH i.e. the secret for their own chunk. They check their verification bits and if that matches they respond to their parent auditor with this secret. If it does not match they know an error occured before, so they start backtracking to find the source -- see point 14. This step is not spurious because in case there are skipped subtrees (as per uniquness bits), the ASH of the last child does not prove their posession of the entire chunk, ie. a malicious storer could use the non-unique chunks hashes for storage and still pass the audit any number of times. It is easy to see that this process follows the order defined in the previous section, and therefore the last secret calculated by the top auditor is the collection-level recursive audit secret (CRASH) for the collection in question. @@ -611,33 +622,33 @@ Interestingly, this situation could also happen as a result of network growth a The arrows represent local transactions between connected peers. After the audit reaches the closest node and the chunk is not found, the closest node challenges the guardian who in turn challenges the node it originally bought a receipt from, and so on until the challenge lands on the current custodian who now has the chance to connect to the node that is actually closest to the chunk address (or at least closer). -If the proximate node gets the chunk, it calculates the audit secret and the audit can continue. If there is a delay longer than the timeout, the audit concludes and litigation starts against the impostor custodian. The initiator includes the address of the known closer node without which an offending node further out claiming to be righful custodian cannot be prosecuted. +If the closest node gets the chunk, it calculates the audit secret and the audit can continue. If there is a delay longer than the timeout, the audit concludes and litigation starts against the current custodian. The initiator includes the address of the known closer node without which the impostor cannot be prosecuted. -The collective audit can also be used to repair chunks in erasure coded collections, this is not primarily about reporting aid to balance out lost reliability for large files +The collective audit is also used as a health check, for instance, to repair chunks in erasure coded collections. The repair process itslef is independent of the litigation (see :cite:`ethersphere2016sw3`). Conclusion ============= -In this paper we presented a simple proof of custody formula inspired by the Wilkinson--Buterik proof of storage used by Storj (:cite:`wilkinsonetal2014storj`). The formula offers 3 different types of challenge that auditors can use in different stages. We specified an auditing and litigation scheme that has ideal properties to secure the swarm against chunk loss (:cite:`wilkinsonetal2014storj`). +In this paper we presented a simple proof of custody formula inspired by the Wilkinson--Buterik proof of storage used by Storj (:cite:`wilkinsonetal2014storj`). The formula offers 3 different types of challenge that auditors can use in different stages. We specified an auditing and litigation scheme that has ideal properties to secure the swarm against chunk loss. -SMASH proofs offer integrity checking for chunks as well as for documents and document collections that +SMASH/CRASH proofs offer integrity checking for chunks as well as for documents and document collections that -* allows storers to initiate and control audits without storing any information other than the swarm hash of the chunk; +* allows owners to initiate and control audits without storing any information other than the swarm hash of the chunk; * allows owners to outsource auditing without a trusted third party; * it provides a seed generation algorithm for securing large document collections with a single audit secret so it scales for both storage and bandwidth; -* the successive seeds contain error detection which makes it very efficient to find offending nodes without remembering the (masked) secret for each chunk; +* the successive secrets matched against verification bits offer a method of error detection which makes it very efficient to find offending nodes without remembering the (masked) secret for each chunk; * allows easy verification by third parties like smart contracts to serve as evidence when it comes to litigation on the blockchain; -* works without ever writing anything to the blockchain which is only used for last-resort litigation; -* enables very small size proofs to optimize bandwidth use and prevent blockchain bloating -* offers guardians and storers ways to refute the challenge, including proof that auditors request is invalid. +* works without ever writing anything to the blockchain which is thus only used for last-resort litigation; +* enables compact proofs to optimize bandwidth use and prevent blockchain bloating +* offers guardians and custodians ways to refute the challenge, including proof that auditors request is invalid. We outlined an auditing and litigation protocol which * offers efficient ways to probe the swarm off-chain with recursive outsourceable collective audits; * enables prompt incentivised escalation whereby an audit continues as litigation on the blockchain; * helps nodes identify greedy peers that do not forward chunks; -* offer a way to repair improper syncronisation state. - +* offer a way to repair improper syncronisation state; +* offer a method to detect a damage in erasure coded data ideally leading to repair due to redundancy .. bibliography:: ../refs.bib :style: plain