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

Google Cloud KMS是否支持secp256k1的RFC6979签名用于以太坊密钥管理?

GCP KMS secp256k1支持RFC6979确定性签名(兼容ethers.js v5 wallet.signMessage)

GCP KMS的secp256k1密钥完全支持RFC6979规范的确定性ECDSA签名,可以实现和ethers.js v5 wallet.signMessage(...)完全一致的签名结果。以下是具体的实现步骤和注意事项:

一、密钥配置要求

创建secp256k1密钥时,必须选择签名算法为EC_SIGN_SECP256K1_SHA256——这个算法默认遵循RFC6979生成确定性的k值,确保相同输入(消息+私钥)生成完全相同的签名,和ethers.js的行为一致。

二、核心实现步骤

ethers.js的signMessage方法会对消息做特殊预处理,再进行签名。用GCP KMS实现相同效果,必须复刻这个预处理流程:

1. 消息预处理(和ethers.js对齐)

ethers.js会自动给消息添加以太坊签名前缀:

"\x19Ethereum Signed Message:\n" + 消息长度 + 原始消息
之后对拼接后的内容做SHA256哈希。你可以直接用ethers.js v5的utils.hashMessage方法完成这一步,避免手动拼接出错:

const {utils} = require('ethers');
const prefixedMessageHash = utils.hashMessage('你的消息内容');

prefixedMessageHash是十六进制格式的哈希值,后续会作为GCP KMS签名的输入。

2. 调用GCP KMS签名API

使用GCP官方Node.js客户端库@google-cloud/kms发起签名请求,传入预处理后的哈希值:

const {KeyManagementServiceClient} = require('@google-cloud/kms');

const kmsClient = new KeyManagementServiceClient();

async function signMessageWithKMS(projectId, location, keyRing, keyId, versionId, message) {
  // 生成符合ethers.js格式的消息哈希
  const hashHex = utils.hashMessage(message);
  const hashBuffer = Buffer.from(hashHex.slice(2), 'hex');

  // 构建KMS签名请求
  const keyVersionPath = kmsClient.cryptoKeyVersionPath(projectId, location, keyRing, keyId, versionId);
  const request = {
    name: keyVersionPath,
    digest: {
      sha256: hashBuffer
    }
  };

  // 执行签名
  const [response] = await kmsClient.asymmetricSign(request);
  return response.signature;
}

3. 转换签名格式为ethers.js兼容格式

GCP KMS返回的签名是DER编码的二进制数据,需要转换成ethers.js使用的r/s/v格式:

async function convertKmsSignatureToEthersFormat(kmsSignature, message, publicKey) {
  // 解析DER签名为r和s
  const {r, s} = utils.splitSignature(kmsSignature);
  
  // 计算v值(以太坊恢复ID,0或1)
  const address = utils.computeAddress(publicKey);
  let recoveredAddr = utils.verifyMessage(message, {r, s, v: 0}, publicKey);
  let v = 0;
  
  if (recoveredAddr.toLowerCase() !== address.toLowerCase()) {
    recoveredAddr = utils.verifyMessage(message, {r, s, v: 1}, publicKey);
    v = 1;
  }

  // 合并成ethers.js兼容的签名字符串
  return utils.joinSignature({r, s, v});
}

// 获取KMS密钥的公钥
async function getKmsPublicKey(projectId, location, keyRing, keyId, versionId) {
  const keyVersionPath = kmsClient.cryptoKeyVersionPath(projectId, location, keyRing, keyId, versionId);
  const [response] = await kmsClient.getPublicKey({name: keyVersionPath});
  
  // 转换PEM公钥为十六进制格式
  const pem = response.pem.replace(/-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\n/g, '');
  return `0x${Buffer.from(pem, 'base64').toString('hex')}`;
}

三、验证一致性

完成上述步骤后,用同一个消息分别调用wallet.signMessage和GCP KMS签名方法,得到的签名字符串应该完全一致,证明实现对齐。

四、权限说明

确保执行签名的服务账号拥有cloudkms.cryptoKeyVersions.signAsymmetric权限,否则会被KMS拒绝请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 05:12:48