Bytom离线签名以及私钥地址生成java和go版本(用户自己管理UTXO)

1 篇文章 0 订阅
这篇博客详细介绍了如何使用Java和Go语言实现Bytom的离线签名以及私钥和地址的生成。内容涵盖Bytom节点机制,提供了源码链接,针对私钥生成、地址生成和离线签名三个步骤,分别给出了Java和Go两种语言的实现版本。
摘要由CSDN通过智能技术生成

Bytom节点机制

	Bytom的主网节点是一个HD钱包,UTXO模型由HD钱包内置的账户模型管理,但是由于HD钱包的原因,导致我们无法进行
	离线签名。官方的SDK关于离线签名少之又少,所以以至于有我们自己去编写sdk去完成离线签名。

源码链接

	以下只贴出部分代码,不做特别申明,具体请看sdk源码。如有疑问,可添加qq:1359669022 或者微信:JFJun_12
	[Java版本](https://github.com/JFJun/Bytom-offline-sign-java)
	[Go版本](https://github.com/JFJun/Bytom-offline-sign-go)

生成私钥

java版本

public static String CreateXprv(){
       long timestamp = System.currentTimeMillis();
       String seedStr = "BytomOfflineSignTest"+timestamp;
       byte[] seed;
       {
           try {
               //创建一个64位 的随机种子
               seed = new Sha512(seedStr.getBytes("utf-8")).finish512();
               //创建root 私钥
               byte[] privkey = RootPrivkey(seed);
               String priv= Hex.encode(privkey);
               return priv;
           } catch (UnsupportedEncodingException e) {
               e.printStackTrace();
           }
       }
       return "";
   }

go版本

//生成私钥,公钥
func GenerateKey()(chainkd.XPrv, chainkd.XPub){
	//生成公钥私钥
	xpriv,xpub,err:=chainkd.NewXKeys(nil)
	if err!=nil {
		fmt.Errorf("create priv_key error,please try again,Err= %v",err)
		panic(err)
	}
	return xpriv,xpub
}

生成地址

java版本

private String EncodingToAddress(String hrp,byte[] witnessProgram){
        if (witnessProgram.length!=20){
            logger.error("Input pub ripemd160 hash len is not equals 20");
            return "";

        }
        byte[] converted = ConvertBits(witnessProgram,8,5,true);

        // Concatenate the witness version and program, and encode the resulting
        // bytes using bech32 encoding.
        byte[] combined = new byte[converted.length+1];
        combined[0] = witnessVersion;
        System.arraycopy(converted,0,combined,1,converted.length);

        //进行编码
        String bech = Bech32Encode(hrp,combined);

        //检查是否可用
        byte[] program = decodeSegWitAddress(bech);

        if( program==null){
            logger.error("program is equals null");
            return "";
        }
        if (!Arrays.equals(witnessProgram,program)){
            logger.error("program is not equals witness program");
            return "";
        }
        return bech;
    }

go版本

//公钥转换为地址
func XpubBytesToAddress(pub []byte)string{
	xpub:=BytesToXPub(pub)
	address:=XpubToAddress(xpub)
	return address
}

func XpubToAddress(xpub chainkd.XPub)string{
	pub := xpub.PublicKey()
	pubHash := crypto.Ripemd160(pub)

	//  TODO 切换生成主网还是测试网
	address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.TestNetParams)		//测试网
	//address, err := common.NewAddressWitnessPubKeyHash(pubHash, &consensus.ActiveNetParams)		//主网
	if err != nil {
		fmt.Errorf("create address error,please try again")
		panic(err)
	}
	return address.EncodeAddress()
}

离线签名

java版本

public static byte[] ed25519InnerSign(byte[] privateKey, byte[] message) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-512");
        byte[] digestData = new byte[32 + message.length];
        int digestDataIndex = 0;
        for (int i = 32; i < 64; i++) {
            digestData[digestDataIndex] = privateKey[i];
            digestDataIndex++;
        }
        for (int i = 0; i < message.length; i++) {
            digestData[digestDataIndex] = message[i];
            digestDataIndex++;
        }
        md.update(digestData);
        byte[] messageDigest = md.digest();

        Ed25519.reduce(messageDigest);
        byte[] messageDigestReduced = Arrays.copyOfRange(messageDigest, 0, 32);
        byte[] encodedR = Ed25519.scalarMultWithBaseToBytes(messageDigestReduced);
        byte[] publicKey = DeriveXpub.deriveXpubByBytes(privateKey);

        byte[] hramDigestData = new byte[32 + encodedR.length + message.length];
        int hramDigestIndex = 0;
        for (int i = 0; i < encodedR.length; i++) {
            hramDigestData[hramDigestIndex] = encodedR[i];
            hramDigestIndex++;
        }
        for (int i = 0; i < 32; i++) {
            hramDigestData[hramDigestIndex] = publicKey[i];
            hramDigestIndex++;
        }
        for (int i = 0; i < message.length; i++) {
            hramDigestData[hramDigestIndex] = message[i];
            hramDigestIndex++;
        }
        md.reset();
        md.update(hramDigestData);
        byte[] hramDigest = md.digest();
        Ed25519.reduce(hramDigest);
        byte[] hramDigestReduced = Arrays.copyOfRange(hramDigest, 0, 32);

        byte[] sk = Arrays.copyOfRange(privateKey, 0, 32);
        byte[] s = new byte[32];
        Ed25519.mulAdd(s, hramDigestReduced, sk, messageDigestReduced);

        byte[] signature = new byte[64];
        for (int i = 0; i < encodedR.length; i++) {
            signature[i] = encodedR[i];
        }
        int signatureIndex = 32;
        for (int i = 0; i < s.length; i++) {
            signature[signatureIndex] = s[i];
            signatureIndex++;
        }
        return signature;
    }

go版本

func SignTransaction(address string,tpl *txbuilder.Template)string{

	if tpl.SigningInstructions==nil{
		tpl.SigningInstructions = []*txbuilder.SigningInstruction{}
	}
	var (
		newTpl *txbuilder.Template
	)
	for i,_:=range tpl.Transaction.Inputs{
		h:=tpl.Hash(uint32(i)).Byte32()
		//进行签名
		sig,xPub,_:=sign(address,h[:])
		data:=[]byte(xPub.PublicKey())
		fmt.Printf("签名数据[%d]:%s",i,hex.EncodeToString(sig))
		newTpl=txbuilder.BuildSignatureDataToTplByJun(tpl,sig,data,i)  //该方法写在与那么里面
	}
	tt,err:=txbuilder.CheckTpl(newTpl)
	if err != nil {
		return ""
	}
	fmt.Println(" Sign a transaction success !!!")

	return tt.Transaction.String()
}

func sign(address string,data []byte)(sig[]byte,pub chainkd.XPub,err error){
	var xPriv *chainkd.XPrv
	//todo 根据地址获取对应的私钥
	// xPriv:= todo
	if err != nil {
		return nil,chainkd.XPub{},err
	}
	//签名交易
	sig =xPriv.Sign(data[:])
	return sig,xPriv.XPub(),nil
}

发送交易

发送交易调用rpc接口“submit-transaction”。Java版本测试后可以进行多个地址向多个地址发送交易,Go版本只实现了
单个地址向一个或者多个地址发送交易。如果需要Go版本进行多对多发送交易,可自行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值