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

io.nuls.base.signture.SignatureUtil Maven / Gradle / Ivy

/*
 * MIT License
 *
 * Copyright (c) 2017-2018 nuls.io
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */
package io.nuls.base.signture;


import io.nuls.base.basic.AddressTool;
import io.nuls.base.data.NulsHash;
import io.nuls.base.data.NulsSignData;
import io.nuls.base.data.Transaction;
import io.nuls.base.script.Script;
import io.nuls.base.script.ScriptBuilder;
import io.nuls.base.script.ScriptChunk;
import io.nuls.base.script.ScriptOpCodes;
import io.nuls.core.constant.BaseConstant;
import io.nuls.core.core.annotation.Component;
import io.nuls.core.crypto.ECKey;
import io.nuls.core.crypto.HexUtil;
import io.nuls.core.exception.NulsException;
import io.nuls.core.log.Log;

import java.io.IOException;
import java.math.BigInteger;
import java.util.*;

/**
 * 交易签名工具类
 * Transaction Signature Tool Class
 *
 * @author tag
 * 2018/10/10
 */
@Component
public class SignatureUtil {
    /**
     * 验证交易中所有签名正确性
     *
     * @param tx 交易
     */
    public static boolean validateTransactionSignture(Transaction tx) throws NulsException {
        try {
            if (tx.getTransactionSignature() == null || tx.getTransactionSignature().length == 0) {
                throw new NulsException(new Exception());
            }
            if (!tx.isMultiSignTx()) {
                TransactionSignature transactionSignature = new TransactionSignature();
                transactionSignature.parse(tx.getTransactionSignature(), 0);
                if ((transactionSignature.getP2PHKSignatures() == null || transactionSignature.getP2PHKSignatures().size() == 0)) {
                    throw new NulsException(new Exception("Transaction unsigned !"));
                }
                int signCount = tx.getCoinDataInstance().getFromAddressCount();
                int passCount = 0;
                for (P2PHKSignature signature : transactionSignature.getP2PHKSignatures()) {
                    if (!ECKey.verify(tx.getHash().getBytes(), signature.getSignData().getSignBytes(), signature.getPublicKey())) {
                        throw new NulsException(new Exception("Transaction signature error !"));
                    }
                    passCount++;
                    if(passCount >= signCount){
                        break;
                    }
                }
            } else {
                MultiSignTxSignature transactionSignature = new MultiSignTxSignature();
                transactionSignature.parse(tx.getTransactionSignature(), 0);
                if ((transactionSignature.getP2PHKSignatures() == null || transactionSignature.getP2PHKSignatures().size() == 0)) {
                    throw new NulsException(new Exception("Transaction unsigned !"));
                }
                List validSignatures = transactionSignature.getValidSignature();
                int validCount = 0;
                for (P2PHKSignature signature : validSignatures) {
                    if (ECKey.verify(tx.getHash().getBytes(), signature.getSignData().getSignBytes(), signature.getPublicKey())) {
                        validCount++;
                    }
                    if (validCount >= transactionSignature.getM()) {
                        break;
                    }
                }
                if (validCount < transactionSignature.getM()) {
                    throw new NulsException(new Exception("Transaction signature error !"));
                }
            }

        } catch (NulsException e) {
            Log.error("TransactionSignature parse error!");
            throw e;
        }
        return true;
    }

    /**
     * 跨链交易验证签名
     *
     * @param tx 交易
     */
    public static boolean validateCtxSignture(Transaction tx)throws NulsException{
        if (tx.getTransactionSignature() == null || tx.getTransactionSignature().length == 0) {
            return false;
        }
        TransactionSignature transactionSignature = new TransactionSignature();
        transactionSignature.parse(tx.getTransactionSignature(), 0);
        for (P2PHKSignature signature : transactionSignature.getP2PHKSignatures()) {
            if (!ECKey.verify(tx.getHash().getBytes(), signature.getSignData().getSignBytes(), signature.getPublicKey())) {
                throw new NulsException(new Exception("Transaction signature error !"));
            }
        }
        return true;
    }

    /**
     * 验证数据签名
     *
     * @param digestBytes
     * @param p2PHKSignature
     * @return
     * @throws NulsException
     */
    public static boolean validateSignture(byte[] digestBytes, P2PHKSignature p2PHKSignature) throws NulsException {
        if (null == p2PHKSignature) {
            throw new NulsException(new Exception("P2PHKSignature is null!"));
        }
        if (ECKey.verify(digestBytes, p2PHKSignature.getSignData().getSignBytes(), p2PHKSignature.getPublicKey())) {
            return true;
        }
        return false;
    }

    /**
     * 判断交易是否存在某地址
     *
     * @param tx 交易
     */
    public static boolean containsAddress(Transaction tx, byte[] address, int chainId) throws NulsException {
        Set addressSet = getAddressFromTX(tx, chainId);
        if (addressSet == null || addressSet.size() == 0) {
            return false;
        }
        return addressSet.contains(AddressTool.getStringAddressByBytes(address));
    }

