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

vite.Wallet Maven / Gradle / Ivy

The newest version!
package vite;

import com.rfksystems.blake2b.Blake2b;
import com.rfksystems.blake2b.security.Blake2bProvider;
import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.Utils;
import net.i2p.crypto.eddsa.math.Curve;
import net.i2p.crypto.eddsa.math.Field;
import net.i2p.crypto.eddsa.math.ed25519.Ed25519LittleEndianEncoding;
import net.i2p.crypto.eddsa.math.ed25519.Ed25519ScalarOps;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import vite.bean.Key;
import vite.bean.ViteMnemonics;
import vite.utils.PBKDF2SHA512;

import java.security.*;
import java.util.Arrays;
import java.util.List;

import static vite.utils.BytesUtils.byteMerger;
import static vite.utils.BytesUtils.int2Bytes;

public class Wallet {
    private static final SecureRandom SECURE_RANDOM = new SecureRandom();


    private static String ViteAccountPathFormat = "m/44'/666666'/%d'";

    private static final String seceret = "ed25519 blake2b seed";

    private static EdDSANamedCurveSpec ED25519_BLAKE2B_CURVES_PEC;

    private static Provider provider;

    static {
        provider = new Blake2bProvider();
        Security.addProvider(provider);

        Field ED25519_FIELD = new Field(
                256, // b
                Utils.hexToBytes("edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"), // q
                new Ed25519LittleEndianEncoding());

        Curve ED25519_CURVE = new Curve(ED25519_FIELD,
                Utils.hexToBytes("a3785913ca4deb75abd841414d0a700098e879777940c78c73fe6f2bee6c0352"), // d
                ED25519_FIELD.fromByteArray(Utils.hexToBytes("b0a00e4a271beec478e42fad0618432fa7d7fb3d99004d2b0bdfc14f8024832b"))); // I

        ED25519_BLAKE2B_CURVES_PEC = new EdDSANamedCurveSpec(
                EdDSANamedCurveTable.ED_25519,
                ED25519_CURVE,
                Blake2b.BLAKE2_B_512, // H
                new Ed25519ScalarOps(), // l
                ED25519_CURVE.createPoint( // B
                        Utils.hexToBytes("5866666666666666666666666666666666666666666666666666666666666666"),
                        true)); // Precompute tables for B

        EdDSANamedCurveTable.defineCurve(ED25519_BLAKE2B_CURVES_PEC);
    }


    public static byte[] createPublicKey(byte[] privateKey) {
        EdDSAPrivateKeySpec key = new EdDSAPrivateKeySpec(privateKey, ED25519_BLAKE2B_CURVES_PEC);
        return key.getA().toByteArray();
    }


    public static byte[] sign(byte[] hash, byte[] privateKey) {
        try {
            EdDSAEngine edDSAEngine = new EdDSAEngine(MessageDigest.getInstance(Blake2b.BLAKE2_B_512, provider));
            EdDSAPrivateKeySpec edDSAPrivateKeySpec = new EdDSAPrivateKeySpec(privateKey, ED25519_BLAKE2B_CURVES_PEC);
            EdDSAPrivateKey edDSAPrivateKey = new EdDSAPrivateKey(edDSAPrivateKeySpec);
            edDSAEngine.initSign(edDSAPrivateKey);
            edDSAEngine.setParameter(EdDSAEngine.ONE_SHOT_MODE);
            edDSAEngine.update(hash);
            return edDSAEngine.sign();
        } catch (GeneralSecurityException e) {
            throw new IllegalStateException("It wasn't possible to sign " + Arrays.toString(hash), e);
        }
    }

    public static boolean verify(byte[] signature, byte[] hash, byte[] publicKey) {
        try {
            EdDSAEngine edDSAEngine = new EdDSAEngine(MessageDigest.getInstance(Blake2b.BLAKE2_B_512, provider));
            EdDSAPublicKeySpec edDSAPublicKeySpec = new EdDSAPublicKeySpec(publicKey, ED25519_BLAKE2B_CURVES_PEC);
            EdDSAPublicKey edDSAPublicKey = new EdDSAPublicKey(edDSAPublicKeySpec);
            edDSAEngine.initVerify(edDSAPublicKey);
            edDSAEngine.setParameter(EdDSAEngine.ONE_SHOT_MODE);
            edDSAEngine.update(hash);
            return edDSAEngine.verify(signature);
        } catch (GeneralSecurityException e) {
            throw new IllegalStateException("It wasn't possible to verify " + Arrays.toString(hash), e);
        }
    }


    public static List createBip39Mnemonic(int length, ViteMnemonics.ViteMnemonicLanguage language) {
        return ViteMnemonics.createBip39Mnemonic(generateSeed(32 * length / 3 / 8), language);
    }

    public static List createBip39Mnemonic() {
        return createBip39Mnemonic(24, ViteMnemonics.ViteMnemonicLanguage.ENGLISH);
    }

