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));
}
}