Last active
November 11, 2017 17:15
-
-
Save zmitton/3c30b9cf4a99bc44c44ba13c3eae6cca to your computer and use it in GitHub Desktop.
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
import java.util.Arrays; | |
import java.util.LinkedList; | |
import javax.xml.bind.DatatypeConverter; | |
import java.lang.Byte; | |
import java.math.BigInteger; | |
class partial{ | |
partial(Object body, int pointer){ | |
this.body = body; | |
this.pointer = pointer; | |
} | |
Object body; | |
int pointer; | |
} | |
class Tuple { | |
public Rlp body; | |
public int pointer; | |
public Tuple(Rlp body, int pointer) { | |
this.body = body; | |
this.pointer = pointer; | |
} | |
} | |
public class Rlp { | |
static final int THRESHOLD = 0x37; //maximum length that can be encoded in a single byte | |
static final int STRING_OFFSET = 0x80; | |
static final int LIST_OFFSET = 0xc0; | |
public boolean isList; | |
public byte[] bytes; | |
public LinkedList<Rlp> items; | |
public Rlp(LinkedList<Rlp> items){ | |
this.isList = true; | |
this.items = items; | |
} | |
public Rlp(byte[] bytes){ this.bytes = bytes; } | |
public Rlp(String str){ this.bytes = str.getBytes(); } | |
public Rlp(byte character){ this.bytes = new byte[]{character}; } | |
public Rlp get(int index){ return this.items.get(index); } | |
public int size(){ return this.items.size(); } | |
public static Rlp decode(byte[] input){ | |
return decodeOne(input).body; | |
} | |
static Tuple decodeOne(byte[] input){ | |
int pref = Byte.toUnsignedInt(input[0]); | |
if(pref < STRING_OFFSET){ | |
System.out.println("here:"); | |
return new Tuple(new Rlp(input[0]), 1); | |
// return new Tuple(new Rlp(new byte[]{Arrays.copyOfRange(input, 0, 1)}, 1)); | |
} | |
else if(pref < STRING_OFFSET+THRESHOLD){ | |
return new Tuple(new Rlp(Arrays.copyOfRange(input, 1, 1+pref-STRING_OFFSET)), 1+pref-STRING_OFFSET); | |
} | |
else if(input[0] < LIST_OFFSET){ | |
int lenlen = pref - STRING_OFFSET - THRESHOLD; | |
int len = 0; | |
for (int i = 1 ; i <= lenlen ; i++) { | |
len += Byte.toUnsignedInt(input[i])*(256^(lenlen-i)); | |
} | |
return new Tuple(new Rlp(Arrays.copyOfRange(input, lenlen+1, 1+lenlen+len)), 1+lenlen+len); | |
}else if(pref < LIST_OFFSET+THRESHOLD){ | |
// return new Rlp(decodeMany(Arrays.copyOfRange(input, 1,1+pref-LIST_OFFSET)), 1+pref-LIST_OFFSET); | |
// }else{ | |
// int lenlen = pref - LIST_OFFSET - THRESHOLD; | |
// int len = bToI(input, 1, lenlen); | |
// return new Rlp(decodeMany(Arrays.copyOfRange(input, 1+lenlen, 1+lenlen+len)), 1+lenlen+len); | |
//temp city ^^ | |
} | |
return new Tuple(new Rlp(Arrays.copyOfRange(input, 1, 1+pref-STRING_OFFSET)), 1+pref-STRING_OFFSET); | |
} | |
static LinkedList<Object> decodeMany(byte[] input){ | |
LinkedList output = new LinkedList(); | |
int pointer = 0; | |
while(pointer < input.length){ | |
Tuple next = decodeOne(Arrays.copyOfRange(input, pointer, input.length)); | |
output.push(next.body); | |
pointer += next.pointer; | |
} | |
return output; | |
} | |
public static byte[] encode(Rlp input){ | |
// System.out.println("HERE"); | |
// return new byte[]{ (byte)0x61}; | |
if(!input.isList){ // string | |
int length = input.bytes.length; | |
if(length == 1 && input.bytes[0] < STRING_OFFSET){ | |
return new byte[]{input.bytes[0]}; | |
} | |
byte[] pref = encodeLength(length, STRING_OFFSET); | |
return concat(pref, input.bytes); | |
} | |
else{ // list | |
byte[] output = new byte[]{}; | |
for (int i = 0 ; i < input.size(); i++) { | |
byte[] encodedItem = encode(input.items.get(i)); | |
// System.out.println("temp1 output: " + DatatypeConverter.printHexBinary(output)); | |
int tempLength = output.length; | |
output = Arrays.copyOfRange(output,0,output.length + encodedItem.length); | |
// System.out.println("temp output: " + ouput); | |
// System.out.println("temp2 output: " + DatatypeConverter.printHexBinary(output)); | |
// System.out.println("temp2 encodedItem: " + DatatypeConverter.printHexBinary(encodedItem)); | |
System.arraycopy(encodedItem, 0, output, tempLength, encodedItem.length); | |
// System.out.println("temp3 output: " + DatatypeConverter.printHexBinary(output)); | |
} | |
byte[] prefix = encodeLength(output.length, LIST_OFFSET); | |
return concat(prefix, output); | |
// var output = new Buffer('') | |
// for (var i = 0; i < input.length; i++) { | |
// output = Buffer.concat([output, encode(input[i])]) | |
// } | |
// return Buffer.concat([encodeLength(output.length, LIST_OFFSET), output]) | |
// return new byte[]{ (byte)0x83 }; | |
} | |
} | |
public static byte[] encode(byte[] input){ return encode(new Rlp(input)); } | |
public static byte[] encode(String str){ return encode(new Rlp(str)); } | |
public String toString(){ | |
if(this.isList){ | |
String str = ""; | |
str += "["; | |
for(int i = 0 ; i < this.size() ; i++){ | |
str += this.items.get(i).toString(); | |
} | |
return str + "]"; | |
} | |
else{ | |
return new String(this.bytes); | |
} | |
} | |
static byte[] encodeLength(int length, int offset){ | |
if(length <= THRESHOLD){ | |
return numToBytes(length + offset); | |
}else{ | |
byte[] len = numToBytes(length); | |
byte[] lenlen = numToBytes(len.length + offset + THRESHOLD); | |
return concat(lenlen, len); | |
} | |
//test this | |
} | |
static int bToI(byte[] input, int offset, int byteLength){ | |
byte[] output = Arrays.copyOfRange(input, offset, offset+byteLength); | |
return Integer.parseInt(DatatypeConverter.printHexBinary(output), 16); | |
} | |
static byte[] numToBytes(int num){ | |
if(num == 0){ | |
return new byte[]{}; | |
}else if(num < 256){ | |
return new byte[]{ (byte)(num) }; | |
}else if(num < 65536){ | |
return new byte[]{ (byte)(num >>> 8),(byte)num }; | |
}else if(num < 16777216){ | |
return new byte[]{ (byte)(num >>> 16),(byte)(num >>> 8),(byte)num }; | |
}else{ // up to 2,147,483,647 | |
return new byte[]{ (byte)(num >>> 24),(byte)(num >>> 16),(byte)(num >>> 8),(byte)num }; | |
} | |
} | |
static byte[] concat(byte[] prefix, byte[] suffix){ | |
byte[] output = new byte[prefix.length + suffix.length]; | |
System.arraycopy(prefix, 0, output, 0, prefix.length); | |
System.arraycopy(suffix, 0, output, prefix.length, suffix.length); | |
return output; | |
} | |
//test stuff below | |
public static void main(String[] args) { | |
// byte[] sampleBytes = new byte[]{ (byte)0xC5,(byte)0x82,(byte)0x7A,(byte)0x61,(byte)0xC1,(byte)0x63,} ; //encode of [za[c]] | |
// System.out.println(Rlp.decode(sampleBytes)); | |
// byte[] encoded = encode(sampleBytes); | |
// System.out.println("in: " + DatatypeConverter.printHexBinary(sampleBytes)); | |
// System.out.println("out: " + DatatypeConverter.printHexBinary(encoded)); | |
// byte[] sampleBytes = new byte[]{ (byte)0x7a } ; //rlp('z') | |
// System.out.println("in: " + DatatypeConverter.printHexBinary(sampleBytes)); | |
// byte[] rlpZA = new byte[]{ (byte)0x7a,(byte)0x61}; | |
// byte[] rlpC = new byte[]{ (byte)0x61}; | |
byte[] rlpzac = Rlp.encode("zac"); | |
System.out.println("encoded zac: " + DatatypeConverter.printHexBinary(rlpzac)); | |
Rlp ZA = new Rlp(new byte[]{ (byte)0x7a,(byte)0x61}); | |
Rlp C = new Rlp(new byte[]{ (byte)0x63}); | |
LinkedList<Rlp> temp1 = new LinkedList<Rlp>(); | |
temp1.add(C); | |
Rlp CArray = new Rlp(temp1); | |
LinkedList<Rlp> temp2 = new LinkedList<Rlp>(); | |
temp2.add(ZA); | |
temp2.add(CArray); | |
Rlp total = new Rlp(temp2); | |
System.out.println("total: " + total); | |
byte[] encodedTotal = Rlp.encode(total); | |
System.out.println("encoded total: " + DatatypeConverter.printHexBinary(encodedTotal)); | |
// numToBytes(2000000000); | |
// Rlp rlp = new Rlp(sampleBytes); | |
// Rlp output = decode(sampleBytes); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment