package org.ethereum.net.rlpx;

import org.ethereum.crypto.ECKey;
import org.spongycastle.math.ec.ECPoint;
import org.spongycastle.util.BigIntegers;
import org.spongycastle.util.encoders.Hex;

import java.util.Arrays;

import static org.ethereum.util.ByteUtil.merge;

/**
 * Authentication initiation message, to be wrapped inside
 *
 * Created by devrandom on 2015-04-07.
 */
public class AuthInitiateMessage {
    ECKey.ECDSASignature signature; // 65 bytes
    byte[] ephemeralPublicHash; // 32 bytes
    ECPoint publicKey; // 64 bytes - uncompressed and no type byte
    byte[] nonce; // 32 bytes
    boolean isTokenUsed; // 1 byte - 0x00 or 0x01

    public AuthInitiateMessage() {
    }

    public static int getLength() {
        return 65+32+64+32+1;
    }

    static AuthInitiateMessage decode(byte[] wire) {
        AuthInitiateMessage message = new AuthInitiateMessage();
        int offset = 0;
        byte[] r = new byte[32];
        byte[] s = new byte[32];
        System.arraycopy(wire, offset, r, 0, 32);
        offset += 32;
        System.arraycopy(wire, offset, s, 0, 32);
        offset += 32;
        int v = wire[offset] + 27;
        offset += 1;
        message.signature = ECKey.ECDSASignature.fromComponents(r, s, (byte)v);
        message.ephemeralPublicHash = new byte[32];
        System.arraycopy(wire, offset, message.ephemeralPublicHash, 0, 32);
        offset += 32;
        byte[] bytes = new byte[65];
        System.arraycopy(wire, offset, bytes, 1, 64);
        offset += 64;
        bytes[0] = 0x04; // uncompressed
        message.publicKey = ECKey.CURVE.getCurve().decodePoint(bytes);
        message.nonce = new byte[32];
        System.arraycopy(wire, offset, message.nonce, 0, 32);
        offset += message.nonce.length;
        byte tokenUsed = wire[offset];
        offset += 1;
        if (tokenUsed != 0x00 && tokenUsed != 0x01)
            throw new RuntimeException("invalid boolean"); // TODO specific exception
        message.isTokenUsed = (tokenUsed == 0x01);
        return message;
    }

    public byte[] encode() {
        // FIXME does this code generate a constant length for each item?
        byte[] sigBytes = merge(BigIntegers.asUnsignedByteArray(signature.r),
                BigIntegers.asUnsignedByteArray(signature.s), new byte[]{EncryptionHandshake.recIdFromSignatureV(signature.v)});

        byte[] buffer = new byte[getLength()];
        int offset = 0;
        System.arraycopy(sigBytes, 0, buffer, offset, sigBytes.length);
        offset += sigBytes.length;
        System.arraycopy(ephemeralPublicHash, 0, buffer, offset, ephemeralPublicHash.length);
        offset += ephemeralPublicHash.length;
        byte[] publicBytes = publicKey.getEncoded(false);
        System.arraycopy(publicBytes, 1, buffer, offset, publicBytes.length - 1);
        offset += publicBytes.length - 1;
        System.arraycopy(nonce, 0, buffer, offset, nonce.length);
        offset += nonce.length;
        buffer[offset] = (byte)(isTokenUsed ? 0x01 : 0x00);
        offset += 1;
        return buffer;
    }

    @Override
    public String toString() {

        byte[] sigBytes = merge(BigIntegers.asUnsignedByteArray(signature.r),
                BigIntegers.asUnsignedByteArray(signature.s), new byte[]{EncryptionHandshake.recIdFromSignatureV(signature.v)});

        return "AuthInitiateMessage{" +
                "\n  sigBytes=" + Hex.toHexString(sigBytes) +
                "\n  ephemeralPublicHash=" + Hex.toHexString(ephemeralPublicHash) +
                "\n  publicKey=" + Hex.toHexString(publicKey.getEncoded(false)) +
                "\n  nonce=" + Hex.toHexString(nonce) +
                "\n}";
    }
}

@@ -259,16 +259,85 @@
 l.merge;
+%0Aimport static org.spongycastle.util.BigIntegers.asUnsignedByteArray;
 %0A%0A/**%0A *
@@ -760,23 +760,16 @@
  %7D%0A%0A    
-public 
 static i
@@ -2134,24 +2134,25 @@
 ode() %7B%0A
+%0A
         
 // FIXME
@@ -2147,73 +2147,182 @@
     
-// FIXME does this code generate a constant length for each item?
+byte%5B%5D rsigPad = new byte%5B32%5D;%0A        byte%5B%5D rsig = asUnsignedByteArray(signature.r);%0A        System.arraycopy(rsig, 0, rsigPad, rsigPad.length - rsig.length, rsig.length);%0A
 %0A   
@@ -2337,37 +2337,54 @@
 e%5B%5D 
+s
 sig
-Bytes = merge(BigIntegers.
+Pad = new byte%5B32%5D;%0A        byte%5B%5D ssig = 
 asUn
@@ -2401,35 +2401,35 @@
 Array(signature.
-r),
+s);
 %0A               
@@ -2425,60 +2425,136 @@
     
-        BigIntegers.asUnsignedByteArray(signature.s)
+System.arraycopy(ssig, 0, ssigPad, ssigPad.length - ssig.length, ssig.length);%0A%0A        byte%5B%5D sigBytes = merge(rsigPad, ssigPad
 , ne
@@ -3406,28 +3406,16 @@
 = merge(
-BigIntegers.
 asUnsign
@@ -3456,28 +3456,16 @@
         
-BigIntegers.
 asUnsign

Fix pading to 64 length signatures (r31+s32+v1)