├── .github
├── dependabot.yml
└── workflows
│ ├── generated-pr.yml
│ ├── maven.yml
│ └── stale.yml
├── .gitignore
├── LICENSE
├── README.md
├── jitpack.yml
├── pom.xml
└── src
├── main
└── java
│ └── io
│ └── ipfs
│ └── multihash
│ └── Multihash.java
└── test
└── java
└── io
└── ipfs
└── multihash
└── MultihashTest.java
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 |
--------------------------------------------------------------------------------
/.github/workflows/generated-pr.yml:
--------------------------------------------------------------------------------
1 | name: Close Generated PRs
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *'
6 | workflow_dispatch:
7 |
8 | permissions:
9 | issues: write
10 | pull-requests: write
11 |
12 | jobs:
13 | stale:
14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-generated-pr.yml@v1
15 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | name: Java CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v4
12 | - name: Set up JDK 11
13 | uses: actions/setup-java@v4
14 | with:
15 | distribution: temurin
16 | java-version: 11
17 | - name: Build with Maven
18 | run: mvn -B test-compile
19 | - name: Run tests with Maven
20 | timeout-minutes: 10
21 | run: mvn -B test
22 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: Close Stale Issues
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *'
6 | workflow_dispatch:
7 |
8 | permissions:
9 | issues: write
10 | pull-requests: write
11 |
12 | jobs:
13 | stale:
14 | uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .project
3 | .settings
4 | *.class
5 |
6 | target/**
7 | build/**
8 | dist/**
9 | .idea/**
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2015 Ian Preston
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # java-multihash
2 |
3 | [](http://ipn.io)
4 | [](https://github.com/multiformats/multiformats)
5 | [](https://webchat.freenode.net/?channels=%23ipfs)
6 | [](https://travis-ci.org/multiformats/java-multihash)
7 | [](https://jitpack.io/#multiformats/java-multihash)
8 | [](https://github.com/RichardLitt/standard-readme)
9 |
10 | > A Java implementation of [multihash](https://github.com/multiformats/multihash).
11 |
12 | ## Install
13 |
14 | Simply clone this repository.
15 |
16 | ## Usage
17 |
18 | ```java
19 | Multihash b58 = Multihash.decode("QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy");
20 | Multihash b36 = Multihash.decode("kmue2y4illvr0m3lt8x6z8iwghtxlzdmkjh957p5rr5cdr9243ugc");
21 | ```
22 |
23 | Note that this library only decodes & encodes Multihashes, and does not actually include any implementations of the hash functions themselves.
24 |
25 | Consumers of this library can use different implementations for different reasons. Here are a few possible implementation choices for each `Multihash.Type`:
26 |
27 | * [JDK's `MessageDigest`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/security/MessageDigest.html) supports (at least) these:
28 | * md5 = MD5
29 | * sha1 = SHA-1
30 | * sha2-224 = SHA-224
31 | * sha2-256 = SHA-256
32 | * sha2-384 = SHA-384
33 | * sha2-512 = SHA-512
34 | * sha2-512-224 = SHA-512/224
35 | * sha2-512-256 = SHA-512/256
36 | * sha3_224 = SHA3-224
37 | * sha3_256 = SHA3-256
38 | * sha3_512 = SHA3-512
39 | * [Google Guava's Hashing](https://github.com/google/guava/wiki/hashingexplained) offers [intentionally only](https://github.com/google/guava/issues/5990#issuecomment-2571350434) these:
40 | * md5 = `@Deprecated Hashing.md5()`
41 | * sha1 = `@Deprecated Hashing.sha1()`
42 | * sha2_256 = `Hashing.sha256()`
43 | * sha2_512 = `Hashing.sha512()`
44 | * murmur3 = `Hashing.murmur3_32_fixed()`
45 | * [Google Tink](https://developers.google.com/tink/supported-key-types#mac)
46 | * AES-CMAC, see [Multicodec Issue #368](https://github.com/multiformats/multicodec/issues/368)
47 | * [BouncyCastle](https://www.bouncycastle.org/documentation/specification_interoperability/)
48 | * blake2*
49 | * blake3*
50 | * shake-*
51 | * ripemd-*
52 | * [Apache Commons Codec](https://commons.apache.org/proper/commons-codec/)
53 | * blake3*
54 | * murmur3
55 | * [Jacksum](https://github.com/jonelo/jacksum)
56 | * skein*
57 | * ...
58 |
59 | Please contribute an update to this list if you know of any other related libraries.
60 |
61 | ## Dependency
62 |
63 | You can use this project by building the JAR file as specified below, or by using [JitPack](https://jitpack.io/#multiformats/java-multihash/) (also supporting Gradle, SBT, etc).
64 |
65 | for Maven, you can add the follwing sections to your POM.XML:
66 |
67 | ```xml
68 |
69 |
70 | jitpack.io
71 | https://jitpack.io
72 |
73 |
74 |
75 |
76 |
77 | com.github.multiformats
78 | java-multihash
79 | $LATEST_VERSION
80 |
81 |
82 | ```
83 |
84 | ## Testing
85 |
86 | `mvn test`
87 |
88 | ## Building
89 |
90 | `mvn package` will build a JAR file with Maven dependency information.
91 |
92 | ## Releasing
93 |
94 | The version number is specified in the `pom.xml` file and must be changed in order to be accurately reflected in the JAR file manifest. A git tag must be added in the format "vx.x.x" for JitPack to work.
95 |
96 | ## Maintainers
97 |
98 | Captain: [@ianopolous](https://github.com/ianopolous).
99 |
100 | ## Contribute
101 |
102 | Contributions welcome. Please check out [the issues](https://github.com/multiformats/java-multihash/issues).
103 |
104 | Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
105 |
106 | Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
107 |
108 | ## License
109 |
110 | [MIT](LICENSE) © 2015 Ian Preston
111 |
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | before_install:
2 | - sdk install java 21-tem
3 | - sdk use java 21-tem
4 | - sdk install maven
5 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.github.multiformats
6 | java-multihash
7 | 1.3.5
8 | jar
9 |
10 | multihash
11 | https://github.com/multiformats/java-multihash
12 |
13 |
14 | https://github.com/multiformats/java-multihash/issues
15 | GitHub Issues
16 |
17 |
18 |
19 | https://github.com/multiformats/java-multihash
20 | scm:git:git://github.com/multiformats/java-multihash.git
21 | scm:git:git@github.com:multiformats/java-multihash.git
22 |
23 |
24 |
25 |
26 | MIT License
27 | https://github.com/multiformats/java-multiaddr/blob/master/LICENSE
28 | repo
29 |
30 |
31 |
32 |
33 | UTF-8
34 | UTF-8
35 | 5.11.0
36 | 3.0
37 | v1.1.1
38 |
39 |
40 |
41 |
42 | jitpack.io
43 | https://jitpack.io
44 |
45 |
46 |
47 |
48 |
49 | com.github.multiformats
50 | java-multibase
51 | ${version.multibase}
52 |
53 |
54 | org.junit.jupiter
55 | junit-jupiter
56 | ${version.junit}
57 | test
58 |
59 |
60 | org.hamcrest
61 | hamcrest-core
62 | ${version.hamcrest}
63 | test
64 |
65 |
66 |
67 |
68 |
69 |
70 | org.apache.maven.plugins
71 | maven-compiler-plugin
72 | 3.1
73 |
74 | 11
75 | 11
76 |
77 |
78 |
79 | org.apache.maven.plugins
80 | maven-surefire-plugin
81 | 3.3.1
82 |
83 |
84 | org.apache.maven.plugins
85 | maven-jar-plugin
86 | 3.0.2
87 |
88 |
89 |
90 | true
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/src/main/java/io/ipfs/multihash/Multihash.java:
--------------------------------------------------------------------------------
1 | package io.ipfs.multihash;
2 |
3 | import io.ipfs.multibase.*;
4 |
5 | import java.io.*;
6 | import java.util.Arrays;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | public class Multihash {
11 | public static final int MAX_IDENTITY_HASH_LENGTH = 1024*1024;
12 |
13 | // From https://github.com/multiformats/multicodec/blob/master/table.csv
14 | public enum Type {
15 | id(0, -1),
16 | md5(0xd5, 16),
17 | sha1(0x11, 20),
18 | sha2_256(0x12, 32),
19 | sha2_512(0x13, 64),
20 | dbl_sha2_256(0x56, 32),
21 | sha3_224(0x17, 24),
22 | sha3_256(0x16, 32),
23 | sha3_512(0x14, 64),
24 | shake_128(0x18, 32),
25 | shake_256(0x19, 64),
26 | keccak_224(0x1a, 24),
27 | keccak_256(0x1b, 32),
28 | keccak_384(0x1c, 48),
29 | keccak_512(0x1d, 64),
30 | murmur3(0x22, 4),
31 |
32 | // blake2b (64 codes)
33 | blake2b_8(0xb201, 1),
34 | blake2b_16(0xb202, 2),
35 | blake2b_24(0xb203, 3),
36 | blake2b_32(0xb204, 4),
37 | blake2b_40(0xb205, 5),
38 | blake2b_48(0xb206, 6),
39 | blake2b_56(0xb207, 7),
40 | blake2b_64(0xb208, 8),
41 | blake2b_72(0xb209, 9),
42 | blake2b_80(0xb20a, 10),
43 | blake2b_88(0xb20b, 11),
44 | blake2b_96(0xb20c, 12),
45 | blake2b_104(0xb20d, 13),
46 | blake2b_112(0xb20e, 14),
47 | blake2b_120(0xb20f, 15),
48 | blake2b_128(0xb210, 16),
49 | blake2b_136(0xb211, 17),
50 | blake2b_144(0xb212, 18),
51 | blake2b_152(0xb213, 19),
52 | blake2b_160(0xb214, 20),
53 | blake2b_168(0xb215, 21),
54 | blake2b_176(0xb216, 22),
55 | blake2b_184(0xb217, 23),
56 | blake2b_192(0xb218, 24),
57 | blake2b_200(0xb219, 25),
58 | blake2b_208(0xb21a, 26),
59 | blake2b_216(0xb21b, 27),
60 | blake2b_224(0xb21c, 28),
61 | blake2b_232(0xb21d, 29),
62 | blake2b_240(0xb21e, 30),
63 | blake2b_248(0xb21f, 31),
64 | blake2b_256(0xb220, 32),
65 | blake2b_264(0xb221, 33),
66 | blake2b_272(0xb222, 34),
67 | blake2b_280(0xb223, 35),
68 | blake2b_288(0xb224, 36),
69 | blake2b_296(0xb225, 37),
70 | blake2b_304(0xb226, 38),
71 | blake2b_312(0xb227, 39),
72 | blake2b_320(0xb228, 40),
73 | blake2b_328(0xb229, 41),
74 | blake2b_336(0xb22a, 42),
75 | blake2b_344(0xb22b, 43),
76 | blake2b_352(0xb22c, 44),
77 | blake2b_360(0xb22d, 45),
78 | blake2b_368(0xb22e, 46),
79 | blake2b_376(0xb22f, 47),
80 | blake2b_384(0xb230, 48),
81 | blake2b_392(0xb231, 49),
82 | blake2b_400(0xb232, 50),
83 | blake2b_408(0xb233, 51),
84 | blake2b_416(0xb234, 52),
85 | blake2b_424(0xb235, 53),
86 | blake2b_432(0xb236, 54),
87 | blake2b_440(0xb237, 55),
88 | blake2b_448(0xb238, 56),
89 | blake2b_456(0xb239, 57),
90 | blake2b_464(0xb23a, 58),
91 | blake2b_472(0xb23b, 59),
92 | blake2b_480(0xb23c, 60),
93 | blake2b_488(0xb23d, 61),
94 | blake2b_496(0xb23e, 62),
95 | blake2b_504(0xb23f, 63),
96 | blake2b_512(0xb240, 64),
97 |
98 | // blake2s (32 codes)
99 | blake2s_8(0xb241, 1),
100 | blake2s_16(0xb242, 2),
101 | blake2s_24(0xb243, 3),
102 | blake2s_32(0xb244, 4),
103 | blake2s_40(0xb245, 5),
104 | blake2s_48(0xb246, 6),
105 | blake2s_56(0xb247, 7),
106 | blake2s_64(0xb248, 8),
107 | blake2s_72(0xb249, 9),
108 | blake2s_80(0xb24a, 10),
109 | blake2s_88(0xb24b, 11),
110 | blake2s_96(0xb24c, 12),
111 | blake2s_104(0xb24d, 13),
112 | blake2s_112(0xb24e, 14),
113 | blake2s_120(0xb24f, 15),
114 | blake2s_128(0xb250, 16),
115 | blake2s_136(0xb251, 17),
116 | blake2s_144(0xb252, 18),
117 | blake2s_152(0xb253, 19),
118 | blake2s_160(0xb254, 20),
119 | blake2s_168(0xb255, 21),
120 | blake2s_176(0xb256, 22),
121 | blake2s_184(0xb257, 23),
122 | blake2s_192(0xb258, 24),
123 | blake2s_200(0xb259, 25),
124 | blake2s_208(0xb25a, 26),
125 | blake2s_216(0xb25b, 27),
126 | blake2s_224(0xb25c, 28),
127 | blake2s_232(0xb25d, 29),
128 | blake2s_240(0xb25e, 30),
129 | blake2s_248(0xb25f, 31),
130 | blake2s_256(0xb260, 32),
131 |
132 | // Murmur
133 | murmur3_x64_64(0x22, 8),
134 | murmur3_x64_128(0x1022, 16); // DRAFT status
135 |
136 | public final int index, length;
137 |
138 | Type(final int index, final int length) {
139 | this.index = index;
140 | this.length = length;
141 | }
142 |
143 | private static Map lookup = new HashMap<>();
144 | static {
145 | for (Type t: Type.values())
146 | lookup.put(t.index, t);
147 | }
148 |
149 | public static Type lookup(int t) {
150 | Type type = lookup.get(t);
151 | if (type == null)
152 | throw new IllegalStateException(String.format("Unknown Multihash type: 0x%x", t));
153 | return type;
154 | }
155 |
156 | }
157 |
158 | private final Type type;
159 | private final byte[] hash;
160 |
161 | public Multihash(Type type, byte[] hash) {
162 | if (hash.length > 127 && type != Type.id)
163 | throw new IllegalStateException("Unsupported hash size: "+hash.length);
164 | if (hash.length > MAX_IDENTITY_HASH_LENGTH)
165 | throw new IllegalStateException("Unsupported hash size: "+hash.length);
166 | if (hash.length != type.length && type != Type.id)
167 | throw new IllegalStateException("Incorrect hash length: " + hash.length + " != "+type.length);
168 | this.type = type;
169 | this.hash = hash;
170 | }
171 |
172 | public Multihash(Multihash toClone) {
173 | this(toClone.type, toClone.hash); // N.B. despite being a byte[], hash is immutable
174 | }
175 |
176 | public byte[] toBytes() {
177 | try {
178 | ByteArrayOutputStream res = new ByteArrayOutputStream();
179 | putUvarint(res, type.index);
180 | putUvarint(res, hash.length);
181 | res.write(hash);
182 | return res.toByteArray();
183 | } catch (IOException e) {
184 | throw new RuntimeException(e);
185 | }
186 | }
187 |
188 | public Type getType() {
189 | return type;
190 | }
191 |
192 | public byte[] getHash() {
193 | return Arrays.copyOf(hash, hash.length);
194 | }
195 |
196 | public void serialize(OutputStream out) {
197 | try {
198 | putUvarint(out, type.index);
199 | putUvarint(out, hash.length);
200 | out.write(hash);
201 | } catch (IOException e) {
202 | throw new RuntimeException(e);
203 | }
204 | }
205 |
206 | public Multihash bareMultihash() {
207 | return this;
208 | }
209 |
210 | public static Multihash deserialize(InputStream din) throws IOException {
211 | int type = (int)readVarint(din);
212 | int len = (int)readVarint(din);
213 | Type t = Type.lookup(type);
214 | byte[] hash = new byte[len];
215 | int total = 0;
216 | while (total < len) {
217 | int read = din.read(hash);
218 | if (read < 0)
219 | throw new EOFException();
220 | else
221 | total += read;
222 | }
223 | return new Multihash(t, hash);
224 | }
225 |
226 | public static Multihash deserialize(byte[] raw) {
227 | try {
228 | return deserialize(new ByteArrayInputStream(raw));
229 | } catch (IOException e) {
230 | throw new RuntimeException(e);
231 | }
232 | }
233 |
234 | /**
235 | *
236 | * @param encoded A multibase encoded serialization of a Multihash
237 | * @return
238 | * @throws IOException
239 | */
240 | public static Multihash decode(String encoded) {
241 | if (encoded.length() == 46 && encoded.startsWith("Qm"))
242 | return deserialize(Base58.decode(encoded));
243 | return deserialize(Multibase.decode(encoded));
244 | }
245 |
246 | @Override
247 | public String toString() {
248 | return toBase58();
249 | }
250 |
251 | @Override
252 | public boolean equals(Object o) {
253 | if (!(o instanceof Multihash))
254 | return false;
255 | return type == ((Multihash) o).type && Arrays.equals(hash, ((Multihash) o).hash);
256 | }
257 |
258 | @Override
259 | public int hashCode() {
260 | return Arrays.hashCode(hash) ^ type.hashCode();
261 | }
262 |
263 | public String toHex() {
264 | return Base16.encode(toBytes());
265 | }
266 |
267 | public String toBase58() {
268 | return Base58.encode(toBytes());
269 | }
270 |
271 | public static Multihash fromHex(String hex) {
272 | if (hex.length() % 2 != 0)
273 | throw new IllegalStateException("Odd number of hex digits!");
274 |
275 | try (ByteArrayOutputStream bout = new ByteArrayOutputStream()) {
276 | for (int i = 0; i < hex.length() - 1; i += 2)
277 | bout.write(Integer.valueOf(hex.substring(i, i + 2), 16));
278 | return Multihash.deserialize(bout.toByteArray());
279 | } catch (IOException e) {
280 | throw new IllegalStateException("Unable to handle Multihash conversion to Hex properly");
281 | }
282 | }
283 |
284 | public static Multihash fromBase58(String base58) {
285 | return Multihash.deserialize(Base58.decode(base58));
286 | }
287 |
288 | public static long readVarint(InputStream in) throws IOException {
289 | long x = 0;
290 | int s=0;
291 | for (int i=0; i < 10; i++) {
292 | int b = in.read();
293 | if (b < 0x80) {
294 | if (i == 9 && b > 1) {
295 | throw new IllegalStateException("Overflow reading varint!");
296 | }
297 | return x | (((long)b) << s);
298 | }
299 | x |= ((long)b & 0x7f) << s;
300 | s += 7;
301 | }
302 | throw new IllegalStateException("Varint too long!");
303 | }
304 |
305 | public static void putUvarint(OutputStream out, long x) throws IOException {
306 | while (x >= 0x80) {
307 | out.write((byte)(x | 0x80));
308 | x >>= 7;
309 | }
310 | out.write((byte)x);
311 | }
312 | }
313 |
--------------------------------------------------------------------------------
/src/test/java/io/ipfs/multihash/MultihashTest.java:
--------------------------------------------------------------------------------
1 | package io.ipfs.multihash;
2 |
3 | import io.ipfs.multibase.*;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.io.*;
7 | import java.security.MessageDigest;
8 | import java.util.Arrays;
9 | import java.util.List;
10 |
11 | import static org.junit.jupiter.api.Assertions.*;
12 |
13 | class MultihashTest {
14 |
15 | @Test
16 | void base58Test() {
17 | List examples = Arrays.asList("QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB",
18 | "QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy");
19 | for (String example: examples) {
20 | byte[] output = Base58.decode(example);
21 | String encoded = Base58.encode(output);
22 | assertEquals(example, encoded);
23 | }
24 | }
25 |
26 | @Test
27 | void decodeTest() throws IOException {
28 | List base58 = Arrays.asList(
29 | "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB",
30 | "QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy"
31 | );
32 | List base36 = Arrays.asList(
33 | "kmue2y4illvr0m3lt8x6z8iwghtxlzdmkjh957p5rr5cdr9243ugc",
34 | "kmuia3qyasz2z5cnz848bag5n5wfc7gzi35cz2npamtmkyifd5anu");
35 | for (int i=0; i < base58.size(); i++) {
36 | Multihash b58 = Multihash.decode(base58.get(i));
37 | Multihash b36 = Multihash.decode(base36.get(i));
38 | assertEquals(b58, b36);
39 | }
40 | }
41 |
42 | @Test
43 | void multihashTest() {
44 | Object[][] examples = new Object[][]{
45 | {Multihash.Type.id, "ID", "13hC12xCn", "hello"},
46 | {Multihash.Type.id, "ID", "11", ""},
47 | {Multihash.Type.md5, "MD5", "fzhnUYo18W8ewDBzLuzLqc9Twp", "hello world"},
48 | {Multihash.Type.sha1, "SHA-1", "5drNu81uhrFLRiS4bxWgAkpydaLUPW", "hello world"},
49 | {Multihash.Type.sha2_256, "SHA-256", "QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4", "hello world"},
50 | {Multihash.Type.sha2_512, "SHA-512", "8Vtkv2tdQ43bNGdWN9vNx9GVS9wrbXHk4ZW8kmucPmaYJwwedXir52kti9wJhcik4HehyqgLrQ1hBuirviLhxgRBNv", "hello world"},
51 | {Multihash.Type.sha3_512, "SHA3-512", "8tWhXW5oUwtPd9d3FnjuLP1NozN3vc45rmsoWEEfrZL1L6gi9dqi1YkZu5iHb2HJ8WbZaaKAyNWWRAa8yaxMkGKJmX", "hello world"}
52 | };
53 |
54 | for(Object[] ex: examples) {
55 | try {
56 | byte[] digest;
57 | if (ex[0] != Multihash.Type.id) {
58 | MessageDigest md = MessageDigest.getInstance((String) ex[1]);
59 | assertNotNull(md);
60 | md.update(((String) ex[3]).getBytes("UTF-8"));
61 | digest = md.digest();
62 | } else
63 | digest = ((String) ex[3]).getBytes("UTF-8");
64 | // Test constructor
65 | Multihash m2 = new Multihash((Multihash.Type)ex[0], digest);
66 | Multihash m = Multihash.fromBase58((String)ex[2]);
67 | // Test comparison
68 | assertEquals(m, m2);
69 | // Test conversions
70 | assertEquals(m.toBase58(), m2.toBase58());
71 | assertEquals(m.toBase58(), ex[2]);
72 | // Test fromHex and toHex
73 | Multihash m3 = Multihash.fromHex(m.toHex());
74 | assertEquals(m, m3);
75 | }
76 | catch (Exception e){
77 | System.out.println(e.getMessage());
78 | assertTrue(false);
79 | }
80 | }
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------