diff --git a/app/src/main/java/io/github/chronosx88/yggdrasil/address/NodeID.java b/app/src/main/java/io/github/chronosx88/yggdrasil/address/NodeID.java new file mode 100644 index 0000000..c09a560 --- /dev/null +++ b/app/src/main/java/io/github/chronosx88/yggdrasil/address/NodeID.java @@ -0,0 +1,45 @@ +package io.github.chronosx88.yggdrasil.address; + +import androidx.annotation.NonNull; + +public class NodeID { + public static final short NODEID_LENGTH = 64; // SHA512 size + private byte[] bytes; + + public NodeID(String hex) { + bytes = Utils.hexToBytes(hex); + } + + public byte[] getBytes() { + return bytes; + } + + @NonNull + @Override + public String toString() { + return Utils.bytesToHex(bytes); + } + + private static class Utils { + private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); + private static String bytesToHex(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = HEX_ARRAY[v >>> 4]; + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + } + return new String(hexChars); + } + + private static byte[] hexToBytes(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i+1), 16)); + } + return data; + } + } +} diff --git a/app/src/main/java/io/github/chronosx88/yggdrasil/address/YggAddress.java b/app/src/main/java/io/github/chronosx88/yggdrasil/address/YggAddress.java new file mode 100644 index 0000000..4eb7b9c --- /dev/null +++ b/app/src/main/java/io/github/chronosx88/yggdrasil/address/YggAddress.java @@ -0,0 +1,54 @@ +package io.github.chronosx88.yggdrasil.address; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +public class YggAddress { + private static final short IPV6_ADDRESS_LENGTH = 16; // represents an IPv6 address in the yggdrasil address range. + private static final short IPV6_SUBNET_LENGTH = 16; // represents an IPv6 /64 subnet in the yggdrasil subnet range. + + private byte[] addressBytes; + private InetAddress address; + + public YggAddress(NodeID nodeID) { + addressBytes = new byte[IPV6_ADDRESS_LENGTH]; + List temp = new ArrayList<>(); + boolean done = false; + byte ones = 0; + byte bits = 0; + byte nBits = 0; + for(int idx = 0; idx < 8 * nodeID.getBytes().length; idx++) { + byte bit = (byte) ((nodeID.getBytes()[idx/8] & (0x80 >> (byte)(idx%8))) >> (byte)(7-(idx%8))); + if(!done && bit != 0) { + ones++; + continue; + } + if(!done && bit == 0) { + done = true; + continue; + } + bits = (byte) ((bits << 1) | bit); + nBits++; + if(nBits == 8) { + nBits = 0; + temp.add(bits); + } + } + + byte[] prefix = getPrefix(); + System.arraycopy(prefix, 0, addressBytes, 0, prefix.length); + addressBytes[prefix.length] = ones; + System.arraycopy(temp.toArray(new Byte[0]), 0, addressBytes, prefix.length+1, temp.size()); + try { + address = InetAddress.getByAddress(addressBytes); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + } + + public static byte[] getPrefix() { + return new byte[]{0x02}; + } +} \ No newline at end of file