PHP 中带有 ED25519 的 Blake2b-512 和 NanoSalt 库(Nano Crypto)

Blake2b-512 with ED25519 in PHP with NanoSalt library (Nano Crypto)

我正在尝试在 PHP 中生成 Nano 私钥、public 密钥和地址(这是一种加密货币)。我成功生成了私钥,但无法生成 public 密钥,因此无法生成校验和和整数地址。为此,我必须通过 blake2b-512 算法和 ED25119 曲线加密私钥,然后我必须通过加密 public 密钥通过 blake2b-40 算法获得校验和。那是我的代码:

$privatekey = strtoupper(bin2hex(random_bytes(32)));
$publickey = sodium_crypto_sign_ed25519_pk_to_curve25519($private_key);
$checksum = hash(blake2b-40, $publickey);

我没有得到我需要的东西。为什么?

2021 年 12 月 30 日更新 13:36

我正在尝试使用 NanoSalt 库解决更新问题,但出现此错误:

index.php

<?php
use MikeRow\Salt\NanoSalt;

$nanoSalt = new NanoSalt();
$public_key = $nanoSalt->crypto_sign_public_from_secret_key(hex2bin("781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3"));
print(strtoupper($public_key->toHex()) . PHP_EOL);
?>

这就是错误:

Fatal error: Uncaught Error: Class "MikeRow\Salt\NanoSalt" not found in C:\xampp\htdocs\Peppe\index.php:4 Stack trace: #0 {main} thrown in C:\xampp\htdocs\Peppe\index.php on line 4

PHP 7 >= 7.2.0 和 PHP 8 确实有一个内置的加密库“sodium”,可让您从给定的秘密中导出 ED25519 public 密钥(私钥):https://www.php.net/manual/en/function.sodium-crypto-sign-publickey-from-secretkey.php

下面是此任务的完整运行示例:

<?php
function generateEd25519KeyPair()
{
    return sodium_crypto_sign_keypair();
}

function deriveEd25519PublicKey($privateKey)
{
    return sodium_crypto_sign_publickey_from_secretkey ($privateKey);
}

function base64Encoding($input)
{
    return base64_encode($input);
}

echo 'Generate ED25519 private and public key and derive public key from private key' . PHP_EOL;
$keyPair = generateEd25519KeyPair();
$privateKey = sodium_crypto_sign_secretkey($keyPair);
$publicKey = sodium_crypto_sign_publickey($keyPair);
echo'privateKey (Base64): ' . base64Encoding($privateKey) . PHP_EOL;
echo'publicKey (Base64):  ' . base64Encoding($publicKey) . PHP_EOL;

echo PHP_EOL . 'derive the publicKey from the privateKey' . PHP_EOL;
$publicKeyDerived = deriveEd25519PublicKey($privateKey);
echo'publicKey (Base64):  ' . base64Encoding($publicKeyDerived) . PHP_EOL;
?>

Nano 不使用标准的 Ed25519,而是使用摘要 Blake2b-512 而不是通常的 SHA-512 的变体,请参阅 standard variant vs Nano variant。 =22=]

因此,通常无法使用标准 Libsodium 库,例如其他答案中提出的 sodium_crypto_sign_publickey_from_secretkey() 函数。除此之外,此函数需要一个 64 字节的密钥(由种子和 public 密钥组成),而在 Nano 中,私钥只有 32 字节(由种子组成)。


Nano 文档中的以下 example 显示了私钥、public 密钥和 public 地址:

"private": "781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3",
"public": "3068BB1CA04525BB0E416C485FE6A67FD52540227D267CC8B6E8DA958A7FA039",
"account": "nano_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx" 

使用 PHP 获取 public 密钥的一种方法是使用支持 Nano 的库。这样的图书馆例如Salt, which also contains the Nano variant。使用此库,public 键的确定很简单:

use MikeRow\Salt\NanoSalt;

$nanoSalt = new NanoSalt();
$public_key = $nanoSalt->crypto_sign_public_from_secret_key(hex2bin("781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3"));
print(strtoupper($public_key->toHex()) . PHP_EOL); // 3068BB1CA04525BB0E416C485FE6A67FD52540227D267CC8B6E8DA958A7FA039

使用示例中的私钥生成示例中的 public 密钥。

另一种获取public键的方法是使用支持Ed25519算法的库,这样就可以通过基点相乘得到public键。这样的图书馆例如phpseclib(虽然坦白说我没有测试过这种方式)。


public 地址是通过使用特殊的 Base32 变体对 public 密钥进行编码并附加同样采用 Base32 编码的校验和来获得的。校验和是 public 密钥的 Blake2b-40 散列,参见 here.

支持特殊 Base32 变体和 Blake2b 的库 NanoPHP. Since the Blake2b implementation is a bit cumbersome, this Blake2b 库可以替代使用。一个可能的实现是:

require "Uint.php";
require "Blake2b.php";

// publick key
$public_key = "3068bb1ca04525bb0e416c485fe6a67fd52540227d267cc8b6e8da958a7fa039";
$key = Uint::fromHex('0' . $public_key);
$key_base32 = $key->toString();
print($key_base32 . PHP_EOL);

// checksum
$blake40 = new Blake2b(5);
$hash = $blake40->hash(hex2bin($public_key));
$check = Uint::fromHex(bin2hex($hash))->reverse();
$check_base32 = $check->toString();
print($check_base32 . PHP_EOL);

print('nano_' . $key_base32 . $check_base32 . PHP_EOL); // nano_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx

其中 Uint.php 提供 Base32 编码并来自 NanoPHP 库,而 Blake2b.php 是更方便的 Blake2b 替代方案。

使用示例中的 public 键给出正确的地址。


要测试其他私钥,this site很有用。


关于安全性:请注意,所有使用的库都相当小,可能包含漏洞。