From 76941a609f7f026379d15e0216bb8f051d74650a Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 6 Jan 2014 04:31:56 +0000 Subject: [PATCH] update dht_sec document --- docs/complete_bit_prefixes.png | Bin 0 -> 7795 bytes docs/dht_sec.html | 84 ++++++++++++++++++++++--------- docs/dht_sec.rst | 87 ++++++++++++++++++++++++++------- docs/hash_distribution.png | Bin 0 -> 9035 bytes docs/ip_id_v4.png | Bin 5798 -> 5825 bytes docs/ip_id_v6.png | Bin 6389 -> 6416 bytes docs/ips.py | 56 --------------------- 7 files changed, 130 insertions(+), 97 deletions(-) create mode 100644 docs/complete_bit_prefixes.png create mode 100644 docs/hash_distribution.png delete mode 100644 docs/ips.py diff --git a/docs/complete_bit_prefixes.png b/docs/complete_bit_prefixes.png new file mode 100644 index 0000000000000000000000000000000000000000..3bc73874d9f321c8e4848f6084c41fbc1a3d0371 GIT binary patch literal 7795 zcmZ8`2{@GB`}bfbW5f&w5#}+JwR}-oiZKjE%9^NTYbq@YktGI08SBiDt+Fc>g_5OY z%QCVgk`h@Oq!=3eGR^<-eSg3A{a^2OJSK$=+N2pXJ4ikoEFA-JoX5MSJhO;X7dIi;A{{Q_#1&u!0u0Q z{`WgUM#dKu1p?`g?fDJa7Lf<(`N%`3@*?aOA|rX`kc~+Hne@O{S8DDEFE0=0 zMFPBs5H^K<7t%kHH$t~Fak`=viH1a?(UB(L6B+5z80o=_+?L;jmj^x`ygXlCV27h59YFy?v*?iH#eJLaWU)1RP62f*1wua&IUI8e!#Z5d1c}<0>%kOnZgxg{`U`) z?_Ae3?(J$cDlT)LCjwJ!iC*8Lp(Z9yc*&UV*!ux_hW@R+jb)BYVx%Y)+7$nemI_n8 ztd$C@Jz~qf|DNco4AU;=ovh7iW!7S)n{H)kGK)1|Cg|3-w-MzT39Pr8G{&u~iJ!#c zP(`O#U5fx)3mbGTfGy$5qtxJ8R9K2Bo|$(7#d1{OwuQ-&Qv#klpsDCA=O{L zwug-ziU7{<3la!{`{sd+ZfB$48B~j689jx_L%-qtx$#ATgce&m4ai$#!w1vQ4GgWF|F ziFY2o2AD(!g<5)FMkqdDoo_BWG7m_c6`Q$=Q-v$KUq-v2V-ii}!4H|}qvQwdAlIIb z(x&+0G1o7Go}?oR_{eb7p!{Nbw4{-NUCi4ji81CIvUGp^=R;nDV?lZ(pM$a@CzmEs z{ghYvJI zt#cXqTo3ab!+b0FT{6~Z{FnvA$BN>DSIdSaaup5mD~PohlU%pNo%Mv z>GSd69Jf|?w;vXsO$8#z-&wQK^rZN=iT_a8MY*kc0O{d<3_t8ih@`dMNEh=i^C~`m z)gcl1rn2(DKhGOydm*Xox=EW@ONJS-9ihS2l)F%lwYRdw74$Uw?a&ZU3y>t8ZDZXi z?%6dMWK6TB9t$`9M=+k_5cZkLkB5Y#UXHZtf#2+N2p0o$H+)S6Jc7^KR`PxctfmZLlmYs@^c^4xL`22UbpAG+rY!M zQieHY!NODg-iOpvN}aMOgz1jr>$hJeACKjT>>qtK0WHYwA?rg9W}{;Ox(Xc5ps4O| zRY}rZE^KzAFmvrQbA1zr7D+=y#0y+LXb{3~evML_aQfbod#Lm9r9yWVu7j7KQ|gSK zb?aJC^*eQ!fg*ol4youVle43xA!B}GR!0@Cl%Vumh{K+XJ%*>M|5`RVx&+~#XPy~| zNpMchzDz+M#AHLCFiZj*t>}Lz2QXNe{pomH*|>#w6&cti5KfxOrAky3j)X8p+ZQ*g zuSSQXuoPJe@EU`TA?C$nBz10xsZrlMg!K^0T^JW;sFEGfg2q1_oAcP+Y zZUO{|H{Q2f5T?jw{1!xjx@v;D5`;KO=+E3W6a21IC?QEgp2F96BkS6|EWYREjpU_Y z(XK6dz#=~y>gKk55BcKR-R%1&clc%m_am&Q3Ph@aHS^s$;!@a}kt2WdZTVu;7FION zd#fYgy}pW&@+oiiQVIV|bP?c$I)AZ7VPT5uCPJL24jxetI?qa%C`Tpo5$T5HCAUgN zT+~kfHk$JuoZW(jqLQwXBBf3tSHneV8NVPTeIgqK0G12lPai_5JBhp8`z$rt7C_+F z{(N;n>0l=*pOyt~6Y&SqCP1JdIEHIY#zgV>9&ptYxNF=D3SChR&0<-Kd=XUSsxJN* zXhb4R4IPx3S2i=26gJEr1EEL%oKmue`mJwwyu95}cq`c88`#VO>rT&Do_`HHIXccp z?jQO`TXyRw7{X%Td^q+TD7!<>W1gvOlB*Z6v{o~|M5@BXmWfglKM9^1Y#pixO;q0f za!ye*i^Z)P9Pg}-3|hG0Sne%=QwfLu3a_t?cFyBIZkCWR!%sbY2$b~?f=hbwD$b6z zf5>AQ-*{^&vf~5Oj#Q87xV8Qogk@ATDx}bE{YkOXi)`Sckt&>F`-WemnI;?XJ9
    #R#X0fJ7b{AkTJn== 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
  1. Node ID restriction
  2. bootstrapping
  3. -
  4. enforcement
  5. -
  6. backwards compatibility and transition
  7. -
  8. forward compatibility
  9. +
  10. rationale
  11. +
  12. enforcement
  13. +
  14. backwards compatibility and transition
  15. +
  16. forward compatibility
  17. @@ -112,20 +113,20 @@ distribution of the IDs remoain uniform. This is why CRC32 was chosen as the hash function. See comparisons of hash functions.

    The expression to calculate a valid ID prefix (from an IPv4 address) is:

    -crc32((ip & 0x01071f7f) .. r)
    +crc32((ip & 0x030f3fff) .. r)
     

    And for an IPv6 address (ip is the high 64 bits of the address):

    -crc32((ip & 0x000103070f1f3f7f) ..  r)
    +crc32((ip & 0x0103070f1f3f7fff) ..  r)
     

    r is a random number in the range [0, 7]. The resulting integer, representing the masked IP address is supposed to be big-endian before hashed. The ".." means concatenation.

    The details of implementing this is to evaluate the expression, store the result in a big endian 64 bit integer and hash those 8 bytes with CRC32.

    -

    The first 4 bytes of the node ID used in the DHT MUST match the first 4 -bytes in the resulting hash. The last byte of the hash MUST match the -random number (r) used to generate the hash.

    +

    The first (most significant) 21 bits of the node ID used in the DHT MUST +match the first 21 bits of the resulting hash. The last byte of the hash MUST +match the random number (r) used to generate the hash.

    ip_id_v4.png ip_id_v6.png

    Example code code for calculating a valid node ID:

    @@ -134,39 +135,40 @@ uint8_t* ip; // our external IPv4 or IPv6 address (network byte order) int num_octets; // the number of octets to consider in ip (4 or 8) uint8_t node_id[20]; // resulting node ID -uint8_t v4mask[] = { 0x01, 0x07, 0x1f, 0x7f }; -uint8_t v6mask[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f }; -uint8_t* mask = num_octets == 4 ? v4_mask : v8_mask; +uint8_t v4_mask[] = { 0x03, 0x0f, 0x3f, 0xff }; +uint8_t v6_mask[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; +uint8_t* mask = num_octets == 4 ? v4_mask : v6_mask; for (int i = 0; i < num_octets; ++i) ip[i] &= mask[i]; -uint32_t rand = rand() & 0xff; +uint32_t rand = std::rand() & 0xff; uint8_t r = rand & 0x7; -uint32_t crc = crc32(0, NULL, 0); +uint32_t crc = crc32(0, nullptr, 0); crc = crc32(crc, ip, num_octets); crc = crc32(crc, &r, 1); +// only take the top 21 bits from crc node_id[0] = (crc >> 24) & 0xff; node_id[1] = (crc >> 16) & 0xff; -node_id[2] = (crc >> 8) & 0xff; -node_id[3] = crc & 0xff; -for (int i = 4; i < 19; ++i) node_id[i] = std::rand(); +node_id[2] = ((crc >> 8) & 0xf8) | (std::rand() & 0x7); +for (int i = 3; i < 19; ++i) node_id[i] = std::rand(); node_id[19] = rand;

    test vectors:

     IP           rand  example node ID
     ============ ===== ==========================================
    -124.31.75.21   1   1712f6c7 0c5d6a4ec8a88e4c6ab4c28b95eee4 01
    -21.75.31.124  86   946406c1 4e7a08645677bbd1cfe7d8f956d532 56
    -65.23.51.170  22   fefd9220 bc8f112a3d426c84764f8c2a1150e6 16
    -84.124.73.14  65   af1546dd 1bb1fe518101ceef99462b947a01ff 41
    -43.213.53.83  90   a9e920bf 5b7c4be0237986d5243b87aa6d5130 5a
    +124.31.75.21   1   d2a6df f10c5d6a4ec8a88e4c6ab4c28b95eee4 01
    +21.75.31.124  86   48cb19 c14e7a08645677bbd1cfe7d8f956d532 56
    +65.23.51.170  22   fd334a 20bc8f112a3d426c84764f8c2a1150e6 16
    +84.124.73.14  65   6aa169 dd1bb1fe518101ceef99462b947a01ff 41
    +43.213.53.83  90   eb6434 bf5b7c4be0237986d5243b87aa6d5130 5a
     

    The bold parts of the node ID are the important parts. The rest are -random numbers.

    +random numbers. The last bold number of each row has only its most significant +bit pulled from the CRC function. The lower 3 bits are random.

    bootstrapping

    @@ -187,6 +189,44 @@ not the node has a correct understanding of its external IP or not. This could be done by voting, or only restart the DHT once at least a certain number of nodes, from separate searches, tells you your node ID is incorrect.

    +
    +

    rationale

    +

    The choice of using CRC32 instead of a more traditional cryptographic hash +function is justified primarily of these reasons:

    +
      +
    1. it is a fast function
    2. +
    3. produces well distributed results
    4. +
    5. there is no need for the hash function to be one-way (the input set is +so small that any hash function could be reversed).
    6. +
    +

    There are primarily two tests run on SHA-1 and CRC32 to establish the +distribution of results. The first one is the number of bits in the output +set that contain every possible combination of bits. The CRC function +has a longer such prefix in its output than SHA-1. This means nodes will still +have well uniformly distributed IDs, even when IP addresses in use are not +uniformly distributed.

    +

    The following graph illustrate a few different hash functions with regard +to this property.

    +complete_bit_prefixes.png +

    This test takes into account IP addresses that are not globally routable, i.e. +reserved for local networks, multicast and other things. It also takes into +account that some /8 blocks are not in use by end-users and exremely unlikely +to ever run a DHT node. This makes the results likely to be very similar to +what we would see in the wild.

    +

    These results indicate that CRC32 provides the best uniformity in the results +in terms of bit prefixes where all possibilities are represented, and that +no more than 21 bits should be used from the result. If more than 21 bits +were to be used, there would be certain node IDs that would be impossible to +have, which would make routing sub-optimal.

    +

    The second test is more of a sanity test for the uniform distribution property. +The target space (32 bit interger) is divided up into 1000 buckets. Every valid +IP and r input is run through the algorithm and the result is put in the +bucket it falls in. The expectation is that each bucket has roughly an equal +number of results falling into it. The following graph shows the resulting +histogram, comparing SHA-1 and CRC32.

    +hash_distribution.png +

    The source code for these tests can be found here.

    +

    enforcement

    Once enforced, write tokens from peers whose node ID does not match its external diff --git a/docs/dht_sec.rst b/docs/dht_sec.rst index 221d11cab..6984341f7 100644 --- a/docs/dht_sec.rst +++ b/docs/dht_sec.rst @@ -71,11 +71,11 @@ __ http://blog.libtorrent.org/2012/12/dht-security/ The expression to calculate a valid ID prefix (from an IPv4 address) is:: - crc32((ip & 0x01071f7f) .. r) + crc32((ip & 0x030f3fff) .. r) And for an IPv6 address (``ip`` is the high 64 bits of the address):: - crc32((ip & 0x000103070f1f3f7f) .. r) + crc32((ip & 0x0103070f1f3f7fff) .. r) ``r`` is a random number in the range [0, 7]. The resulting integer, representing the masked IP address is supposed to be big-endian before @@ -84,9 +84,9 @@ hashed. The ".." means concatenation. The details of implementing this is to evaluate the expression, store the result in a big endian 64 bit integer and hash those 8 bytes with CRC32. -The first 4 bytes of the node ID used in the DHT MUST match the first 4 -bytes in the resulting hash. The last byte of the hash MUST match the -random number (``r``) used to generate the hash. +The first (most significant) 21 bits of the node ID used in the DHT MUST +match the first 21 bits of the resulting hash. The last byte of the hash MUST +match the random number (``r``) used to generate the hash. .. image:: ip_id_v4.png .. image:: ip_id_v6.png @@ -97,25 +97,25 @@ Example code code for calculating a valid node ID:: int num_octets; // the number of octets to consider in ip (4 or 8) uint8_t node_id[20]; // resulting node ID - uint8_t v4mask[] = { 0x01, 0x07, 0x1f, 0x7f }; - uint8_t v6mask[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f }; - uint8_t* mask = num_octets == 4 ? v4_mask : v8_mask; + uint8_t v4_mask[] = { 0x03, 0x0f, 0x3f, 0xff }; + uint8_t v6_mask[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; + uint8_t* mask = num_octets == 4 ? v4_mask : v6_mask; for (int i = 0; i < num_octets; ++i) ip[i] &= mask[i]; - uint32_t rand = rand() & 0xff; + uint32_t rand = std::rand() & 0xff; uint8_t r = rand & 0x7; - uint32_t crc = crc32(0, NULL, 0); + uint32_t crc = crc32(0, nullptr, 0); crc = crc32(crc, ip, num_octets); crc = crc32(crc, &r, 1); + // only take the top 21 bits from crc node_id[0] = (crc >> 24) & 0xff; node_id[1] = (crc >> 16) & 0xff; - node_id[2] = (crc >> 8) & 0xff; - node_id[3] = crc & 0xff; - for (int i = 4; i < 19; ++i) node_id[i] = std::rand(); + node_id[2] = ((crc >> 8) & 0xf8) | (std::rand() & 0x7); + for (int i = 3; i < 19; ++i) node_id[i] = std::rand(); node_id[19] = rand; test vectors: @@ -124,14 +124,15 @@ test vectors: IP rand example node ID ============ ===== ========================================== - 124.31.75.21 1 **1712f6c7** 0c5d6a4ec8a88e4c6ab4c28b95eee4 **01** - 21.75.31.124 86 **946406c1** 4e7a08645677bbd1cfe7d8f956d532 **56** - 65.23.51.170 22 **fefd9220** bc8f112a3d426c84764f8c2a1150e6 **16** - 84.124.73.14 65 **af1546dd** 1bb1fe518101ceef99462b947a01ff **41** - 43.213.53.83 90 **a9e920bf** 5b7c4be0237986d5243b87aa6d5130 **5a** + 124.31.75.21 1 **d2a6df** f10c5d6a4ec8a88e4c6ab4c28b95eee4 **01** + 21.75.31.124 86 **48cb19** c14e7a08645677bbd1cfe7d8f956d532 **56** + 65.23.51.170 22 **fd334a** 20bc8f112a3d426c84764f8c2a1150e6 **16** + 84.124.73.14 65 **6aa169** dd1bb1fe518101ceef99462b947a01ff **41** + 43.213.53.83 90 **eb6434** bf5b7c4be0237986d5243b87aa6d5130 **5a** The bold parts of the node ID are the important parts. The rest are -random numbers. +random numbers. The last bold number of each row has only its most significant +bit pulled from the CRC function. The lower 3 bits are random. bootstrapping ------------- @@ -156,6 +157,54 @@ not the node has a correct understanding of its external IP or not. This could be done by voting, or only restart the DHT once at least a certain number of nodes, from separate searches, tells you your node ID is incorrect. +rationale +--------- + +The choice of using CRC32 instead of a more traditional cryptographic hash +function is justified primarily of these reasons: + +1. it is a fast function +2. produces well distributed results +3. there is no need for the hash function to be one-way (the input set is + so small that any hash function could be reversed). + +There are primarily two tests run on SHA-1 and CRC32 to establish the +distribution of results. The first one is the number of bits in the output +set that contain every possible combination of bits. The CRC function +has a longer such prefix in its output than SHA-1. This means nodes will still +have well uniformly distributed IDs, even when IP addresses in use are not +uniformly distributed. + +The following graph illustrate a few different hash functions with regard +to this property. + +.. image:: complete_bit_prefixes.png + +This test takes into account IP addresses that are not globally routable, i.e. +reserved for local networks, multicast and other things. It also takes into +account that some /8 blocks are not in use by end-users and exremely unlikely +to ever run a DHT node. This makes the results likely to be very similar to +what we would see in the wild. + +These results indicate that CRC32 provides the best uniformity in the results +in terms of bit prefixes where all possibilities are represented, and that +no more than 21 bits should be used from the result. If more than 21 bits +were to be used, there would be certain node IDs that would be impossible to +have, which would make routing sub-optimal. + +The second test is more of a sanity test for the uniform distribution property. +The target space (32 bit interger) is divided up into 1000 buckets. Every valid +IP and ``r`` input is run through the algorithm and the result is put in the +bucket it falls in. The expectation is that each bucket has roughly an equal +number of results falling into it. The following graph shows the resulting +histogram, comparing SHA-1 and CRC32. + +.. image:: hash_distribution.png + +The source code for these tests can be found here_. + +.. _here: https://github.com/arvidn/hash_complete_prefix + enforcement ----------- diff --git a/docs/hash_distribution.png b/docs/hash_distribution.png new file mode 100644 index 0000000000000000000000000000000000000000..7bc1be79e5adb6fd1c53182f67b2e971573404e7 GIT binary patch literal 9035 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 literal 0 HcmV?d00001 diff --git a/docs/ip_id_v4.png b/docs/ip_id_v4.png index 7c17deb630d8021b97bab675378a9968375ee63e..55d02390e9b2965af7d83816bb50bea2e778236f 100644 GIT binary patch delta 5464 zcmX|F2Q(X88>VJy?Hx61C47paYOAfKMTioF8Z~RAwpjU$+Qc5UNrJ?#-PEXATGXCR zjT)tD7Qg=gIsZN9o_p_e-uJodeeS*ImP@>sz`;l#k=%TxYvDseLf7**lcGR$01^^b zSv^g4Q~$i3eA=cGAcI!XQa&>6SLUhF%7FP(QyMMxPu2^uv3%sCNG4j_TWKkz+z1kq zb{3Vb;}H@mb4~?M!7o0NobVl6wE)gujv&TYBJG}&=Z;~Om}Hk@AZ(z7aS+I)@@L|| z(Aej@I&+L{>0seJ*^)qWRv}lnZGZX4lEs5P(V+|#l>5~WlzlrAl@AX<j;nRvGyz`^Y*lw zx3^v_(9y!A*0lyJ^SL5NxrZs~Z9-%bCG?>eqCe)_e>vO_vdFz78UJwP(TWu;dnnR4 zx#L-vh&c1(rG+4Zo%P$_^2LLSvMfbQr_#yS^h>wv4GT`y55x5+St79c_*i%RHs?Sq zqh+(_7mQr!b65L!j34q@(s@AGT04m;5;5#GL$?zSB=N|8V4c#;$D`*IkaAuQ*mbnKO|q7 zJ8R^c2tdd161W_)H@|nigPD5$^MAer*DXf_6ftT9NIDs z4w7Ge1C{g&b4r0!<-=_*_>48k>lh!yS*uw<{{i7$lJ79_y@7fOX&nhHTwD!u9Yib$ zn;t`>StZ%l&}0(LBCEb*!^S=X?l5OcqI9PpdjI>c8w_N;4OC_Ip%lkP1F@9uyfL@B z*{Y{f+WrD!k7#8;q>NQOeiw1Q!M>d*Oktv?^%K&{$a$zI3E{@3=0jMp&$u14ftU?Qb$N1V$j8)H2eN!?3pK*5Y>Wy!1+yoMV@Ks?d{eU0HJjd zWLOpFz&ceP*B&CsK@t4#omEk^6X zF#Pg+eMq=6)ukXGp$%=viSe3?oOqZx*c%aDMzzU~BjPy;XXw7T->MZMKBm2KiRUQ4h&M=-?l*YAFKyIgE&TqElN~&3sZCz`fto$ zwO7AoyPhPW&XV09M}0F+3?8~TH{J8_7kX6E=cg9HwG-r4cB{1rUQjn^ zl&Vd~f8Q~|A5nkZqtX;}MhB=Nh~8gOaGKufi2H>0Bhd4FdFk4H8}sMf>LO2)W@wk; zZ8Nv?_Ja(jRIxO5&b4_rPv_S(uL}DE33cpEYmmiJ>Z37ro%WE#0I zQi!<%Xl5syktz5#){GT|=NcM%M&ZUb+ZQ{o#F;MmJoN)b88v!#XxzTLPd^MO?)k$R zVP8ic^5gb>3w6jR&35iO+&tL@O!lYDqfN3T??VnEvGPWXmzGDlpH#ekaKg?_5cv9NR)MK`&tAr>)d%3HugRm2$(X8jKHNa6{NwtVf7%+P}MTYbCph6x0mGQ z`3I6sis655e;A|Q<5+W5Dom!5u=H1)Ya@6l7iZM~wJWu2D!h8MWA^#nXHb|CHAwM9 z+ma}BKK^T+vLf$K+c%BNNd&XR;yM+&3!?zRK4j7%9~7RoLBo9SEM+14C_lXu(btKa z`XwV51uw7m_GbCuo6FC`ZUF8Xd-#b)UP(7v8?2IGXm* zJ3V%$jelDmxEG6`9cJaYIQ+7-CF&-==DJPmdR+6=D;Ax>-oX*DbBF%(GmgELvU=mN z1fjjGhntEogA+nv7Dhw~7_<}tWV1;qNu_wnVsKIEPXGBf05lnSXoD_XSM^T@jt<3b zt3L$lCERrwk;pjjb!%^Pv824==L6=gjKye!L{sY=0if$aboD@Cj8+&Rn`J_Mo@m;q zZRpCsR8Lz+Y<#H|R1Ip7!n^foNCR$nCRnEo#f9fF*@PWn;!x8n!RipBS;&2` zLlb_tw4EFJ$%jxZXC_4RV_H^Wx;a!GLhoh3TRGrlf2U2@07tnAov#FD;JE~?(u6>t z-b+qH=wH=hrD+f#f~-XW^xZ>*I>c`dvKe9 z5*ebO3QG38Dmr%eOI@XDA74h`YQBm6S8dHL)%G70@r&Pb{(O7mg5}ZsbK2|vRhTXQ z*kDznwYwuG{fW1-Hwf@K_cWn7rJ1lm>O;65wGb$!}{xO{rb)JfMJSr@F}aHsi5Db z6OmTVOn4Q58AjWsvl%?WbU3dq-|6JTa?4HCpxa|uzzZ+z8`lDh8Zf6C=KdYH)pgCW zSu_Hmz1RzdHP1R92VNUviXdhRzgC`FUyHbeAU05!BUa1RWor-B4NpMbU3(FCEh7BJ zsECt>jiY_<;Fb*lsWixtGu5#~^ai~KaF2_Omw3;9mg?iXrKH9P{U~bs&nR{fs8I7Ya+pQm)e z$z5DvvMP>|N|)0;?C@h`x&h$F8vylFf!2h{E>rNr74sU#i;q5;Cm`9ozeHF_=Qk4+ z8p?jsofiX$Lit~ZzVWBikVMp$`dMeD9(Yuz2+icpx_^M9s(Ogb9s`I=U=S4tDU^87 zE&pI1tDyeKhIdUM@i|igZ!qr($4tWUHG>z)nsSesJ=oe%oTN2!w?ihoFK70L zfvr$-c>kb9I;+ZEtoPYXf*ZyU9Y=i0Yxo+8s#SkjwRLY^6@I7# zr|Cd6P9TH={z^N^74yO*bIc6&MU*%738b@d_o1uL>DibF-v?DI|Xl5NSy*CvNaF?cPw;?Q|(^L8LCGm4LcW0`H!pQ&#l@^%4){j}5>( zntz(m5JOla`Bk=oce*9yN0W=pY6{xcKKrQ{fSN(+azmjt-+-4=1G4U)fU~to8IZ)z zDe2aCP=mE7FVBNi+9=w`n)-@7LB}*}Ar<)N+M4#VkGS}R{$b_Z)6YpS5mJb1T%rm@ zFp7onxnViCMp=$le+MRiugCIX;c5p^SXq*Ng4fcj}`vxEh4A#R95dnxOUE-LV%B5>wD2 zHIzNpO8|Sv@h&GGtxTg1Q@QgQ%n)|=@HXNNz>p9Db@-k8RO#LfB_W4#!D4QITGnIX zZX#4K&D-~876BD|;)Jw2`}$Eku%o&EQbteVA-yRo=|tzDNnzhyPoV0-iNWAFlMBWj z4CnAN0N-0|E>eohNCVplh&SVBlUlw&-uo{JTSL~yu3|i7LV?8V`vu&KAZJ4lCPy}) zlzXqRL~jd2u@A#IjkX6IhSNiRw<1X3Mm4eHdC9uuk8e#m>3;Jky9wX?`zV5ETd z0wuwJ>HEK4;<U=7EA zD+lCn(IPEQ+;0eta%S-ew6A6>+P2-(=hFi=BnXM}a{_SeDYj2XHZ1?cKnM(T^)|(! zJJo|_>Fk~*pSYVvx}AxN5S??2``9}5rnJ;E{@0FmZ>*|o?J7JW*Rn9j{b|^H$Tcv zz0*>cv$|gO29o1&E%g@A_UUFD!Hp2NG$Z^L$g#)S62J{A2iJc5m?x&xM4m$DtB+uuTlpR4PCYxk^diEbX23S5S;q^hJ#TS zKlZUWR1bPXAp!>GO`>)s>TlHzj}LJnFttBpaAq~7i+ab8#uewf{g+l4VT}e?oa`bx z4gcT-$jIf)+61eAZuBl{c9tlE*>G&yV7d zdsJ}6p{ry{KrD{xr3)`41!rsT@WD?Any*mqGDJfd>?5Fj;f{r9@bBAO0n`ZhaJ0)? zIT)&;{&xKF9W>Kas3rKXk8-zTqV)us2814$Qo=s4#XP|;KK)~IzX3Np>01X+)L)pP z>^rBUr!{CxZ58i|@xTI^*xazg9OlOCdv7w2!WqmQ<3Ux&`O1M+=+5``1Q#;SF`F?k z>W|4*EX2sLunFH3h5C#z1DpCYn1$XT=x^Tu0hOphs;;nb^Pf>!N_Uj=Nq-vhi6>J~ z)4m`j+#vaXVr9w!+_@wF^08Z%ajEBC6%-v^kORGgFVkw+d^*%W!dDgSrs;C}Sm94~ zYG~fFcQfAWtH-DmK6K}>FsInib;A-b!KGY0{R_Q=C=s0Xtt75FCY!4G#Pu9-o;O`w zK=fz6-EEn7zZ;S(fL%7$*Wt)?;moeESTOX3>2Brz8HDxpiXr_gJ# zmZN78VR9P}a$9H+E%Oj~tqB+^O*2)Ijuayb3J9kg&CLmYszl&tmPbK1PtEfV*QLBi znZ?5us{duP)c*FluXw=Xuf2es@o8mZ=5v)U59@?u8XCKku;a+>wi>A1Wr(R59DVfBl4rIh z2)}GmZ@=3NIb^)&WMQLW?);fQGbvMD|1>LR;vfYfeUK@X{zN5WXhA#8&Hh50$sNlN zn^x0i=}NP0pZmKNPRS3{fJGTbg6?(v)o#+>-%|`%p|Iz1XdQ!%FtGFNuSA7Ab{-eE zn51*^1Y8dV-=^1*UVmk zxpgx;!DoyYkmqyuqX{q>1>nqWBS_;pEt?<-8@GsuwG)3mUv-3zVcDE^GqS@MbG80$ z`FekUO0lBrGFx&Y93;-1D`f?ySE9TXL= zzE!mGB pCbbM@cwjK02Km3{uPaY^ugFGxSEc8FCd&N9^|TB%Ycy;l{sSnddX)eG delta 5495 zcmaKPc{tS3_kVUqmW+uI%D!eDWnW`t3&Ug|`<7j{cw4hh6hmYxgD?g&LbfbZh(h+I zED^G2-@;d)-yh%a?|Ht@_x^S7>z;F7=brPr_jzu+#9Ijhk_>>{f@y1*hvu(i=o$+} znG*_TrgWf7S*N}~yM={Cb<{Qb&x3^oWvKcRSnfGozVv?%WmeVYgQ-i>Wd`{n&yE^k zcZ;uI7S6nHKunGn`>9nj9YUd9tm!#rLwc?Y&Vma({);;RrY_wt`?k%mtHgXY3oeu& zDY#e3pi-XY+yeXL2|Tv zv#x;cj*y2G%p56Z7(Pngd@|wM|Cjf;&6z?}qpoi^d7Zd+t-B8VecyMd92%wQ<CM}!iEI%oBn0>TsfAWT(f5wu;lH-DHV$N~FxNjDpl3OPHE7na~+ZQ1l)X(P$ zukZQ38;qTtdd&R7d=8!t(v3`l=?vGvJh$EJ?E= zjR&)mmUH{kKw6K>-`~Ss5wF;y*$+!qgfV+!^?<&r`!|M|&zIH)JgzsaTKb)5$<+LD z7T~=(GGA#=4ClsFwNUbcMkIm_)HF9L6)s4FvckDkfQoSZACu4Re8LjqA*U&50;w}1 zAlZ(YhehV{Cu8xogrSd%PK}*K(X-=|@+DG;x?2{$i)|dgQ?&8T^ zxr~-CjRv6ZTFMS=vF)w$?hV%24WZffPzP|GSKUOJhcCRLIfC);=_!0XZ4X_lJk3bv zdTq!hlN@Y-|9h~k=GhzCxn@K*9YsF|>IyZZ3 zvwD)_=xg4J&IzEZ&)Ar=y$^u@JW?h!af}E1hs2}5h#8foKp>-)G-Vi<7su-7CwGxy zN|c0NTMMu^*C#cier15Nj1pDo37y}8OYP0WO2YQqoj-0aa8pDRchRVSP(FMlvT0=b z`1srQ3+u8Ur{0?l6CAk^nFBb_9Y&l{g(c^e`jDl^NaAe!T||ru4RFTCOKQS7QoZz_ zi5pgY+S3u+RZFwXnXs_V+%_8Wph152#OEyF?4wPibc0!R$N>qQz5c~0Ts+fMrUi#+ zcl~j|i!OX!e}G?cIt`o_zBp*xtcAHlX6&ZrkD%)<(-tP>rr^I=(`I>wNY^P2ho}c zrcfomai-Rbxj7%mPZE-M|XT#v!`yT``-CO+(GE;y*0Y)k{0;xL&1bd z+XtRix-Wv>OT=c(m9@lO6`EL_BO9&Ps)lERK-z)7(;U$1FYKMI^1zl?{2;|ep0#KB z2`c%P);So{PGQGw=x}+s^)EM*saNy8yX>2WEOq#+l|-U4lj-Vh(Gr5{#9L0QIwHrs z0ep=d`A|i#V!reR*OaOw6B2F|j~k~VfkHFF-v>cMSfp4-4f1ga)IZ%t3tGYPov!#Q zZ3Y5h?V%(j80cow=MFPs%eq;*QmXx)j8lvZM`*4nM0K<5Rw#UPrb14ErInnK4K&9e zUFY0lWT;=Ee?wQq?o;^9r~J*G>5zN6C0{4RI%zf$QY|gtV!0Cpzs_H$@dLelOb;bK zA+ShQetv!Q0c;l6IX0eeG9ED)&n*VCh<628&F%+!(7kW#SJ9htyYyRtoW2wCU}|ah z>oLbmFle=mi+Pm2dK%oRF7#74JknRCB~@vU7XmJtVgnalL)dV1Zt*ocrB!VOXmSU6 zFRXi4flk)b92;@$1=kv)()gg7X*3>P0hLe+WU|#}Yi5wYtlgLWwScxbmC+P6Py`^5 zB6=*xXup7BXHy-F3zBtk6gFu4t;^^(8De_OaYC9@eNE)U+aHUTXiI<1xi zRNqcmcdT4$anx`N&GJ(edPU>-)=2*jkFp-5^-Ic{hN1|}kl#f@CHthqvAN09nugpm z)9do^C;37ME9^lk3bN0Owx7chK-;*K4(R+%p`MR!`?!nb%_k8v-q5Rno?sImo1lZ5 zrBvDH?X9O?eu+A;|Ex^ysSgrEDbR|^JDy$cH%I5s$Hk8@qiMykRk4Ii&t&-CP?5p~ z65t)!gy7yqCDE$kr1cm23TAc}$~ybWKx!Q7#FpU*s9=FTw6NL%UFzh65n+7b*ss~~ zV`}8oCjqB7Z}U;X8$h0TJ4cbFf5E@IoaSek?X65RKKZQT{+Q!_%y=xTMIbnN0m4}d;e)q{5V2F|bj+lDCoG}F z*_}pQ51guE2hr1ec_HB9cp_W64~^y1+Xg3X^0^7#2bQ$u{O@yDRR?-Yc>=i(Hip*T zM$YDOedQ({Cn%bC(Dr`Doa=BZdTy*2)S$b6YC=r~tR;I$WYHMYVM z3cl>19eSXASoR8=EoA>C>e0>)HFDuC_Qp38d)ZM-Y)@HtwN+`=wTp7N6zRi>SSGXl zh>R4S5W6G(ASkDpg$3k0V#vEWb%dr+NRLlhFHw5w7{TyN7ZEQ_a723O=on|*4b3nL zXg9z^Gqo|1P4$N*lY4_dUL;Q|CcRF3;p%^B z{xn|)UYj!<^Gl;g(^&F#apbIqqASM7omM}v0W$(l(82H;E;5i(-hO63oPn4K>4~Ur zdZ;6wnBsa~yI-nC!8c!hV?cqg$W@5mZ4~8-J!x`XVjwA^>I-o*G6whIXmF9ouqE~{ zm%><-+g==jMM;cyRpbx{^tc(=pDKam3ik<<8!rO=OzO1PXAj_GUvBVhaTgIQyC(yO zkCQvO_|fi$32#}REqzXrNr!~paaY!@cTZBHB7UMW009(xg2#G;ZUgo?=v` zV}NLR{kvOZnPsHQDN$WZ8W|Rab)zZ1XMQc+5+WvyU-ezCkug&C^SPlOdHV5PLb2tZ z0#97h_O;cQx(+EdSX+3&Df=v}~c zL_I!9p`iC1TjS|;J#3;EGtwIsk^`P`LShc$l5|b!LODtn4-uTH`}}h4Xt`qT5p{D& z96|Z>YBSgdHl%M(qx;b+;+~{)p^dDm4XjG!KG|;!Fk&q{md0v1C@#?0+?0r86c)li zomI;$)@GykvKaCCBnxlvlqoQUGV_N19k>@Hn+T>}!a(BpIE^8rM4X)}wPz3gstnU$ zs-3f2ZOH!S=Kl7`AIPCfpNb$T1#N&TYs024nwk#+YQTF|7fh@T>gun5c(Ai+| zO(wjMEA+R-Od$T4i>nH?;?9}N=hJ!u4`~0 z8ROxQ6!ze27d)@&7m41I3NwQf>-f4Wd`e>Mn={iLw)bRpkJ?Sybqa@=U1gpNY zdNtm`YGF1nOdK>J8;#qzm;vITu!ned_;OMZ{36Mve|vWlAY+!@Ng|Puw1dc%KVw1N z7TAc&|irCN?z||Nqt;-@VLSf=_R6 zk(RY# zh7Uh`M#=744qDW--gw7DZs4VCERD4VvxRhDJk=MR zzt6v~!*YATyVV?-^8UGnlAKi)Jqg{;h&lH0Zx`+Gfmn>k$pv5b)*O9Iq=BsOai}lussYUDzt{A<5#O4$f#+bk>WwF{Tbi~@f&wOqJ1 zaS5)Vty^XDdBwmp{WY1DztRj;s;Jkx5#}rA3{xU@%c=5+V4y==d3xK^e~# z>4K=ncFC~2r>PRuA$G9Ot#d_c>B)hw9O%TuBHf8D+L8~&^YV36VS9Wx1xM03Ld*7c z)^h~cCZ_*eL3Sr+dcoRv<+}P=)%y8iqf60PVXM+$xjbmuP{5&1IO8f zOm<=yaoe!c|HLtW>aq6`!;0gr|M5@`HpDO|(9nhLkG}KenB|FPCR0OHGr1|S(xqKA zn*KNQS*v(~PtO&b4QQS-=juy$CluWfwG8$ULpeXSs8zw!8vTjRl&&^Pbx@FVXyq+$ z>yJTLv#7zB`zUuh3IfQmX@>YqOT5BfT~i}7(3vNaUbxujzqRrI&7!q!?C-?7`SA+7 zX#nX;8%y&*)#Js{vqv6Y@MzquQdhitpXCV&1XO)6iZCwuhc=dKAj;9qgQK`h!R;k> z${)n@5McqSH1X^6&Ai;wCIdTxa{Dj(=5{ zajb7sPClIA?m>*oKqt5#!47!mKFI;4Aq}51GA3#$Ppb#+l(cRf!&LnEoB}Nof>5Vb z?o~c&t)oNB6)VUa$$C3A_xq_kYuRDsky5Fb{j0p@Fd;_3sl0tD#ed9S5jvx)=_!k= z;AA+>6ek~x^6X8i2OhaJrv`6y7*fTX1M~0nSC(HGL!Y1W-U4-)D4zp4#&JE**hro{ zJ4Hv1;eeY~X`r!UdSPPx!mG^l-oTI_hEBSOI<7!Aq44_MT2Xad?{M+0fpNs!u4;^l zI%4|HhIYydF*|k_Lu>!#ZS<@q6qF?^J@3*!60&UB6Q;eR&yjmjBKtlymQcPSgH Pe>hCXNV`(gA@;ujrwe&c diff --git a/docs/ip_id_v6.png b/docs/ip_id_v6.png index 0422adb50f2875765ee3561399f1d8c512d3335e..328caed1c959a29c1c62dfe72b7546e6af36c26b 100644 GIT binary patch delta 6118 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 delta 6091 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 z 0: - ret += min(num_used, bits) - num_used -= bit_dec - if num_used < 0: num_used = 0 - bits -= 8 - - return 1 << ret - -f = open('ip_id_v4.dat', 'w+') -for i in range(0, 33): - print >>f, '%d\t%d\t%d' % (i, num_ids(i, 32), 1 << i) -f.close() - -f = open('ip_id_v6.dat', 'w+') -for i in range(0, 65): - print >>f, '%d\t%d\t%d' % (i, num_ids(i, 64), 1 << i) -f.close() - -f = open('ip_id.gnuplot', 'w+') - -f.write(''' -set term png size 600,300 -set output "ip_id_v4.png" -set logscale y -set title "Number of possible node IDs" -set ylabel "possible node IDs" -set xlabel "bits controlled in IPv4" -set xtics 4 -set grid -plot "ip_id_v4.dat" using 1:2 title "octet-wise modulus" with lines, \ - "ip_id_v4.dat" using 1:3 title "hash of IP" with lines - -set output "ip_id_v6.png" -set title "Number of possible node IDs" -set xlabel "bits controlled in IPv6" -plot "ip_id_v6.dat" using 1:2 title "octet-wise modulus" with lines, \ - "ip_id_v6.dat" using 1:3 title "hash of IP" with lines -''') -f.close() -os.system('gnuplot ip_id.gnuplot') -