问题描述
在 Zero to Monero book 中,我正在阅读 Schnorr signatures。第 2.3.4 节引用了 src/crypto/crypto.cpp
的 codebase 中的 random32_unbiased()
函数。我的理解是这个函数生成一个介于 1
和 l-1
(两者都包括在内)之间的随机整数,其中 l
是一个大整数。
那个函数是:
void random32_unbiased(unsigned char *bytes)
{
// l = 2^252 + 27742317777372353535851937790883648493.
// l fits 15 times in 32 bytes (iow,15 l is the highest multiple of l that fits in 32 bytes)
static const unsigned char limit[32] = { 0xe3,0x6a,0x67,0x72,0x8b,0xce,0x13,0x29,0x8f,0x30,0x82,0x8c,0x0b,0xa4,0x10,0x39,0x01,0x00,0xf0 };
while(1)
{
generate_random_bytes_thread_safe(32,bytes);
if (!less32(bytes,limit))
continue;
sc_reduce32(bytes);
if (sc_isnonzero(bytes))
break;
}
}
带有 static const unsigned char limit[32]
的行有什么用途?
我的主要问题是上面的问题,但总的来说,我对函数的工作原理不是很了解,因此也希望得到解释。
解决方法
Monero 使用 edwards25519
作为基础椭圆曲线,用于生成 EdDSA
(爱德华兹数字签名),以在 Monero 区块链上创建交易。
edwards25519
是复合阶曲线,也就是说,它不是像比特币使用的secp256k1
那样的素阶曲线。
由于这个事实,在加密上下文中,我们必须在曲线的素数阶子群中工作,因此出于安全原因,我们的群是素数。
门罗币的那个子群比实际曲线的阶数小约 8 倍!因此子组大小为l
,即2^252 + 27742317777372353535851937790883648493
因此,门罗币只能有 2^252 + 27742317777372353535851937790883648493
个有效的公钥,或者其他任何使用 edwards25519
的公钥
正如 James K. Polk 指出的那样,我们希望确保我们留在循环子群中,但不会在关键材料中引入偏差。
有趣的是,我将 l
放入 sagemath 中,将其乘以 15,结果确实适合 256 位。
255.906890595609
准确地说,16 次需要 256.000000000000000000000000000000000000005
位。数学哟。