-1

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

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

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

更新 30/12/2021 13:36

我正在尝试使用 NanoSalt 库解决更新,但它给了我这个错误:

索引.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
4

2 回答 2

0

PHP 7 >= 7.2.0 和 PHP 8 确实有一个内置的加密库“钠”,可以让您从给定的秘密(私有)密钥中派生 ED25519 公钥: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;
?>
于 2021-12-28T15:47:35.530 回答
0

Nano不使用标准 Ed25519,而是使用摘要 Blake2b-512 代替通常的 SHA-512 的变体,请参阅标准变体Nano 变体

出于这个原因,通常不能使用标准的 Libsodiumsodium_crypto_sign_publickey_from_secretkey()库,例如另一个答案中提出的函数。除此之外,这个函数需要一个 64 字节的密钥(由种子和公钥组成),而在 Nano 中,私钥只有 32 字节(由种子组成)。


Nano 文档中的以下示例显示了私钥、公钥和公共地址:

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

使用 PHP 获取公钥的一种方法是使用支持 Nano 的库。这样的库是例如Salt,它也包含Nano 变体。使用这个库,公钥的确定很简单:

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

使用示例中的私钥会产生示例中的公钥。

另一种获取公钥的方法是使用支持 Ed25519 算法的库,这样就可以通过乘以基点来获得公钥。这样的库是例如phpseclib(虽然坦率地说我没有测试过这种方式)。


公共地址是通过使用特殊的 Base32 变体对公钥进行编码并附加一个也是 Base32 编码的校验和来获得的。校验和是公钥的 Blake2b-40 哈希,请参见此处

支持特殊 Base32 变体和 Blake2b 的库是NanoPHP。由于 Blake2b 的实现有点麻烦,这个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 替代品。

使用示例中的公钥给出正确的地址。


要测试其他私钥,此站点很有用。


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

于 2021-12-29T17:24:25.327 回答