    private static byte[] generateSeed(int length) {
        byte[] seed = new byte[length];
        SECURE_RANDOM.nextBytes(seed);
        return seed;
    }
//m/44'/666666'/0' 5c196b50d9c0d9edc174c49fc9d18e59a0629b8b96b33d5815b560204e9ec988  vite_f41ea3215ef1b195e1389c23bfde50534260be96304cb2db46

    /**
     * @param mnemonics
     * @param index
     * @param type      user or contract
     * @return
     */
    public static Key generateKeyPairsFromMnemonics(String mnemonics, int index, int type) {


        // seed pbkdf2sha512
        byte[] seed = PBKDF2SHA512.derive(mnemonics, "mnemonic" + "", 2048, 64);

        //  System.out.println("seed: " + Hex.encodeHexString(seed));
        String path = ViteAccountPathFormat.replaceAll("%d", index + "");
        byte[] result = deriveForPath(path, seed);
        byte[] key = new byte[32];
        System.arraycopy(result, 0, key, 0, 32);
        byte[] pubKey = createPublicKey(key);
        byte[] addressFirst = ViteWalletHelper.digest(20, pubKey);
        byte[] checkSum = null;
        if (type == 1) {
            checkSum = ViteWalletHelper.digest(5, addressFirst);
            for (int i = 0; i < checkSum.length; i++) {
                checkSum[i] = (byte)~checkSum[i];
            }
        } else {
            checkSum = ViteWalletHelper.digest(5, addressFirst);
        }

        Key keyresult = new Key();
        keyresult.setPriKey(key);
        keyresult.setPubKey(createPublicKey(key));
        keyresult.setAddress(addressFirst);
        keyresult.setChecksum(checkSum);
        if (type == 1) {
            keyresult.setIsContract((byte)1);
        } else {
            keyresult.setIsContract((byte)0);
        }
        return keyresult;
        // System.out.println(path + "\t" + Hex.encodeHexString(key) + "\t" + "vite_" + Hex.encodeHexString(address) + Hex.encodeHexString(checkSum));
    }


    public static String getViteAddressFromBase64PubKey(String base64PubKey, int type) {


        Base64 base64 = new Base64();
        byte[] pubBytes = base64.decode(base64PubKey);
        byte[] addressFirst = ViteWalletHelper.digest(20, pubBytes);
        byte[] checkSum = null;
        if (type == 1) {
            checkSum = ViteWalletHelper.digest(5, addressFirst);
            for (int i = 0; i < checkSum.length; i++) {
                checkSum[i] = (byte)~checkSum[i];
            }
        } else {
            checkSum = ViteWalletHelper.digest(5, addressFirst);
        }

        return "vite_" + Hex.encodeHexString(addressFirst) + Hex.encodeHexString(checkSum);
    }

    private static byte[] deriveForPath(String path, byte[] seed) {

        try {
            byte[] bytes = hmacSha512(seceret.getBytes("utf-8"), seed);
            byte[] masterKey = new byte[32];
            byte[] chaincode = new byte[32];
            System.arraycopy(bytes, 0, masterKey, 0, 32);
            System.arraycopy(bytes, 32, chaincode, 0, 32);

            //          System.out.println("masterKey " + new String(Hex.encodeHex(masterKey)));
            //        System.out.println("chainCode " + new String(Hex.encodeHex(chaincode)));


            String segments[] = path.replaceAll("'", "").split("/");
            byte[] result = null;
            for (int i = 1; i < 4; i++) {
                int i32 = Integer.parseInt(segments[i]);
                i32 = i32 | 1 << 31;
                // System.out.println(i32);
                result = derive(i32, masterKey, chaincode);
                masterKey = new byte[32];
                chaincode = new byte[32];
                System.arraycopy(result, 0, masterKey, 0, 32);
                System.arraycopy(result, 32, chaincode, 0, 32);
            }

            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private static byte[] derive(int index, byte[] masterkey, byte[] chainCode) {
        byte[] iBytes = int2Bytes(index);
        byte[] prefix = {0x0};
        byte[] keymodfify = byteMerger(prefix, masterkey);
        keymodfify = byteMerger(keymodfify, iBytes);
        byte[] result = hmacSha512(chainCode, keymodfify);
        return result;
    }

    static HMac createHmacSha512Digest(byte[] key) {
        SHA512Digest digest = new SHA512Digest();
        HMac hMac = new HMac(digest);
        hMac.init(new KeyParameter(key));
        return hMac;
    }

    static byte[] hmacSha512(HMac hmacSha512, byte[] input) {
        hmacSha512.reset();
        hmacSha512.update(input, 0, input.length);
        byte[] out = new byte[64];
        hmacSha512.doFinal(out, 0);
        return out;
    }

    public static byte[] hmacSha512(byte[] key, byte[] data) {
        return hmacSha512(createHmacSha512Digest(key), data);
    }


}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy