钱包地址、公私钥生成算法

公私钥生成的算法以及代码开源。钱包地址、公钥hash的生成方式

相关源码开源地址:研发人员加班打包创建中...

核心加密算法:

数字签名密钥算法:ECDSA,

椭圆曲线(EC)域参数设定:secp256k(比特币选择的也是该算法),

数字签名签名/验证算法:SHA512withECDSA;

Hash算法:SHA256、RIPEMD160算法(RACE原始完整性校验讯息摘要);

私钥说明

私钥字节总长度:144位(后68位为公钥的动态字节b)

例如私钥字节:

[48, -127, -115, 2, 1, 0, 48, 16, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 5, 43, -127, 4, 0, 10, 4, 118, 48, 116, 2, 1, 1, 4, 32, 111, 96, -19, 42, -3, -105, -91, -46, -79, -82, -79, 108, 96, -37, 91, -23, -40, 102, -114, 2, 67, -70, -100, 102, 90, -29, -127, -120, 125, 66, -11, -90, -96, 7, 6, 5, 43, -127, 4, 0, 10, -95, 68, 3, 66, 0, 4, 88, -23, 4, 81, 31, 69, 102, 52, 32, -73, 15, -48, 56, -120, -58, 49, -34, 67, 76, 47, -73, 74, 123, -22, -67, 82, -125, -42, 108, 24, 116, 88, -88, 53, 105, 78, 123, -13, 116, 40, -92, 47, 1, 54, 101, -63, -125, 26, 22, 29, -120, -32, -89, -36, -107, -27, -119, -18, -77, -71, 69, 103, 47, 63]

转换为字符串:30818d020100301006072a8648ce3d020106052b8104000a0476307402010104206f60ed2afd97a5d2b1aeb16c60db5be9d8668e0243ba9c665ae381887d42f5a6a00706052b8104000aa1440342000458e904511f45663420b70fd03888c631de434c2fb74a7beabd5283d66c187458a835694e7bf37428a42f013665c1831a161d88e0a7dc95e589eeb3b945672f3f

公钥说明

公钥字节总长度:88位(前20位为固定字节a,后68位为公钥动态字节b)

例如公钥字节:

[48, 86, 48, 16, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 5, 43, -127, 4, 0, 10, 3, 66, 0, 4, 88, -23, 4, 81, 31, 69, 102, 52, 32, -73, 15, -48, 56, -120, -58, 49, -34, 67, 76, 47, -73, 74, 123, -22, -67, 82, -125, -42, 108, 24, 116, 88, -88, 53, 105, 78, 123, -13, 116, 40, -92, 47, 1, 54, 101, -63, -125, 26, 22, 29, -120, -32, -89, -36, -107, -27, -119, -18, -77, -71, 69, 103, 47, 63]

其中:48, 86, 48, 16, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 5, 43, -127, 4, 0, 10 为固定的公钥前缀。为椭圆算法密钥对的算法标识、以及主编码格式标识。

转换为字符串:3056301006072a8648ce3d020106052b8104000a0342000458e904511f45663420b70fd03888c631de434c2fb74a7beabd5283d66c187458a835694e7bf37428a42f013665c1831a161d88e0a7dc95e589eeb3b945672f3f

部分展示代码

创建新的密钥对

/**
 * 创建新的密钥对
 * @return
 */
public static KeyPair newECKeyPair() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
    // 注册 BC Provider
    Security.addProvider(new BouncyCastleProvider());
    // 创建椭圆曲线算法的密钥对生成器,算法为 ECDSA
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
    // 椭圆曲线(EC)域参数设定
    ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(EC_PARAMETER_SPEC);
    //使用给定的参数集和随机源初始化密钥对生成器,生成公私钥
    keyPairGenerator.initialize(ecSpec, new SecureRandom());
    return keyPairGenerator.generateKeyPair();
}

通过密钥对获取到公私钥字节

