最近,IPFS增加了对琐碎(身份)哈希的支持 。 在我的文章中,我将讨论它并展示如何使用它。
让我提醒您:星际文件系统是一个新的分散式文件共享网络(HTTP服务器, 内容传递网络 )。 我在“星际文件系统IPFS”一文中开始了有关它的故事。
通常,通过散列函数进行散列时,数据不可逆地被“压缩”,因此获得了简短的标识符。 该标识符使您可以在网络上查找数据并检查其完整性。
琐碎的哈希是数据本身。 数据不会发生任何变化,因此,“哈希”的大小等于数据的大小。
琐碎的散列执行与Data:URL相同的功能。 在这种情况下,内容标识符包含数据本身而不是哈希。 这使您可以将子块嵌套在父块中,从而在接收父块后立即使它们可用。 您还可以将站点数据直接包含在DNS记录中。
例如,使用琐碎的哈希在内容标识符 (CID)中编码文本字符串“ Hello World”。

ID结构:
[ ][varint CID][varint ][varint ID ][varint ][]
让我们从头开始。
[哈希]
在我们的例子中,琐碎的哈希是字符串本身。 让我们将其翻译为HEX 。
" " = 0x"D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180"
这是此utf-8编码字符串的十六进制。 但是为了使浏览器确定这是utf-8行,请将其添加到开头: 0xEFBBBF
。 这是一个字节序列标记 (BOM)。
0x"EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180"
[varint哈希长度]
现在我们可以计算“哈希”的长度。 每两个十六进制字符为一个字节。 因此,结果字符串的长度为22个字节。 在十六进制中,它将为0x16
。
在行首添加0x16
。
0x"16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180"
[varint哈希ID]
现在我们需要哈希ID。 哈希表中的琐碎哈希或标识具有标识符0x00
。
将0x00
添加到该行的开头。
0x"00 16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180"
这已经是标识符的多哈希部分,您可以将HEX转码为Base58,并且多哈希已准备就绪。 但是ipfs无法在内容标识符(CID)之外识别它。
让我们继续前进。
[varint内容类型]
现在查看multicodec表以获取内容类型。 在我们的情况下,这是原始数据,标识符分别为0x55
。
在行首添加0x55
。
0x"55 00 16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180"
[CID的变体版本]
我们对内容标识符的第一个版本的格式进行编码。 因此,添加0x01。
在行首添加0x01
。
0x"01 55 00 16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180"
因此,我们已经处于终点。
[基本前缀]
它指示使用哪种选项将二进制数据编码为文本。
十六进制(F)
我们可以通过在HEX基本前缀的开头添加“ F”符号来直接使用HEX术语
F01550016EFBBBFD09FD180D0B8D0B2D0B5D18220D0BCD0B8D180
我们获得了包含utf-8行的内容的十六进制标识符:“ Hello world”
测试: / ipfs / F01550016EFBBBFD09FD180D0B8D0B2D0B5D18220D0BCD0B8D180
Base58btc(z)
因此,Base58btc会更短
我们将十六进制字符串转换为base58btc。 您可以使用在线转换器 。
0x"01 55 00 16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180" = "3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P" (base58btc)
将基本前缀字符base58btc“ z”添加到该行的开头
z3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P
我们给base58btc一个内容标识符,其中包含utf-8行:“ Hello world”
测试: / ipfs / z3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P
DAG块
文本很好,但是为了对HTML页面进行编码,我们需要将其数据嵌入DAG目录块中。
这是我们的HTML:
<b><i><u> </u></i></b>
同样,根据上述说明,我们在base58btc中获得此文本的内容标识符:
zeExnPvBXdTRwCBhfkJ1fHFDaXpdW4ghvQjfaCRHYxtQnd3H4w1MPbLczSqyCqVo
现在编写JSON文件:
{ "links": [{ "Cid": { "/": "zeExnPvBXdTRwCBhfkJ1fHFDaXpdW4ghvQjfaCRHYxtQnd3H4w1MPbLczSqyCqVo" }, "Name": "index.html" }], "data": "CAE=" }
- “数据”指示DAG块的类型-目录。
- “链接”是文件链接的数组。
- “名称”分别是文件的名称。
- “ Cid”包含内容标识符
ipfs dag put -f"protobuf"
通过IPFS将JSON转换为DAG块。
我有一个多哈希算法: QmXXixn4rCzGguhxQPjXQ8Mr5rdqwZfJTKkeB6DfZLt8EZ
在这个阶段,我们收到了一个块,其中有一个目录,其中刻有一个文件。
接下来,使用这种多现金方式,卸载完成的块
ipfs block get QmXXixn4rCzGguhxQPjXQ8Mr5rdqwZfJTKkeB6DfZLt8EZ > block.dag
我们将block.dag的内容转换为十六进制:
0x"123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801"
添加:
- CID版本(0x01)
- DAG内容类型(0x70)
- 平凡哈希(0x00)
- 数据大小69字节(0x45)
0x"01 70 00 45 123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801"
转换为Base58btc并添加前缀“ z”
z6S3Z3W1zuRxio8AJC41jRTdyU9pZWnU6sNbvyGyypEdD8JVNdW42ZmGYWKWGbVDELLvJNWcMspaZMUPZKt7JQmhdyXCqq7j37GL
因此,我们获得了一个目录的内容标识符,该目录中的html页面index.html带有文本“ Hello World”。
测试: / ipfs / z6S3Z3W1zuRxio8AJC41jRTdyU9pZWnU6sNbvyGyypEdD8JVNdW42ZmGYWKWGbVDELLvJNWcMspaZMUPZKt7JQmhdyXCqqjj37gL
此外,此哈希还可以嵌入到另一个块中或记录在DNS dnslink记录中。 因此,您可以在一个街区中容纳一个小型简单站点。
DAG块和协议缓冲区
DAG块也可以手动组装。 DAG块是协议缓冲区数据。 顶层是merkledag.proto ,在数据中具有unixfs.proto 。
协议缓冲区
任何原型缓冲区均以varint字段标识符开头。 标识符通常占用一个字节,因为其总值小于0x80。 在我们的情况下,第一个字节为0x12。 该字段的低3位是类型。 其余的是原始文件中指定的ID。
长度定界
我们解密标识符:
0x12 & 0x07 = 2 (: Length-delimited) 0x12 >> 3 = 2 (ID: 2)
长度分隔意味着varint后跟字段的大小(以字节为单位)及其内容直接。 此类型用于各种嵌套结构和原始数据(字符串,字节,嵌入式消息,打包的重复字段)。 原始文件中已经定义了什么。
瓦林特
解密另一种类型的标识符:
0x18 & 0x07 = 0 (: Varint) 0x12 >> 3 = 3 (ID: 3)
Varint表示紧随varint中的值。 该容器用于写入许多类型的值(int32,int64,uint32,uint64,sint32,sint64,bool,enum)。 其中还定义了原始文件。
我们将分析上面翻译成HEX的block.dag
要解析一个块,您可以使用一个无需使用原始文件即可自动解析任何协议缓冲区的站点 。
0x"123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801"
我们反汇编该块并映射原始文件中的标识符。
merkledag.proto // An IPFS MerkleDAG Link message PBLink { // multihash of the target object optional bytes Hash = 1; // utf string name. should be unique per object optional string Name = 2; // cumulative size of target object optional uint64 Tsize = 3; } // An IPFS MerkleDAG Node message PBNode { // refs to other objects repeated PBLink Links = 2; // opaque user data optional bytes Data = 1; }
unixfs.proto message Data { enum DataType { Raw = 0; Directory = 1; File = 2; Metadata = 3; Symlink = 4; HAMTShard = 5; } required DataType Type = 1; optional bytes Data = 2; optional uint64 filesize = 3; repeated uint64 blocksizes = 4; optional uint64 hashType = 5; optional uint64 fanout = 6; }
12 (: 2 (Length-delimited). ID: 2 (PBLink PBNode.Links (merkledag.proto))) 3F (: 63 ) 0A (: 2 (Length-delimited). ID: 1 (PBLink.Hash)) 2F (: 47 ) 01 55 00 2B (CIDv1 Raw Identity 43 ) EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E = "<b><i><u> </u></i></b>" 12 (: 2 (Length-delimited). ID: 2 (PBLink.Name)) 0A (: 10 ) 696E6465782E68746D6C = "index.html" 18 (: 0 (Varint). ID: 3 (PBLink.Size)) 00 (: 0) 0A (: 2 (Length-delimited). ID: 1 (PBNode.Data = Data (unixfs.proto))) 02 (: 2 ) 08 (: 0 (Varint). ID: 1 (Data.Type)) 01 (1 == Data.DataType.Directory)
因此,具有两个文件的块将如下所示:
12 (: 2 (Length-delimited). ID: 2 (PBLink PBNode.Links (merkledag.proto))) 3B (: 59 ) 0A (: 2 (Length-delimited). ID: 1 (PBLink.Hash)) 2F (: 47 ) 01 55 00 2B (CIDv1 Raw Identity 43 ) EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E = "<b><i><u> </u></i></b>" 12 (: 2 (Length-delimited). ID: 2 (PBLink.Name)) 06 (: 6 ) 312E68746D6C = "1.html" 18 (: 0 (Varint). ID: 3 (PBLink.Size)) 00 (: 0) 12 (: 2 (Length-delimited). ID: 2 (PBLink PBNode.Links)) 3B (: 59 ) 0A (: 2 (Length-delimited). ID: 1 (PBLink.Hash)) 2F (: 47 ) 01 55 00 2B (CIDv1 Raw Identity 43 ) EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E = "<b><i><u> </u></i></b>" 12 (: 2 (Length-delimited). ID: 2 (PBLink.Name)) 06 (: 6 ) 322E68746D6C = "2.html" 18 (: 0 (Varint). ID: 3 (PBLink.Size)) 00 (: 0) 0A (: 2 (Length-delimited). ID: 1 (PBNode.Data = Data(unixfs.proto))) 02 (: 2 ) 08 (: 0 (Varint). ID: 1 (Data.Type)) 01 (1 == Data.DataType.Directory)
也就是说,PBNode.Links(0x12)字段重复的次数与要放置在块中的文件数量一样多。
要进行检查,请在“ F 01 70 00”(HEX CIDv1 DAG标识)的开头添加DAG块“ 7E”的大小(126字节)
F 01 70 00 7E 12 3B 0A 2F 01 55 00 2B EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E 12 06 312E68746D6C 18 00 12 3B 0A 2F 01 55 00 2B EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E 12 06 322E68746D6C 18 00 0A 02 08 01
检查: / IPF问题/ F0170007E123B0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E1206312E68746D6C1800123B0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E1206322E68746D6C18000A020801
结论
我希望我给出了足够的信息,以便可以实现块和标识符的创建。