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 替代品。
使用示例中的公钥给出正确的地址。
要测试其他私钥,此站点很有用。
关于安全性:请注意,使用的所有库都相当小,并且可能包含漏洞。