> For the complete documentation index, see [llms.txt](https://datacbc.gitbook.io/index/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://datacbc.gitbook.io/index/kai-fa-zhi-nan/qian-bao-di-zhi-gong-si-yao-sheng-cheng-suan-fa.md).

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

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

核心加密算法：

数字签名密钥算法：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

部分展示代码

### 创建新的密钥对

```java
/**
 * 创建新的密钥对
 * @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();
}
```

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

```java
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进制字符串

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

```

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

```java
 /**
  * 通过公钥字符串获取公钥字节
  * @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

```java
/**
 * 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生成地址

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

```java
/**
 * 通过公钥字节获取钱包地址 
 * @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("错误的公钥地址");
    }
}

```

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

```java
/**
 * 通过私钥字节获取公钥字节
 * @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->地址（注意：无法反向推导） .&#x20;
