Skip to content

Instantly share code, notes, and snippets.

@zmitton
Last active November 11, 2017 17:15
Show Gist options
  • Save zmitton/3c30b9cf4a99bc44c44ba13c3eae6cca to your computer and use it in GitHub Desktop.
Save zmitton/3c30b9cf4a99bc44c44ba13c3eae6cca to your computer and use it in GitHub Desktop.
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