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

com.github.DNAProject.core.program.Program Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2018 The DNA Authors
 * This file is part of The DNA library.
 *
 *  The DNA is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  The DNA is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with The DNA.  If not, see .
 *
 */

package com.github.DNAProject.core.program;

import com.github.DNAProject.common.Common;
import com.github.DNAProject.common.ErrorCode;
import com.github.DNAProject.common.Helper;
import com.github.DNAProject.core.scripts.ScriptBuilder;
import com.github.DNAProject.core.scripts.ScriptOp;
import com.github.DNAProject.crypto.ECC;
import com.github.DNAProject.crypto.KeyType;
import com.github.DNAProject.io.BinaryReader;
import com.github.DNAProject.sdk.exception.SDKException;
import org.bouncycastle.math.ec.ECPoint;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 *
 */
public class Program {
    public static byte[] ProgramFromParams(byte[][] sigData) throws IOException {
        ScriptBuilder sb = new ScriptBuilder();
        sigData = Arrays.stream(sigData).sorted((o1, o2) -> {
            return Helper.toHexString(o1).compareTo(Helper.toHexString(o2));
        }).toArray(byte[][]::new);
        for (byte[] sig : sigData) {
            sb.emitPushByteArray(sig);
        }
        return sb.toArray();
    }
    public static byte[] ProgramFromPubKey(byte[] publicKey) throws Exception {
        ScriptBuilder sb = new ScriptBuilder();
        sb.emitPushByteArray(publicKey);
        sb.add(ScriptOp.OP_CHECKSIG);
        return sb.toArray();
    }
    public static byte[] ProgramFromMultiPubKey(int m, byte[]... publicKeys) throws Exception {
        int n = publicKeys.length;

        if (m <= 0 || m > n || n > Common.MULTI_SIG_MAX_PUBKEY_SIZE) {
            throw new SDKException(ErrorCode.ParamError);
        }
        try (ScriptBuilder sb = new ScriptBuilder()) {
            sb.emitPushInteger(BigInteger.valueOf(m));
            publicKeys = sortPublicKeys(publicKeys);
            for (byte[] publicKey : publicKeys) {
                sb.emitPushByteArray(publicKey);
            }
            sb.emitPushInteger(BigInteger.valueOf(publicKeys.length));
            sb.add(ScriptOp.OP_CHECKMULTISIG);
            return sb.toArray();
        }
    }
    public static byte[][] sortPublicKeys(byte[]... publicKeys){
        publicKeys = Arrays.stream(publicKeys).sorted((o1, o2) -> {
            if (KeyType.fromPubkey(o1).getLabel() != KeyType.fromPubkey(o2).getLabel()) {
                return KeyType.fromPubkey(o1).getLabel() >= KeyType.fromPubkey(o2).getLabel() ? 1 : -1;
            }
            switch (KeyType.fromPubkey(o1)) {
                case SM2:
                    byte[] p = new byte[33];
                    System.arraycopy(o1, 2, p, 0, p.length);
                    o1 = p;
                    byte[] p2 = new byte[33];
                    System.arraycopy(o2, 2, p2, 0, p2.length);
                    o2 = p2;
                    ECPoint smPk1 = ECC.sm2p256v1.getCurve().decodePoint(o1);
                    ECPoint smPk2 = ECC.sm2p256v1.getCurve().decodePoint(o2);
                    return ECC.compare(smPk1, smPk2);
                case ECDSA:
                    ECPoint pk1 = ECC.secp256r1.getCurve().decodePoint(o1);
                    ECPoint pk2 = ECC.secp256r1.getCurve().decodePoint(o2);
                    return ECC.compare(pk1, pk2);
                case EDDSA:
                    //TODO
                    return Helper.toHexString(o1).compareTo(Helper.toHexString(o1));
                default:
                    return Helper.toHexString(o1).compareTo(Helper.toHexString(o1));
            }
        }).toArray(byte[][]::new);
        return publicKeys;
    }
    public static byte[][] getParamInfo(byte[] program) {
        ByteArrayInputStream bais = new ByteArrayInputStream(program);
        BinaryReader br = new BinaryReader(bais);
        List list = new ArrayList();
        while(true){
            try {
                list.add(readBytes(br));
            } catch (IOException e) {
                break;
            }
        }
        byte[][] res = new byte[list.size()][];
        for(int i=0;i < list.size(); i++){
            res[i] = list.get(i);
        }
        return res;
    }

