Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generating a shared secret key returns a hex string with two extra bytes. #619

Closed
williambran opened this issue Oct 21, 2024 · 2 comments
Closed

Comments

@williambran
Copy link

williambran commented Oct 21, 2024

When we generate a sharedKey this way, we have two bytes at the beginning of the hexadecimal string. These two bytes vary between 02 and 03.

02bd31c0f26231b8e03500fa9d7eae20a275be3e89fc492a057714a43370629c38
036d87a58361d64e85fcc032055301413chee336e00c1852192e0e6a074b12383c

What do these two bytes represent, and how can we access them to remove them without having to process the final string?
function using
var sharedKey = privateKey.sharedSecretFromKeyAgreement(with: publickey)

@csjones
Copy link
Contributor

csjones commented Oct 21, 2024

Hey @williambran 👋

The two bytes you're seeing at the beginning of the hexadecimal string (either 02 or 03) correspond to the compressed point prefix used in elliptic curve cryptography. In your case, when generating the shared key via the secp256k1 elliptic curve, these bytes indicate the parity of the Y-coordinate for the public point:

  • 02 indicates that the Y-coordinate is even.
  • 03 indicates that the Y-coordinate is odd.

This prefix is part of the standard for compressed points and ensures that the elliptic curve point can be correctly reconstructed from just the X-coordinate. It’s important to note that this is not part of the actual shared secret, but rather metadata about the elliptic curve point since the shared keys in your example are using a compressed format.

How to Remove the Prefix

If you want to work only with the raw shared secret (i.e., use an X-Only Key format), you can drop the prefix by directly accessing the underlying bytes. Here’s a quick suggestion on how you can handle this:

let sharedKey = privateKey.sharedSecretFromKeyAgreement(with: publickey)
let xonlySharedKey = sharedKey.dataRepresentation.dropFirst()

print("Shared X-Only Key: \(String(bytes: xonlySharedKey.dataRepresentation))")

While this is the easiest, the key parity information will be gone. Alternatively, you could store the shared key in a public key structure to access only the x-only key and keep the key parity. Looks like this:

let sharedKey = privateKey.sharedSecretFromKeyAgreement(with: publickey)
let sharedPublicKey = try! secp256k1.KeyAgreement.PublicKey(dataRepresentation: sharedKey)

// Key parity is accessible with `sharedPublicKey.xonly.parity` 
print("Shared X-Only Key: \(String(bytes: sharedPublicKey.xonly.dataRepresentation))")

Let me know if that helps!

@williambran
Copy link
Author

It really did store the shared key in a public key and provided access to the x-only key. thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants