Skip to content

Commit b81a35b

Browse files
committed
Tools to compute UnixFS IPFS hash.
1 parent dee1c11 commit b81a35b

File tree

7 files changed

+498
-1
lines changed

7 files changed

+498
-1
lines changed

libdevcore/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ set(sources
1212
FixedHash.h
1313
IndentedWriter.cpp
1414
IndentedWriter.h
15+
IpfsHash.cpp
16+
IpfsHash.h
1517
JSON.cpp
1618
JSON.h
1719
Keccak256.cpp
1820
Keccak256.h
21+
picosha2.h
1922
Result.h
2023
StringUtils.cpp
2124
StringUtils.h

libdevcore/Exceptions.h

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct Exception: virtual std::exception, virtual boost::exception
4747
DEV_SIMPLE_EXCEPTION(InvalidAddress);
4848
DEV_SIMPLE_EXCEPTION(BadHexCharacter);
4949
DEV_SIMPLE_EXCEPTION(FileError);
50+
DEV_SIMPLE_EXCEPTION(DataTooLong);
5051

5152
// error information to be added to exceptions
5253
using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>;

libdevcore/IpfsHash.cpp

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include <libdevcore/IpfsHash.h>
19+
20+
#include <libdevcore/Exceptions.h>
21+
#include <libdevcore/picosha2.h>
22+
#include <libdevcore/CommonData.h>
23+
24+
using namespace std;
25+
using namespace dev;
26+
27+
namespace
28+
{
29+
bytes varintEncoding(size_t _n)
30+
{
31+
bytes encoded;
32+
while (_n > 0x7f)
33+
{
34+
encoded.emplace_back(uint8_t(0x80 | (_n & 0x7f)));
35+
_n >>= 7;
36+
}
37+
encoded.emplace_back(_n);
38+
return encoded;
39+
}
40+
41+
string base58Encode(bytes const& _data)
42+
{
43+
static string const alphabet{"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"};
44+
bigint data(toHex(_data, HexPrefix::Add));
45+
string output;
46+
while (data)
47+
{
48+
output += alphabet[size_t(data % alphabet.size())];
49+
data /= alphabet.size();
50+
}
51+
reverse(output.begin(), output.end());
52+
return output;
53+
}
54+
}
55+
56+
bytes dev::ipfsHash(string _data)
57+
{
58+
if (_data.length() >= 1024 * 256)
59+
BOOST_THROW_EXCEPTION(
60+
DataTooLong() <<
61+
errinfo_comment("Ipfs hash for large (chunked) files not yet implemented.")
62+
);
63+
64+
bytes lengthAsVarint = varintEncoding(_data.size());
65+
66+
bytes protobufEncodedData;
67+
// Type: File
68+
protobufEncodedData += bytes{0x08, 0x02};
69+
if (!_data.empty())
70+
{
71+
// Data (length delimited bytes)
72+
protobufEncodedData += bytes{0x12};
73+
protobufEncodedData += lengthAsVarint;
74+
protobufEncodedData += asBytes(std::move(_data));
75+
}
76+
// filesize: length as varint
77+
protobufEncodedData += bytes{0x18} + lengthAsVarint;
78+
79+
// PBDag:
80+
// Data: (length delimited bytes)
81+
size_t protobufLength = protobufEncodedData.size();
82+
bytes blockData = bytes{0x0a} + varintEncoding(protobufLength) + std::move(protobufEncodedData);
83+
// TODO Handle "large" files with multiple blocks
84+
85+
// Multihash: sha2-256, 256 bits
86+
bytes hash = bytes{0x12, 0x20} + picosha2::hash256(std::move(blockData));
87+
return hash;
88+
}
89+
90+
string dev::ipfsHashBase58(string _data)
91+
{
92+
return base58Encode(ipfsHash(std::move(_data)));
93+
}

libdevcore/IpfsHash.h

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#pragma once
19+
20+
#include <libdevcore/Common.h>
21+
22+
#include <string>
23+
24+
namespace dev
25+
{
26+
27+
/// Compute the "ipfs hash" of a file with the content @a _data.
28+
/// The output will be the multihash of the UnixFS protobuf encoded data.
29+
/// As hash function it will use sha2-256.
30+
/// The effect is that the hash should be identical to the one produced by
31+
/// the command `ipfs add <filename>`.
32+
bytes ipfsHash(std::string _data);
33+
34+
/// Compute the "ipfs hash" as above, but encoded in base58 as used by ipfs / bitcoin.
35+
std::string ipfsHashBase58(std::string _data);
36+
37+
}

0 commit comments

Comments
 (0)