将 X25519 转换为 curve25519-dalek 中的 Ed25519

问题描述 投票:0回答:1

对于只有 X25519 密钥对可用但我需要使用我所拥有的创建和验证签名的情况,我正在尝试将 X25519 公钥转换为 Ed25519 验证密钥,该密钥可以成功验证使用 X25519 所做的签名私钥。

虽然普遍不赞成(我知道原因,但如上所述,X25519 密钥对是我所拥有的一切),但有一个野外实现可以做到这一点,可以 C 代码的形式。我正在尝试遵循这个例子。

由于周围的软件使用 dalek 包,我也使用这个库来进行转换。我的公钥转换函数如下:

pub(crate) fn x25519_pub_to_ed25519_ver(
    public_key: [u8; 32],
) -> Result<VerifyingKey, SignatureError> {
    match MontgomeryPoint(public_key).to_edwards(SIGN_BIT) {
        None => Err(SignatureError::new()),
        Some(key) => VerifyingKey::from_bytes(key.compress().as_bytes()),
    }
}

这从蒙哥马利点计算爱德华兹点,我已经验证了to_edwards代码完全按照上面的参考代码linekd所做的事情。

对于签名方,我认为我需要确保使用能够产生正确符号的私钥,因为 X25519 和 Ed25519 公钥之间的转换不是 1:1。我的参考库还有一个如何生成匹配私钥的示例,我尝试模仿:

pub(crate) fn x25519_priv_to_ed25519_sig(private_key: &StaticSecret) -> SigningKey {
    let clamped = clamp_integer(private_key.to_bytes());
    let signing_key = SigningKey::from_bytes(&clamped);
    let test_public_key = signing_key.verifying_key().to_bytes();

    if (test_public_key[31] & 0x80) >> 7 == SIGN_BIT {
        signing_key
    } else {
        let scalar = Scalar::from_bytes_mod_order(clamped);
        let neg = scalar.invert();
        SigningKey::from_bytes(&neg.to_bytes())
    }
}

遗憾的是,我的测试代码不起作用,生成的公钥与直接从计算的 Ed25519 密钥导出的 Ed25519 验证密钥不匹配:

const TEST_MESSAGE: &[u8] = b"Das Pferd frisst keinen Gurkensalat.";

fn main() {
    let private_key = StaticSecret::random();
    println!("X25519 private key: {:02x?}", private_key.to_bytes());
    let public_key = PublicKey::from(&private_key);

    let signing_key = x25519_priv_to_ed25519_sig(&private_key);
    println!("Ed25519 signing key: {:02x?}", signing_key.to_bytes());
    let signature = signing_key.sign(TEST_MESSAGE);

    let verifying_key = x25519_pub_to_ed25519_ver(public_key.to_bytes()).unwrap();
    println!(
        "Transformed verifying key: {:02x?}",
        verifying_key.to_bytes()
    );
    println!(
        "Real verifying key: {:02x?}",
        signing_key.verifying_key().to_bytes()
    );
    let result = verifying_key.verify(TEST_MESSAGE, &signature);
    assert!(result.is_ok());
}

我在哪一点进行了错误的转换?

可以在 Codeberg

 上找到
可以使用 cargo 运行的最小工作示例。

rust cryptography elliptic-curve ed25519 x25519
1个回答
0
投票

verifying_key()
生成的
ed25519_dalek
并不是直接从标量乘以曲线得出的点。这是因为在真实的 Ed25519 中用于签名的秘密密钥不是标量本身,而是通过秘密标量进行 SHA-512 密钥派生的结果,产生 32 字节作为新标量和 32 字节作为伪随机哈希输入签名。

为了使签名和验证部分独立密钥派生工作,需要不同的密钥派生算法,如 Signal 的 XEdDSA 规范所述。

© www.soinside.com 2019 - 2024. All rights reserved.