    public static byte[] readBytes(BinaryReader br) throws IOException {

        byte code = br.readByte();
        long keyLen;
        if(code == ScriptOp.OP_PUSHDATA4.getByte()){
            int temp;
            temp = br.readInt();
            keyLen = Long.valueOf(temp);
        } else if(code == ScriptOp.OP_PUSHDATA2.getByte()){
            int temp;
            temp = br.readShort();
            keyLen = Long.valueOf(temp);
        }else if(code == ScriptOp.OP_PUSHDATA1.getByte()) {
            int temp;
            temp = br.readByte();
            keyLen = Long.valueOf(temp&0xFF);
        }else if(code <= ScriptOp.OP_PUSHBYTES75.getByte() && code >= ScriptOp.OP_PUSHBYTES1.getByte()){
            keyLen = Long.valueOf(code) - Long.valueOf(ScriptOp.OP_PUSHBYTES1.getByte()) + 1;
        }else{
            keyLen = 0;
        }
        byte[] res = br.readBytes((int) keyLen);
        return res;
    }

    public static ProgramInfo getProgramInfo(byte[] program) throws IOException {
        ProgramInfo info = new ProgramInfo();
        if(program.length <= 2) {

        }
        byte end = program[program.length - 1];
        byte[] temp = new byte[program.length - 1];
        System.arraycopy(program,0,temp,0,program.length - 1);
        ByteArrayInputStream bais = new ByteArrayInputStream(temp);
        BinaryReader reader = new BinaryReader(bais);
        if(end == ScriptOp.OP_CHECKSIG.getByte()){
            try {
                byte[] publicKey = readBytes(reader);
                info.setPublicKey(new byte[][]{publicKey});
                info.setM((short)1);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else if(end == ScriptOp.OP_CHECKMULTISIG.getByte()) {
            short m = 0;
            int len = program[program.length - 2] - ScriptOp.OP_PUSH1.getByte() +1;
            try {
                m = (byte)(reader.readByte() - ScriptOp.OP_PUSH1.getByte()+1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            byte[][] pub = new byte[len][];
            for(int i =0; i<(int)len; i++){
                pub[i] = reader.readVarBytes();
            }
            info.setPublicKey(pub);
            info.setM(m);
        }
        return info;
    }

    public static short readNum(BinaryReader reader) throws IOException, SDKException {
        ScriptOp code = readOpCode(reader);
        if(code == ScriptOp.OP_PUSH0){
            readOpCode(reader);
            return 0;
        }else {
            int num = (int)code.getByte() - (int)ScriptOp.OP_PUSH1.getByte() + 1;
            if(num >= 1 && num <= 16) {
                readOpCode(reader);
                return (short)num;
            }
        }
        byte[] buff = readBytes(reader);
        BigInteger bint = Helper.BigIntFromNeoBytes(buff);
        long num = bint.longValue();
        if(num > Short.MAX_VALUE || num < 16){
            throw new SDKException(ErrorCode.ParamErr("num is wrong"));
        }
        return (short)num;
    }
    public static ScriptOp readOpCode(BinaryReader reader) throws IOException {
        return ScriptOp.valueOf(reader.readByte());
    }

    public static byte[] programFromParams(byte[][] sigs) {
        ScriptBuilder builder = new ScriptBuilder();
        for(byte[] sigdata : sigs){
            builder.emitPushByteArray(sigdata);
        }
        return builder.toArray();
    }
    public static byte[] programFromPubKey(byte[] publicKey) {
        ScriptBuilder builder = new ScriptBuilder();
        builder.emitPushByteArray(publicKey);
        builder.emit(ScriptOp.OP_CHECKSIG);
        return builder.toArray();
    }

    public static byte[] programFromMultiPubKey(byte[][] publicKey,short m) throws SDKException {
        int n = publicKey.length;
        if (m >= 1 && m <= n && n <= 1024) {
            throw new SDKException(ErrorCode.ParamErr("m is wrong"));
        }
        ScriptBuilder builder = new ScriptBuilder();
        builder.pushNum(m);
        builder.add(ScriptOp.OP_CHECKSIG);
        return builder.toArray();
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy