Closed paulh69 closed 4 years ago
What does you Golang code look like so far?
plenty of non-working examples:
// https://play.golang.org/p/2Wyt0tG0MS - pubkey points decompression - non-working
package main
import ( "crypto/elliptic" "encoding/hex" "fmt" "math/big" )
func main() {
// Points are decompressed by solving for y in the equation used for secp256k1's elliptic curve where x is the last 32 bytes of your public key.
// The equation is y^2 = x^3 + 7. You will get 2 possible y values, one even and one odd. The correct one is indicated by the prefix byte of your
// public key which indicates whether y is even or odd.
// Note that all operations must be modulo p which is defined by secp256k1's spec as being 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F.
//
// Example value, generated from Ruby OpenSSL bindings
// compressed_hex := "02A8825EBBF4054E83560EC27A0A9143D272586A0193F1299F6B00A0A62B6A9FF8" // expected output y=76522963597422956337536269116481171608116861681996601930470996322015033166962 // compressed_hex := "05cf85155acd39922c881b61861b6ca9114628ff9f7f5c490a3a652d2125d09e12" // expected output for x=04cf85155acd39922c881b61861b6ca9114628ff9f7f5c490a3a652d2125d09e12 // y=d95e98b2e1b9fd9eb26d1e57639ad8f9a92e9bc453a828686364668a2d912885 compressed_hex := "047a488354d9d5414de09b7121b80b973c991b76998ad68756d8cf4560c0ddcbe2" // expected output (047a488354d9d5414de09b7121b80b973c991b76998ad68756d8cf4560c0ddcbe24ae72a77cca86f6d1d11b1b796e3f14caa5852e6d4c60e9bebedc71673b58ec0) // y=4ae72a77cca86f6d1d11b1b796e3f14caa5852e6d4c60e9bebedc71673b58ec0 // check with https://iancoleman.io/bitcoin-key-compression/
compressed_bytes, _ := hex.DecodeString(compressed_hex)
// 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)
// The params for P256
c := elliptic.P256().Params()
// The equation is y^2 = x^3 - 3x + b
// x^3, mod P
x_cubed := new(big.Int).Exp(x, three, c.P)
// 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.
fmt.Println("Invalid point")
return
}
// Finally, check if you have the correct root. If not you want
// -y mod P
if y.Bit(0) != sign_byte & 1 {
y.Neg(y)
y.Mod(y, c.P)
}
fmt.Printf("y coord is %v\n", y)
}
another example would be https://github.com/btcsuite/btcd/blob/master/btcec/pubkey.go
You're using the wrong curve parameters in your code: https://www.johndcook.com/blog/2018/08/21/a-tale-of-two-elliptic-curves/
Also, I cannot help you any further than this. Based on the repositories you have forked and the questions you are are asking, it doesn't appear to me that you're embarking upon an entirely noble pursuit.
struggling to add working pubkey point decompression script. I've seen python examples but unable to get the math to workout quite the same in golang at the moment
e.g. https://bitcoin.stackexchange.com/questions/86234/how-to-uncompress-a-public-key
! /usr/bin/env python3
import binascii
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
def decompress_pubkey(pk): x = int.from_bytes(pk[1:33], byteorder='big') y_sq = (pow(x, 3, p) + 7) % p y = pow(y_sq, (p + 1) // 4, p) if y % 2 != pk[0] % 2: y = p - y y = y.to_bytes(32, byteorder='big') return b'\x04' + pk[1:33] + y
print(binascii.hexlify(decompress_pubkey(binascii.unhexlify('0229b3e0919adc41a316aad4f41444d9bf3a9b639550f2aa735676ffff25ba3898'))).decode()) print(binascii.hexlify(decompress_pubkey(binascii.unhexlify('02f15446771c5c585dd25d8d62df5195b77799aa8eac2f2196c54b73ca05f72f27'))).decode())