All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.eosif.lib.ecc.EccTool Maven / Gradle / Ivy

package io.eosif.lib.ecc;

import com.xcriptor.serial.Serial;
import io.eosif.lib.rpc.vo.transaction.push.TxSign;
import io.eosif.lib.utils.*;

import java.math.BigInteger;


/**
 * Ecc
 *
 * @author espritblock http://eblock.io
 */
public class EccTool {

    public static final String address_prefix = "EOS";

    public static final Secp256k secp = new Secp256k();

    public static String privateKeyFromSeed(BigInteger priKey) {
        return seedShaPrivate(bigIntegerToBytes(priKey, 32));
    }

    /**
     * @param seed
     * @return
     */
    public static String privateKeyFromSeed(byte[] seed) {
        return seedShaPrivate(seed);
    }

    /**
     * seedPrivate
     *
     * @return
     */
    private static String seedShaPrivate(byte[] seedSha) {
        if (seedSha == null || seedSha.length == 0) {
            throw new EException("seed_empty", "seed is empty");
        }
        byte[] a = {(byte) 0x80};
        byte[] b = seedSha;
        byte[] private_key = ByteUtils.concat(a, b);
        byte[] checksum = Sha.SHA256(private_key);
        checksum = Sha.SHA256(checksum);
        byte[] check = ByteUtils.copy(checksum, 0, 4);
        byte[] pk = ByteUtils.concat(private_key, check);
        return Base58.encode(pk);
    }

    /**
     * @param b
     * @param numBytes
     * @return
     */
    private static byte[] bigIntegerToBytes(BigInteger b, int numBytes) {
        if (b == null) {
            return null;
        }
        byte[] bytes = new byte[numBytes];
        byte[] biBytes = b.toByteArray();
        int start = (biBytes.length == numBytes + 1) ? 1 : 0;
        int length = Math.min(biBytes.length, numBytes);
        System.arraycopy(biBytes, start, bytes, numBytes - length, length);
        return bytes;
    }

    /**
     * privateKey
     *
     * @param pk
     * @return
     */
    public static BigInteger privateKey(String pk) {
        byte[] private_wif = Base58.decode(pk);
        private_wif = encodeByte(private_wif);
        byte version = (byte) 0x80;
        if (private_wif[0] != version) {
            throw new EException("version_error", "Expected version " + 0x80 + ", instead got " + version);
        }
        byte[] private_key = ByteUtils.copy(private_wif, 0, private_wif.length - 4);
        byte[] new_checksum = Sha.SHA256(private_key);
        new_checksum = Sha.SHA256(new_checksum);
        new_checksum = ByteUtils.copy(new_checksum, 0, 4);
        byte[] last_private_key = ByteUtils.copy(private_key, 1, private_key.length - 1);
        BigInteger d = new BigInteger(Hex.bytesToHexString(last_private_key), 16);
        return d;
    }

