椭圆曲线点压缩算法不行,细微错误?
Elliptic curve point compression algorithm is not working, subtle error?
我尝试实现 JavaScript 代码以从 处的压缩 P-256 X 点恢复 y 坐标。
在我看来,以下代码似乎与 .NET/C# 中的代码等效,但这似乎不起作用,因为结果不正确。所以可以断定代码有问题,但我似乎无法发现问题所在。也许其他人可以看到它?
/*
Curves and their primes
NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1
NIST P-384 (secp384r1) 2^384 - 2^128 - 2^96 + 2^32 - 1
NIST P-521 (secp521r1) 2^521 - 1
const two = new bigInt(2),
// 115792089210356248762697446949407573530086143415290314195533631308867097853951
prime = two.pow(256).sub( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).sub(1),
b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
// Pre-computed value, or literal
pIdent = prime.add(1).divide(4); // 28948022302589062190674361737351893382521535853822578548883407827216774463488
*/
var key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var keyParams = key.ExportParameters(includePrivateParameters: false);
var prime = BigInteger.Parse("115792089210356248762697446949407573530086143415290314195533631308867097853951");
var b = BigInteger.Parse("41058363725152142129326129780047268409114441015993725554835256314039467401291");
var pIdent = BigInteger.Parse("28948022302589062190674361737351893382521535853822578548883407827216774463488");
// Other combinations of isUnsighed and isBigEndian do not seem to work.
var xBig = new BigInteger(keyParams.Q.X, isUnsigned: false, isBigEndian: false);
var y = BigInteger.ModPow(BigInteger.Pow(xBig, 3) - (xBig * 3) + b, pIdent, prime);
// Either yarr0 or yarr1 should match with yParams. This is not the case here now. Calculation going wrong?
var yParams = keyParams.Q.Y;
var yarr0 = y.ToByteArray();
var yarr1 = (prime - y).ToByteArray();
(添加和检查 0x02
、0x03
或 0x04
的代码或被故意省略,因为默认情况下 .NET 不会这样做,并且不需要这种最小情况.这也缺少其他检查以查看点是否在曲线上等)
keyParams.Q.X
和 keyParams.Q.Y
将被解释为大端字节顺序的无符号字节数组。因此,将字节数组转换为 BigInteger
:
时要设置参数
var xBig = new BigInteger(keyParams.Q.X, isUnsigned: true, isBigEndian: true);
反向模拟:
var yarr0 = y.ToByteArray(true, true);
var yarr1 = (prime - y).ToByteArray(true, true);
通过这些更改,代码 returns 预期结果,即 yarr0
或 yarr1
等于 yParams
。
我尝试实现 JavaScript 代码以从 处的压缩 P-256 X 点恢复 y 坐标。
在我看来,以下代码似乎与 .NET/C# 中的代码等效,但这似乎不起作用,因为结果不正确。所以可以断定代码有问题,但我似乎无法发现问题所在。也许其他人可以看到它?
/*
Curves and their primes
NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1
NIST P-384 (secp384r1) 2^384 - 2^128 - 2^96 + 2^32 - 1
NIST P-521 (secp521r1) 2^521 - 1
const two = new bigInt(2),
// 115792089210356248762697446949407573530086143415290314195533631308867097853951
prime = two.pow(256).sub( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).sub(1),
b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
// Pre-computed value, or literal
pIdent = prime.add(1).divide(4); // 28948022302589062190674361737351893382521535853822578548883407827216774463488
*/
var key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var keyParams = key.ExportParameters(includePrivateParameters: false);
var prime = BigInteger.Parse("115792089210356248762697446949407573530086143415290314195533631308867097853951");
var b = BigInteger.Parse("41058363725152142129326129780047268409114441015993725554835256314039467401291");
var pIdent = BigInteger.Parse("28948022302589062190674361737351893382521535853822578548883407827216774463488");
// Other combinations of isUnsighed and isBigEndian do not seem to work.
var xBig = new BigInteger(keyParams.Q.X, isUnsigned: false, isBigEndian: false);
var y = BigInteger.ModPow(BigInteger.Pow(xBig, 3) - (xBig * 3) + b, pIdent, prime);
// Either yarr0 or yarr1 should match with yParams. This is not the case here now. Calculation going wrong?
var yParams = keyParams.Q.Y;
var yarr0 = y.ToByteArray();
var yarr1 = (prime - y).ToByteArray();
(添加和检查 0x02
、0x03
或 0x04
的代码或被故意省略,因为默认情况下 .NET 不会这样做,并且不需要这种最小情况.这也缺少其他检查以查看点是否在曲线上等)
keyParams.Q.X
和 keyParams.Q.Y
将被解释为大端字节顺序的无符号字节数组。因此,将字节数组转换为 BigInteger
:
var xBig = new BigInteger(keyParams.Q.X, isUnsigned: true, isBigEndian: true);
反向模拟:
var yarr0 = y.ToByteArray(true, true);
var yarr1 = (prime - y).ToByteArray(true, true);
通过这些更改,代码 returns 预期结果,即 yarr0
或 yarr1
等于 yParams
。