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

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

核心加密算法：

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://datacbc.gitbook.io/index/kai-fa-zhi-nan/qian-bao-di-zhi-gong-si-yao-sheng-cheng-suan-fa.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
