Skip to content

Commit 00af3ac

Browse files
committed
[WIP] Tools to compute UnixFS IPFS hash.
1 parent fbe225a commit 00af3ac

File tree

5 files changed

+431
-0
lines changed

5 files changed

+431
-0
lines changed

libdevcore/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ set(sources
1616
JSON.h
1717
Keccak256.cpp
1818
Keccak256.h
19+
picosha2.h
1920
Result.h
2021
StringUtils.cpp
2122
StringUtils.h

libdevcore/SwarmHash.cpp

+58
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <libdevcore/SwarmHash.h>
2121

2222
#include <libdevcore/Keccak256.h>
23+
#include <libdevcore/picosha2.h>
2324

2425
using namespace std;
2526
using namespace dev;
@@ -67,3 +68,60 @@ h256 dev::swarmHash(string const& _input)
6768
{
6869
return swarmHashIntermediate(_input, 0, _input.size());
6970
}
71+
72+
namespace
73+
{
74+
bytes varintEncoding(size_t _n)
75+
{
76+
uint8_t leastSignificant = _n & 0x7f;
77+
size_t moreSignificant = _n >> 7;
78+
if (moreSignificant)
79+
return bytes{uint8_t(uint8_t(0x80) | leastSignificant)} + varintEncoding(moreSignificant);
80+
else
81+
return bytes{leastSignificant};
82+
}
83+
84+
string base58Encode(bytes const& _data)
85+
{
86+
static string const alphabet{"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"};
87+
bigint data(toHex(_data, HexPrefix::Add));
88+
string output;
89+
while (data)
90+
{
91+
output += alphabet[size_t(data % alphabet.size())];
92+
data /= alphabet.size();
93+
}
94+
reverse(output.begin(), output.end());
95+
return output;
96+
}
97+
}
98+
99+
bytes dev::ipfsHash(string const& _data)
100+
{
101+
bytes lengthAsVarint = varintEncoding(_data.size());
102+
103+
bytes protobufEncodedData;
104+
// Type: File
105+
protobufEncodedData += bytes{0x08, 0x02};
106+
if (!_data.empty())
107+
{
108+
// Data (length delimited bytes)
109+
protobufEncodedData += bytes{0x12};
110+
protobufEncodedData += lengthAsVarint;
111+
protobufEncodedData += asBytes(_data);
112+
}
113+
// filesize: length as varint
114+
protobufEncodedData += bytes{0x18} + lengthAsVarint;
115+
116+
// TODO check what this actually refers to
117+
// TODO Handle "large" files with multiple blocks
118+
bytes blockData = bytes{0x0a} + varintEncoding(protobufEncodedData.size()) + protobufEncodedData;
119+
120+
cout << toHex(protobufEncodedData) << endl;
121+
cout << toHex(blockData) << endl;
122+
// Multihash: sha2-256, 256 bits
123+
// TODO Do not go to hex and back
124+
bytes hash = bytes{0x12, 0x20} + fromHex(picosha2::hash256_hex_string(blockData));
125+
cout << "ipfs://" << base58Encode(hash) << endl;
126+
return hash;
127+
}

libdevcore/SwarmHash.h

+6
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,11 @@ namespace dev
2828

2929
/// Compute the "swarm hash" of @a _input
3030
h256 swarmHash(std::string const& _input);
31+
/// Compute the "ipfs hash" of a file with the content @a _data.
32+
/// The output will be the multihash of the UnixFS protobuf encoded data.
33+
/// As hash function it will use sha2-256.
34+
/// The effect is that the hash should be identical to the one produced by
35+
/// the command `ipfs add <filename>`.
36+
bytes ipfsHash(std::string const& _data);
3137

3238
}

0 commit comments

Comments
 (0)