From Myblog: ywandy.github.io import this
From Myblog: yeweiandy.coding.me import this
分析
我们在使用hyperledger sawtooth平台的时候,需要使用keygen这一个sawtooth的cli程序去创建一对密钥对,在hyperledger sawtooth中,该过程是使用一个特定的随机函数,生成一个私钥,再执行Secp256k1椭圆曲线算法,根据私钥导出公钥
-
我在使用sawtooth的java sdk时候遇到了这样的问题,首先java的sdk 源码(https://github.com/hyperledger/sawtooth-sdk-java)
- 在sdk的example代码,调用了如下两个函数:
public static ECKey readWif(String wif) { return DumpedPrivateKey.fromBase58(MAINNET, wif).getKey(); } public static String getPublicKey(ECKey privateKey) { return ECKey.fromPrivate(privateKey.getPrivKey(), true).getPublicKeyAsHex(); }
- 并且按照example给出的测试集其中一对公钥私钥如下:
私钥: 5JkisHAXScTk6Tah9jq9S5B4ByiputRjnKnQrF6k1uBLBQAD8Mi 公钥: 03bc976dc770b84decb90abeb94364c6368da051a9417cc4046f9f478d995b2ba7
按照以上的调用,通过readWif(String wif)
把私钥导入,确实能够生成以上对应的公钥,也证明了bitcoinj库是没有任何问题
- 同时我是用sawtooth自带的keygen工具去生成密钥对时候发现,sawtooth自带的生成公钥和私钥长度和以上测试用例的不一样,具体如下:
私钥 :'20f34219eed055a8292767876e97cedc681cdee65f8d100f0c192d0b61cb13d6'
公钥 :'02fe868857f1dcb31137b34c55cf1b6e031447b5fe7902e49a083eaf95c54aaecf'
- 通过分析我们发现,example给出的例子使用的经过了base58编码的公私密钥对,而sawtooth原生的keygen则没有采用base58编码。因此如果使用java的bitcoinj库现有的方法能生成sawtooth keygen格式的公钥私钥对呢?这个就是本文的一个重点。
解决方法:
- 我们首先观察example里面的Signing 类,发现里面调用的方法都是来自于ECKey这个类的,通过分析,首先在ECKey类里面的私钥都是使用BigInteger表示的,而我们sawtooth keygen生成的私钥是16位Hex格式的String
- 因此我们需要使用方法把导入的String从16位Hex读入再变成BigInteger对象,再使用ECKey的fromPrivate((BigInteger privKey)方法,由BigInteger对象生成一个ECKey的对象。
具体的fromPrivate()方法如下:
public static ECKey fromPrivate(BigInteger privKey) {
return fromPrivate(privKey, true);
}
- 最后通过getPublicKeyAsHex()方法即可得到由16位hex编码的String 公钥
具体实现代码:
public static String getPublicKeyFromHex(String key){
BigInteger privateKeyBigInt = new BigInteger(key,16);
ECKey privateKey = ECKey.fromPrivate(privateKeyBigInt);
return privateKey.getPublicKeyAsHex();
}
实现的例子:
import org.bitcoinj.core.ECKey;
import java.math.BigInteger;
public class main {
public static String getPublicKeyFromHex(String key){
BigInteger privateKeyBigInt = new BigInteger(key,16);
ECKey privateKey = ECKey.fromPrivate(privateKeyBigInt);
return privateKey.getPublicKeyAsHex();
}
public static void main(String[] args) {
//此处我输入我上文提到的公钥
String privateKeyStr = "20f34219eed055a8292767876e97cedc681cdee65f8d100f0c192d0b61cb13d6";
System.out.println(getPublicKeyFromHex(privateKeyStr));
}
}
- 程序执行结果:
02fe868857f1dcb31137b34c55cf1b6e031447b5fe7902e49a083eaf95c54aaecf
- 我们成功的使用java实现了sawtooth自带的keygen功能,除了keygen的通过随机数生成privatekey外,我们已经实现了把keygen生成的私钥生成回sawtooth keygen兼容的公钥格式