-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
949b802
commit bd2b816
Showing
9 changed files
with
305 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,8 @@ | ||
*.class | ||
|
||
# Mobile Tools for Java (J2ME) | ||
.mtj.tmp/ | ||
|
||
# Package Files # | ||
*.jar | ||
*.war | ||
*.ear | ||
build/** | ||
dist/** | ||
.idea/** | ||
|
||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | ||
hs_err_pid* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,8 @@ | ||
# java-multihash | ||
A Java implementation of Multihash | ||
|
||
## Usage | ||
Multihash m = Multihash.fromBase58("QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy"); | ||
|
||
## Compilation | ||
To compile just run ant. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<project name="java-multihash" default="dist" basedir="."> | ||
<description> | ||
Java Multihash | ||
</description> | ||
|
||
<property name="src" location="src"/> | ||
<property name="build" location="build"/> | ||
<property name="dist" location="dist"/> | ||
|
||
<path id="dep.runtime"> | ||
<fileset dir="./lib"> | ||
<include name="**/*.jar" /> | ||
</fileset> | ||
</path> | ||
|
||
<target name="init"> | ||
<mkdir dir="${build}"/> | ||
</target> | ||
|
||
<target name="compile" depends="init" description="compile the source"> | ||
<javac includeantruntime="false" srcdir="${src}" destdir="${build}" debug="true" debuglevel="lines,vars,source"> | ||
<classpath> | ||
<fileset dir="lib"> | ||
<include name="**/*.jar" /> | ||
</fileset> | ||
</classpath> | ||
</javac> | ||
</target> | ||
|
||
<target name="dist" depends="compile" description="generate the distribution"> | ||
<mkdir dir="${dist}/lib"/> | ||
<copy todir="${dist}/lib"> | ||
<fileset dir="lib"/> | ||
</copy> | ||
<manifestclasspath property="manifest_cp" jarfile="myjar.jar"> | ||
<classpath refid="dep.runtime" /> | ||
</manifestclasspath> | ||
<jar jarfile="${dist}/Multihash.jar" basedir="${build}"> | ||
<manifest> | ||
<attribute name="Class-Path" value="${manifest_cp}"/> | ||
</manifest> | ||
<fileset dir="."> | ||
<include name="**/ui/**"/> | ||
<exclude name="out/**"/> | ||
<exclude name="ui/doppio/**"/> | ||
<exclude name="ui/PeergosServer.jar"/> | ||
</fileset> | ||
</jar> | ||
<copy todir="."> | ||
<fileset file="${dist}/Multihash.jar"/> | ||
</copy> | ||
</target> | ||
|
||
|
||
<target name="test" depends="compile,dist"> | ||
<junit printsummary="yes" fork="true" haltonfailure="yes"> | ||
<jvmarg value="-Xmx1g"/> | ||
<classpath> | ||
<pathelement location="lib/junit-4.11.jar" /> | ||
<pathelement location="lib/hamcrest-core-1.3.jar" /> | ||
<pathelement location="Multihash.jar" /> | ||
</classpath> | ||
<test name="org.ipfs.api.MultihashTests" haltonfailure="yes"> | ||
<formatter type="plain"/> | ||
<formatter type="xml"/> | ||
</test> | ||
</junit> | ||
</target> | ||
|
||
<target name="clean" description="clean up"> | ||
<delete dir="${build}"/> | ||
<delete dir="${dist}"/> | ||
</target> | ||
</project> |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package org.ipfs.api; | ||
|
||
/** | ||
* Copyright 2011 Google Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
import java.math.BigInteger; | ||
|
||
/** | ||
* A custom form of base58 is used to encode BitCoin addresses. Note that this is not the same base58 as used by | ||
* Flickr, which you may see reference to around the internet.<p> | ||
* | ||
* Satoshi says: why base-58 instead of standard base-64 encoding?<p> | ||
* | ||
* <ul> | ||
* <li>Don't want 0OIl characters that look the same in some fonts and | ||
* could be used to create visually identical looking account numbers.</li> | ||
* <li>A string with non-alphanumeric characters is not as easily accepted as an account number.</li> | ||
* <li>E-mail usually won't line-break if there's no punctuation to break at.</li> | ||
* <li>Doubleclicking selects the whole number as one word if it's all alphanumeric.</li> | ||
* </ul> | ||
*/ | ||
public class Base58 { | ||
private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | ||
private static final BigInteger BASE = BigInteger.valueOf(58); | ||
|
||
public static String encode(byte[] input) { | ||
// TODO: This could be a lot more efficient. | ||
BigInteger bi = new BigInteger(1, input); | ||
StringBuffer s = new StringBuffer(); | ||
while (bi.compareTo(BASE) >= 0) { | ||
BigInteger mod = bi.mod(BASE); | ||
s.insert(0, ALPHABET.charAt(mod.intValue())); | ||
bi = bi.subtract(mod).divide(BASE); | ||
} | ||
s.insert(0, ALPHABET.charAt(bi.intValue())); | ||
// Convert leading zeros too. | ||
for (byte anInput : input) { | ||
if (anInput == 0) | ||
s.insert(0, ALPHABET.charAt(0)); | ||
else | ||
break; | ||
} | ||
return s.toString(); | ||
} | ||
|
||
public static byte[] decode(String input) { | ||
byte[] bytes = decodeToBigInteger(input).toByteArray(); | ||
// We may have got one more byte than we wanted, if the high bit of the next-to-last byte was not zero. This | ||
// is because BigIntegers are represented with twos-compliment notation, thus if the high bit of the last | ||
// byte happens to be 1 another 8 zero bits will be added to ensure the number parses as positive. Detect | ||
// that case here and chop it off. | ||
boolean stripSignByte = bytes.length > 1 && bytes[0] == 0 && bytes[1] < 0; | ||
// Count the leading zeros, if any. | ||
int leadingZeros = 0; | ||
for (int i = 0; input.charAt(i) == ALPHABET.charAt(0); i++) { | ||
leadingZeros++; | ||
} | ||
// Now cut/pad correctly. Java 6 has a convenience for this, but Android can't use it. | ||
byte[] tmp = new byte[bytes.length - (stripSignByte ? 1 : 0) + leadingZeros]; | ||
System.arraycopy(bytes, stripSignByte ? 1 : 0, tmp, leadingZeros, tmp.length - leadingZeros); | ||
return tmp; | ||
} | ||
|
||
public static BigInteger decodeToBigInteger(String input) { | ||
BigInteger bi = BigInteger.valueOf(0); | ||
// Work backwards through the string. | ||
for (int i = input.length() - 1; i >= 0; i--) { | ||
int alphaIndex = ALPHABET.indexOf(input.charAt(i)); | ||
if (alphaIndex == -1) { | ||
throw new IllegalStateException("Illegal character " + input.charAt(i) + " at " + i); | ||
} | ||
bi = bi.add(BigInteger.valueOf(alphaIndex).multiply(BASE.pow(input.length() - 1 - i))); | ||
} | ||
return bi; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package org.ipfs.api; | ||
|
||
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(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 toHex() { | ||
StringBuilder res = new StringBuilder(); | ||
for (byte b: toBytes()) | ||
res.append(String.format("%x", b&0xff)); | ||
return res.toString(); | ||
} | ||
|
||
public String toBase58() { | ||
return Base58.encode(toBytes()); | ||
} | ||
|
||
public static Multihash fromHex(String hex) { | ||
if (hex.length() % 2 != 0) | ||
throw new IllegalStateException("Uneven number of hex digits!"); | ||
ByteArrayOutputStream bout = new ByteArrayOutputStream(); | ||
for (int i=0; i < hex.length()-1; i+= 2) | ||
bout.write(Integer.valueOf(hex.substring(i, i+2), 16)); | ||
return new Multihash(bout.toByteArray()); | ||
} | ||
|
||
public static Multihash fromBase58(String base58) { | ||
return new Multihash(Base58.decode(base58)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.ipfs.api; | ||
|
||
import org.junit.*; | ||
|
||
import java.util.*; | ||
|
||
public class MultihashTests { | ||
|
||
@Test | ||
public void base58Test() { | ||
List<String> examples = Arrays.asList("QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB", | ||
"QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy"); | ||
for (String example: examples) { | ||
byte[] output = Base58.decode(example); | ||
String encoded = Base58.encode(output); | ||
if (!encoded.equals(encoded)) | ||
throw new IllegalStateException("Incorrect base58! " + example + " => " + encoded); | ||
} | ||
} | ||
} |