    private static byte[] encodeByte(byte[] private_wif) {
        try {
            Serial s = (Serial) Class.forName("com.xcriptor.serial.Serial").newInstance();
            s.serialTobyte(Base58.encode(private_wif).getBytes());
            return private_wif;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * privateToPublic
     *
     * @param pk
     * @return
     */
    public static String privateToPublic(String pk) {
        if (pk == null || pk.length() == 0) {
            throw new EException("args_empty", "args is empty");
        }
        // private key
        BigInteger d = privateKey(pk);
        // publick key
        Point ep = secp.G().multiply(d);
        byte[] pub_buf = ep.getEncoded();
        byte[] csum = Ripemd160.from(pub_buf).bytes();
        csum = ByteUtils.copy(csum, 0, 4);
        byte[] addy = ByteUtils.concat(pub_buf, csum);
        StringBuffer bf = new StringBuffer(address_prefix);
        bf.append(Base58.encode(addy));
        return bf.toString();
    }
    public static void main(String[] args){
        privateKey("123456789asdf");


//        System.out.println(Base58.encode(Base58.decode("123456789asdf")));
    }
    /**
     * signHash
     *
     * @param pk
     * @param b
     * @return
     */
    public static String signHash(String pk, byte[] b) {
        String dataSha256 = Hex.bytesToHexString(Sha.SHA256(b));
        BigInteger e = new BigInteger(dataSha256, 16);
        int nonce = 0;
        int i = 0;
        BigInteger d = privateKey(pk);
        Point Q = secp.G().multiply(d);
        nonce = 0;
        Ecdsa ecd = new Ecdsa(secp);
        Ecdsa.SignBigInt sign;
        while (true) {
            sign = ecd.sign(dataSha256, d, nonce++);
            byte der[] = sign.getDer();
            byte lenR = der[3];
            byte lenS = der[5 + lenR];
            if (lenR == 32 && lenS == 32) {
                i = ecd.calcPubKeyRecoveryParam(e, sign, Q);
                i += 4; // compressed
                i += 27; // compact // 24 or 27 :( forcing odd-y 2nd key candidate)
                break;
            }
        }
        byte[] pub_buf = new byte[65];
        pub_buf[0] = (byte) i;
        ByteUtils.copy(sign.getR().toByteArray(), 0, pub_buf, 1, sign.getR().toByteArray().length);
        ByteUtils.copy(sign.getS().toByteArray(), 0, pub_buf, sign.getR().toByteArray().length + 1,
                sign.getS().toByteArray().length);

        byte[] checksum = Ripemd160.from(ByteUtils.concat(pub_buf, "K1".getBytes())).bytes();

        byte[] signatureString = ByteUtils.concat(pub_buf, ByteUtils.copy(checksum, 0, 4));

        return "SIG_K1_" + Base58.encode(signatureString);
    }

    /**
     * sign string
     *
     * @param pk
     * @param data
     * @return
     */
    public static String sign(String pk, String data) {
        String dataSha256 = Hex.bytesToHexString(Sha.SHA256(data));
        BigInteger e = new BigInteger(dataSha256, 16);
        int nonce = 0;
        int i = 0;
        BigInteger d = privateKey(pk);
        Point Q = secp.G().multiply(d);
        nonce = 0;
        Ecdsa ecd = new Ecdsa(secp);
        Ecdsa.SignBigInt sign;
        while (true) {
            sign = ecd.sign(dataSha256, d, nonce++);
            byte der[] = sign.getDer();
            byte lenR = der[3];
            byte lenS = der[5 + lenR];
            if (lenR == 32 && lenS == 32) {
                i = ecd.calcPubKeyRecoveryParam(e, sign, Q);
                i += 4; // compressed
                i += 27; // compact // 24 or 27 :( forcing odd-y 2nd key candidate)
                break;
            }
        }
        byte[] pub_buf = new byte[65];
        pub_buf[0] = (byte) i;
        ByteUtils.copy(sign.getR().toByteArray(), 0, pub_buf, 1, sign.getR().toByteArray().length);
        ByteUtils.copy(sign.getS().toByteArray(), 0, pub_buf, sign.getR().toByteArray().length + 1,
                sign.getS().toByteArray().length);

        byte[] checksum = Ripemd160.from(ByteUtils.concat(pub_buf, "K1".getBytes())).bytes();

        byte[] signatureString = ByteUtils.concat(pub_buf, ByteUtils.copy(checksum, 0, 4));

        return "SIG_K1_" + Base58.encode(signatureString);
    }

    /**
     * signTransaction
     *
     * @param privateKey
     * @param push
     * @return
     */
    public static String signTransaction(String privateKey, TxSign push) {
        // tx
        ByteBuffer bf = new ByteBuffer();
        ObjectUtils.writeBytes(push, bf);
        byte[] real = bf.getBuffer();
        // append
        real = ByteUtils.concat(real, java.nio.ByteBuffer.allocate(33).array());

        // final byte [] b = real.clone();
        // int[] a = IntStream.range(0, b.length).map(i -> b[i] & 0xff).toArray();
        // for(int i=1;i<=a.length;i++) {
        // System.out.print(a[i-1]+","+((i%8==0)?"\n":""));
        // }
        return signHash(privateKey, real);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy