You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Rust P256 crate从十六进制私钥获取ECDSA签名密钥遇阻

问题

我正在用Rust编写一个小型区块链模拟程序,需要获取ECDSA签名密钥来对添加到区块链的交易进行签名,但遇到了问题。

我在crypto.rs文件中定义了如下密钥对结构体:

pub struct KeyPair {
    pub name: String,
    pub public_key: String,
    private_key: String,
}

并实现了密钥生成逻辑:

impl KeyPair {
    pub fn generate(name: String, key_store: &mut KeyStore) -> KeyPair {
        // 先生成私钥
        let secret = SecretKey::random(&mut OsRng);
        let private_key = hex::encode(&secret.to_bytes());
        // 再生成公钥
        let public_key = hex::encode(secret.public_key().to_sec1_bytes());
        let key_pair: KeyPair = KeyPair {
            name,
            public_key,
            private_key,
        };
        // 存储副本并返回原对象供后续操作
        key_store.append_key_pair(key_pair.clone());
        key_store.write();
        key_pair
    }
}

测试时在key_store.json中生成了如下内容:

{
    "keys": [
        {
            "name": "TEST",
            "public_key": "040eda3b0d1b30a78cc830ab9e69dc25a52d5448c3c8228511481a67b1f6420bc55beb4efc297a49a657cfe08b7873293e78fef553724453f55eea3656a6369d5a",
            "private_key": "ccb789f12826fd81b45f27489b73ac5650f46f9b8f0281922f459be515f018b6"
        }
    ]
}

现在我需要从私钥(SecretKey)获取签名密钥来对交易哈希签名,但尝试的方法均失败。

第一次尝试的函数触发signature error panic:

pub fn get_signature(&self, hash: &String) -> String {
    let private_key = self.get_private_key();
    let signing_key = match private_key.parse::<SigningKey>() {
        Ok(key) => key,
        Err(e) => panic!("Error parsing signing key from private key: {}", e),
    };
    let signature: Signature = signing_key.sign(&hash.as_bytes());
    signature.to_string()
}

我参考了相关文章,该实现使用pem,但我选择将字节串转为十六进制存储,这是常见的密钥存储方式。

第二次尝试触发Error parsing bytes to String: invalid utf-8 sequence of 1 bytes from index 0 panic:

pub fn get_signature(&self, hash: &String) -> String {

    let private_key: String = self.get_private_key();
    let decoded: Vec<u8> = match hex::decode(&private_key) {
        Ok(bytes) => bytes,
        Err(e) => panic!("Error decoding bytes: {}", e),
    };
    let str_from_bytes: String = match String::from_utf8(decoded) {
        Ok(s) => s,
        Err(e) => panic!("Error parsing bytes to String: {}", e),
    };
    let signing_key = match str_from_bytes.parse::<SigningKey>() {
        Ok(key) => key,
        Err(e) => panic!("Error parsing signing key from private key: {}", e),
    };
    let signature: Signature = signing_key.sign(&hash.as_bytes());
    signature.to_string()
}

请问如何将转为十六进制存储的SecretKey还原为签名密钥?

解决方案

核心问题是错误地将十六进制解码后的私钥字节转成了UTF-8字符串,再尝试解析为SigningKey——私钥字节本身不是合法的UTF-8序列,而且SigningKey本身支持直接从字节数组构建,不需要转成字符串。

正确的实现步骤:

  1. 将存储的十六进制私钥字符串解码为字节数组
  2. 直接用这个字节数组实例化SecretKey,再转换为SigningKey(取决于你使用的ECDSA库,比如k256或ecdsa crate)
  3. 用SigningKey对交易哈希签名并转为字符串

假设你使用的是k256和ecdsa crate,修正后的代码如下:

use k256::SecretKey;
use ecdsa::SigningKey;
use hex;

pub fn get_signature(&self, hash: &String) -> String {
    let private_key_hex = self.get_private_key();
    // 解码十六进制字符串为原始私钥字节
    let private_key_bytes = hex::decode(private_key_hex)
        .expect("Failed to decode private key hex");
    
    // 从字节数组恢复SecretKey,再转为SigningKey
    let secret_key = SecretKey::from_slice(&private_key_bytes)
        .expect("Failed to recover SecretKey from bytes");
    let signing_key = SigningKey::from(secret_key);
    
    // 对哈希签名并转为字符串返回
    let signature = signing_key.sign(hash.as_bytes());
    signature.to_string()
}

关键说明:

  • 私钥的十六进制编码是字节的直接表示,解码后得到的是原始私钥字节,不需要转成UTF-8字符串——这是第二次尝试失败的根本原因。
  • SecretKey::from_slice方法可以直接从原始字节数组恢复密钥,和生成时调用secret.to_bytes()的操作完全对应。
  • 如果你的SigningKey来自ecdsa crate,它可以通过From<SecretKey> trait直接从SecretKey转换,无需额外解析。

无论使用的ECDSA库版本如何,核心逻辑一致:直接使用十六进制解码后的字节数组初始化签名密钥,不要经过UTF-8字符串转换。

内容的提问来源于stack exchange,提问作者PumpkinBreath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:12:29