如何在Go中解压缩ECDH P256曲线上的单个X9.62压缩点?

e5nqia27  于 2023-03-27  发布在  Go
关注(0)|答案(2)|浏览(142)

Golang的椭圆曲线库可以在给定具有X和Y值的公共坐标(未压缩坐标)的情况下导出密钥。
但是,当给定的点是具有给定y位的X9.62压缩形式的单个值时,如何解压缩它?
OpenSSL使用以下方法处理此场景:
https://github.com/openssl/openssl/blob/4e9b720e90ec154c9708139e96ec0ff8e2796c82/include/openssl/ec.h#L494
似乎也有一个类似的问题涉及到数学,但不是Go的最佳实践,具体来说:
https://crypto.stackexchange.com/questions/8914/ecdsa-compressed-public-key-point-back-to-uncompressed-public-key-point
在Go中应该如何做到这一点?

jdzmm42g

jdzmm42g1#

据我所知,Go标准库(或“x”包)中没有点解压缩函数,所以你必须自己做(或找到现有的实现)。
实现并不太困难,尽管有几件事需要注意。
基本上,你需要将X的值插入曲线方程Y2 = X3 + aX + b,然后使用符号位确定你想要的两个根中的哪一个。棘手的是要记住,所有这些都需要对群的域素数取模。
我发现Go’s big integer package有时使用起来有点奇怪,因为它使用可变值,但它确实有一个模平方根函数,这使我们更容易。曲线参数在crypto/elliptic package中可用,尽管你需要知道这些曲线的a参数始终是-3
假设你有一个[]byte的压缩点(前面是0x020x03)在compressed_bytes中,即following should work。这是等式的一个非常直接的实现,我用注解和大量的命名变量来试图解释发生了什么。(和更短的)实现。它基本上是相同的,直到模平方根。

compressed_bytes := //...

// Split the sign byte from the rest
sign_byte := uint(compressed_bytes[0])
x_bytes := compressed_bytes[1:]

// Convert to big Int.
x := new(big.Int).SetBytes(x_bytes)

// We use 3 a couple of times
three := big.NewInt(3)

// and we need the curve params for P256
c := elliptic.P256().Params()

// The equation is y^2 = x^3 - 3x + b
// First, x^3, mod P
x_cubed := new(big.Int).Exp(x, three, c.P)

// Next, 3x, mod P
three_X := new(big.Int).Mul(x, three)
three_X.Mod(three_X, c.P)

// x^3 - 3x ...
y_squared := new(big.Int).Sub(x_cubed, three_X)

// ... + b mod P
y_squared.Add(y_squared, c.B)
y_squared.Mod(y_squared, c.P)

// Now we need to find the square root mod P.
// This is where Go's big int library redeems itself.
y := new(big.Int).ModSqrt(y_squared, c.P)
if y == nil {
    // If this happens then you're dealing with an invalid point.
    // Panic, return an error, whatever you want here.
}

// Finally, check if you have the correct root by comparing
// the low bit with the low bit of the sign byte. If it’s not
// the same you want -y mod P instead of y.
if y.Bit(0) != sign_byte & 1 {
    y.Neg(y)
    y.Mod(y, c.P)
}

// Now your y coordinate is in y, for all your ScalarMult needs.
rmbxnbpk

rmbxnbpk2#

在Go的后续版本中,这方面已经有所改进。现在可以使用UnmarshalCompressed方法。这是Go 1.15引入的。
示例:

x,y := elliptic.UnmarshalCompressed(elliptic.P224(), compressed)

相关问题