package peergos.shared.io.ipfs.multihash; import peergos.shared.io.ipfs.multibase.*; import java.io.*; import java.util.*; public class Multihash { public enum Type { sha1(0x11, 20), sha2_256(0x12, 32), sha2_512(0x13, 64), sha3(0x14, 64), blake2b(0x40, 64), blake2s(0x41, 32); public int index, length; Type(int index, int length) { this.index = index; this.length = length; } private static Map<Integer, Type> lookup = new TreeMap<>(); static { for (Type t: Type.values()) lookup.put(t.index, t); } public static Type lookup(int t) { if (!lookup.containsKey(t)) throw new IllegalStateException("Unknown Multihash type: "+t); return lookup.get(t); } } public final Type type; private final byte[] hash; public Multihash(Type type, byte[] hash) { if (hash.length > 127) throw new IllegalStateException("Unsupported hash size: "+hash.length); if (hash.length != type.length) throw new IllegalStateException("Incorrect hash length: " + hash.length + " != "+type.length); this.type = type; this.hash = hash; } public Multihash(Multihash toClone) { this(toClone.type, toClone.hash); // N.B. despite being a byte[], hash is immutable } public Multihash(byte[] multihash) { this(Type.lookup(multihash[0] & 0xff), Arrays.copyOfRange(multihash, 2, multihash.length)); } public byte[] toBytes() { byte[] res = new byte[hash.length+2]; res[0] = (byte)type.index; res[1] = (byte)hash.length; System.arraycopy(hash, 0, res, 2, hash.length); return res; } public void serialize(DataOutput dout) throws IOException { dout.write(toBytes()); } public static Multihash deserialize(DataInput din) throws IOException { int type = din.readUnsignedByte(); int len = din.readUnsignedByte(); Type t = Type.lookup(type); byte[] hash = new byte[len]; din.readFully(hash); return new Multihash(t, hash); } @Override public String toString() { return toBase58(); } @Override public boolean equals(Object o) { if (!(o instanceof Multihash)) return false; return type == ((Multihash) o).type && Arrays.equals(hash, ((Multihash) o).hash); } @Override public int hashCode() { return Arrays.hashCode(hash) ^ type.hashCode(); } public String toBase58() { return Base58.encode(toBytes()); } public static Multihash fromBase58(String base58) { return new Multihash(Base58.decode(base58)); } }