    /**
     * 获取交易签名地址
     *
     * @param tx 交易
     */
    public static Set getAddressFromTX(Transaction tx, int chainId) throws NulsException {
        Set addressSet = new HashSet<>();
        if (tx.getTransactionSignature() == null || tx.getTransactionSignature().length == 0) {
            return null;
        }
        try {
            List p2PHKSignatures;
            if (tx.isMultiSignTx()) {
                MultiSignTxSignature transactionSignature = new MultiSignTxSignature();
                transactionSignature.parse(tx.getTransactionSignature(), 0);
                p2PHKSignatures = transactionSignature.getP2PHKSignatures();
            } else {
                TransactionSignature transactionSignature = new TransactionSignature();
                transactionSignature.parse(tx.getTransactionSignature(), 0);
                p2PHKSignatures = transactionSignature.getP2PHKSignatures();
            }

            if ((p2PHKSignatures == null || p2PHKSignatures.size() == 0)) {
                return null;
            }
            for (P2PHKSignature signature : p2PHKSignatures) {
                if (signature.getPublicKey() != null && signature.getPublicKey().length != 0) {
                    addressSet.add(AddressTool.getStringAddressByBytes(AddressTool.getAddress(signature.getPublicKey(), chainId)));
                }
            }
        } catch (NulsException e) {
            Log.error("TransactionSignature parse error!");
            throw e;
        }
        return addressSet;
    }

    /**
     * 生成交易TransactionSignture
     *
     * @param tx         交易
     * @param signEckeys 需要生成普通签名的秘钥
     */
    public static void createTransactionSignture(Transaction tx, List signEckeys) throws IOException {
        if (signEckeys == null || signEckeys.size() == 0) {
            Log.error("TransactionSignature signEckeys is null!");
            throw new NullPointerException();
        }
        TransactionSignature transactionSignature = new TransactionSignature();
        List p2PHKSignatures = null;
        try {
            p2PHKSignatures = createSignaturesByEckey(tx, signEckeys);
            transactionSignature.setP2PHKSignatures(p2PHKSignatures);
            tx.setTransactionSignature(transactionSignature.serialize());
        } catch (IOException e) {
            Log.error("TransactionSignature serialize error!");
            throw e;
        }
    }

    /**
     * 生成交易多个传统签名(多地址转账可能会用到)
     *
     * @param tx     交易
     * @param eckeys 秘钥列表
     */
    public static List createSignaturesByEckey(Transaction tx, List eckeys) {
        List signatures = new ArrayList<>();
        for (ECKey ecKey : eckeys) {
            signatures.add(createSignatureByEckey(tx, ecKey));
        }
        return signatures;
    }

    public static List createSignaturesByEckey(NulsHash hash, List eckeys) {
        List signatures = new ArrayList<>();
        for (ECKey ecKey : eckeys) {
            signatures.add(createSignatureByEckey(hash, ecKey));
        }
        return signatures;
    }

    /**
     * 生成交易的签名传统
     *
     * @param tx     交易
     * @param priKey 私钥
     */
    public static P2PHKSignature createSignatureByPriKey(Transaction tx, String priKey) {
        ECKey ecKey = ECKey.fromPrivate(new BigInteger(1, HexUtil.decode(priKey)));
        P2PHKSignature p2PHKSignature = new P2PHKSignature();
        p2PHKSignature.setPublicKey(ecKey.getPubKey());
        //用当前交易的hash和账户的私钥账户
        p2PHKSignature.setSignData(signDigest(tx.getHash().getBytes(), ecKey));
        return p2PHKSignature;
    }

    /**
     * 生成交易的签名传统
     *
     * @param tx    交易
     * @param ecKey 秘钥
     */
    public static P2PHKSignature createSignatureByEckey(Transaction tx, ECKey ecKey) {
        P2PHKSignature p2PHKSignature = new P2PHKSignature();
        p2PHKSignature.setPublicKey(ecKey.getPubKey());
        //用当前交易的hash和账户的私钥账户
        p2PHKSignature.setSignData(signDigest(tx.getHash().getBytes(), ecKey));
        return p2PHKSignature;
    }


    public static P2PHKSignature createSignatureByEckey(NulsHash hash, ECKey ecKey) {
        P2PHKSignature p2PHKSignature = new P2PHKSignature();
        p2PHKSignature.setPublicKey(ecKey.getPubKey());
        //用当前交易的hash和账户的私钥账户
        p2PHKSignature.setSignData(signDigest(hash.getBytes(), ecKey));
        return p2PHKSignature;
    }

    /**
     * 生成多个解锁脚本
     *
     * @param signtures 签名列表
     * @param pubkeys   公钥列表
     */
    public static List