KeyPair keyPair = ECDSAUtils.newECKeyPair();
//获取私钥
BCECPrivateKey privateKey = (BCECPrivateKey) keyPair.getPrivate();
//获取公钥
BCECPublicKey publicKey = (BCECPublicKey) keyPair.getPublic();
//获取到私钥字节
this.setPrivateKey(ECDSAUtils.getBytesByKey(privateKey));
//获取到公钥字节
this.setPublicKey(ECDSAUtils.getBytesByKey(publicKey));

通过公私钥字节获取到公私钥字符串

字节数组转16进制字符串

 /**
  * 公钥
  * @return
  */
 public String getPublicKeyStr(){
     return ByteUtils.bytesToHexString(this.publicKey);
 }
 /**
  * 私钥
  * @return
  */
 public String getPrivateKeyStr(){
     return ByteUtils.bytesToHexString(this.privateKey);
 }

通过公私钥字符串获取到公私钥字节

 /**
  * 通过公钥字符串获取公钥字节
  * @param pubKeyStr 公钥字符串
  * @return 公钥字节
  */
 public static byte[] getPubkeyByPubkeyStr(String pubKeyStr) {
     return ByteUtils.hexStringToByte(pubKeyStr);
 }
 /**
  * 通过私钥字符串获取私钥字节
  * @param privateKeyStr 私钥字符串
  * @return 私钥字节
  */
 public static byte[] getPrivateKeyByPrivateKeyStr(String privateKeyStr) {
     return ByteUtils.hexStringToByte(privateKeyStr);
 }

通过公钥字节生成公钥Hash

/**
 * ripeMD160Hash
 * 计算公钥的 RIPEMD160 Hash值
 * 通过公钥获取到公钥Hash
 * 获取公钥hash
 * @param pubKey 公钥
 * @return ipeMD160Hash(sha256 ( pubkey))
 */
public static byte[] getPubkeyHashByPubkey(byte[] pubKey) {
    //1. 先对公钥做 sha256 处理
    byte[] shaHashedKey = DigestUtils.sha256(pubKey);
    RIPEMD160Digest ripemd160 = new RIPEMD160Digest();
    ripemd160.update(shaHashedKey, 0, shaHashedKey.length);
    byte[] output = new byte[ripemd160.getDigestSize()];
    ripemd160.doFinal(output, 0);
    return output;
}

通过公钥Hash生成地址

通过算法保证绝对不可能通过地址推算出公钥。

/**
 * 通过公钥字节获取钱包地址 
 * @param pubkeyHashBytes
 * @return
 */
private static String getAddressByPubkeyHash(byte[] pubkeyHashBytes) {
    try {
        // 2. 添加版本 0x00
        ByteArrayOutputStream addrStream = new ByteArrayOutputStream();
        addrStream.write((byte) 0);
        addrStream.write(pubkeyHashBytes);
        byte[] versionedPayload = addrStream.toByteArray();

        // 3. 计算校验码
        byte[] checksum = Wallet.checksum(versionedPayload);

        // 4. 得到 version + paylod + checksum 的组合
        addrStream.write(checksum);
        byte[] binaryAddress = addrStream.toByteArray();

        // 5. 执行Base58转换处理
        return Base58Check.rawBytesToBase58(binaryAddress);
    } catch (Exception e) {
        log.error("通过公钥获取钱包失败",e);
        throw new ServiceException("错误的公钥地址");
    }
}

通过私钥字节推导出公钥字节

/**
 * 通过私钥字节获取公钥字节
 * @param privateKeyBytes 私钥字节
 * @return 公钥字节
 */
public static byte[] getPubkeyByteByPrivateKey(byte[] privateKeyBytes){
    byte[] pubkey = new byte[88];
    pubkey[0]=48;
    pubkey[1]=86;
    System.arraycopy(privateKeyBytes, 6, pubkey, 2, 18);
    System.arraycopy(privateKeyBytes, 76, pubkey, 20, 68);
    return pubkey;
}

公钥、公钥Hash、地址之间的关系:

私钥->公钥->公钥Hash->地址(注意:无法反向推导) .

最后更新于