use crate::error::{Error, Result};
use crate::primitives::encoding::{from_hex, to_base58_check, to_hex};
use crate::primitives::hash::{hash160, sha256_hmac};
use crate::primitives::BigNumber;
use k256::elliptic_curve::group::prime::PrimeCurveAffine;
use k256::elliptic_curve::scalar::FromUintUnchecked;
use k256::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
use k256::{AffinePoint, EncodedPoint, ProjectivePoint, PublicKey as K256PublicKey, Scalar, U256};
use super::Signature;
#[derive(Clone)]
pub struct PublicKey {
inner: K256PublicKey,
}
impl PublicKey {
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
let encoded = EncodedPoint::from_bytes(bytes)
.map_err(|e| Error::InvalidPublicKey(format!("Invalid public key encoding: {}", e)))?;
let point = AffinePoint::from_encoded_point(&encoded);
if point.is_none().into() {
return Err(Error::InvalidPublicKey("Point not on curve".to_string()));
}
let inner = K256PublicKey::from_affine(point.unwrap())
.map_err(|_| Error::InvalidPublicKey("Invalid point".to_string()))?;
Ok(Self { inner })
}
pub fn from_hex(hex: &str) -> Result<Self> {
let bytes = from_hex(hex)?;
Self::from_bytes(&bytes)
}
pub fn from_private_key(private_key: &super::PrivateKey) -> Self {
private_key.public_key()
}
pub fn verify(&self, msg_hash: &[u8; 32], signature: &Signature) -> bool {
super::verify(msg_hash, signature, self)
}
pub fn to_compressed(&self) -> [u8; 33] {
let encoded = self.inner.to_encoded_point(true);
let bytes = encoded.as_bytes();
let mut result = [0u8; 33];
result.copy_from_slice(bytes);
result
}
pub fn to_uncompressed(&self) -> [u8; 65] {
let encoded = self.inner.to_encoded_point(false);
let bytes = encoded.as_bytes();
let mut result = [0u8; 65];
result.copy_from_slice(bytes);
result
}
pub fn to_hex(&self) -> String {
to_hex(&self.to_compressed())
}
pub fn to_hex_uncompressed(&self) -> String {
to_hex(&self.to_uncompressed())
}
pub fn x(&self) -> [u8; 32] {
let encoded = self.inner.to_encoded_point(false);
let x_bytes = encoded.x().expect("point not at infinity");
let mut result = [0u8; 32];
result.copy_from_slice(x_bytes);
result
}
pub fn y(&self) -> [u8; 32] {
let encoded = self.inner.to_encoded_point(false);
let y_bytes = encoded.y().expect("point not at infinity");
let mut result = [0u8; 32];
result.copy_from_slice(y_bytes);
result
}
pub fn y_is_even(&self) -> bool {
let y = self.y();
y[31] & 1 == 0
}
pub fn hash160(&self) -> [u8; 20] {
hash160(&self.to_compressed())
}
pub fn to_address(&self) -> String {
self.to_address_with_prefix(0x00)
}
pub fn to_address_with_prefix(&self, version: u8) -> String {
let hash = self.hash160();
to_base58_check(&hash, &[version])
}
pub fn derive_child(
&self,
other_privkey: &super::PrivateKey,
invoice_number: &str,
) -> Result<PublicKey> {
let shared_secret = self.derive_shared_secret(other_privkey)?;
let hmac = sha256_hmac(&shared_secret.to_compressed(), invoice_number.as_bytes());
let hmac_scalar = BigNumber::from_bytes_be(&hmac);
let order = BigNumber::secp256k1_order();
let hmac_mod = hmac_scalar.modulo(&order);
let hmac_bytes = hmac_mod.to_bytes_be(32);
let scalar = bytes_to_scalar(&hmac_bytes)?;
let generator = ProjectivePoint::GENERATOR;
let offset_point = generator * scalar;
let self_point = ProjectivePoint::from(*self.inner.as_affine());
let new_point = self_point + offset_point;
let new_affine = new_point.to_affine();
if new_affine.is_identity().into() {
return Err(Error::PointAtInfinity);
}
let new_pubkey = K256PublicKey::from_affine(new_affine)
.map_err(|_| Error::InvalidPublicKey("Result is invalid".to_string()))?;
Ok(Self { inner: new_pubkey })
}
pub fn mul_scalar(&self, scalar_bytes: &[u8; 32]) -> Result<PublicKey> {
let scalar = bytes_to_scalar(scalar_bytes)?;
let point = ProjectivePoint::from(*self.inner.as_affine());
let result = point * scalar;
let affine = result.to_affine();
if affine.is_identity().into() {
return Err(Error::PointAtInfinity);
}
let pubkey = K256PublicKey::from_affine(affine)
.map_err(|_| Error::InvalidPublicKey("Result is invalid".to_string()))?;
Ok(Self { inner: pubkey })
}
pub fn derive_shared_secret(&self, other_privkey: &super::PrivateKey) -> Result<PublicKey> {
let scalar_bytes = other_privkey.to_bytes();
self.mul_scalar(&scalar_bytes)
}
pub fn from_scalar_mul_generator(scalar_bytes: &[u8; 32]) -> Result<PublicKey> {
let scalar = bytes_to_scalar(scalar_bytes)?;
let generator = ProjectivePoint::GENERATOR;
let result = generator * scalar;
let affine = result.to_affine();
if affine.is_identity().into() {
return Err(Error::PointAtInfinity);
}
let pubkey = K256PublicKey::from_affine(affine)
.map_err(|_| Error::InvalidPublicKey("Result is invalid".to_string()))?;
Ok(Self { inner: pubkey })
}
pub fn add(&self, other: &PublicKey) -> Result<PublicKey> {
let self_point = ProjectivePoint::from(*self.inner.as_affine());
let other_point = ProjectivePoint::from(*other.inner.as_affine());
let result = self_point + other_point;
let affine = result.to_affine();
if affine.is_identity().into() {
return Err(Error::PointAtInfinity);
}
let pubkey = K256PublicKey::from_affine(affine)
.map_err(|_| Error::InvalidPublicKey("Result is invalid".to_string()))?;
Ok(Self { inner: pubkey })
}
pub fn is_valid(&self) -> bool {
let point = AffinePoint::from(self.inner);
!bool::from(point.is_identity())
}
pub(crate) fn from_k256(inner: K256PublicKey) -> Self {
Self { inner }
}
}
fn bytes_to_scalar(bytes: &[u8]) -> Result<Scalar> {
if bytes.len() != 32 {
return Err(Error::CryptoError(format!(
"Expected 32 bytes for scalar, got {}",
bytes.len()
)));
}
let uint = U256::from_be_slice(bytes);
let scalar = Scalar::from_uint_unchecked(uint);
Ok(scalar)
}
impl PartialEq for PublicKey {
fn eq(&self, other: &Self) -> bool {
self.to_compressed() == other.to_compressed()
}
}
impl Eq for PublicKey {}
impl std::fmt::Debug for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PublicKey")
.field("compressed", &self.to_hex())
.finish()
}
}
impl std::fmt::Display for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl std::hash::Hash for PublicKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.to_compressed().hash(state);
}
}
impl serde::Serialize for PublicKey {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_hex())
}
}
impl<'de> serde::Deserialize<'de> for PublicKey {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct PublicKeyVisitor;
impl serde::de::Visitor<'_> for PublicKeyVisitor {
type Value = PublicKey;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a hex-encoded public key string")
}
fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
where
E: serde::de::Error,
{
PublicKey::from_hex(v).map_err(serde::de::Error::custom)
}
}
deserializer.deserialize_str(PublicKeyVisitor)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_public_key_from_hex_compressed() {
let hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let pubkey = PublicKey::from_hex(hex).unwrap();
assert_eq!(pubkey.to_hex(), hex);
}
#[test]
fn test_public_key_from_hex_uncompressed() {
let hex = "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8";
let pubkey = PublicKey::from_hex(hex).unwrap();
assert_eq!(
pubkey.to_hex(),
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
);
}
#[test]
fn test_public_key_compression() {
let hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let pubkey = PublicKey::from_hex(hex).unwrap();
let compressed = pubkey.to_compressed();
assert_eq!(compressed.len(), 33);
assert!(compressed[0] == 0x02 || compressed[0] == 0x03);
let uncompressed = pubkey.to_uncompressed();
assert_eq!(uncompressed.len(), 65);
assert_eq!(uncompressed[0], 0x04);
}
#[test]
fn test_public_key_x_y_coordinates() {
let hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let pubkey = PublicKey::from_hex(hex).unwrap();
let x = pubkey.x();
assert_eq!(
to_hex(&x),
"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
);
assert!(pubkey.y_is_even());
}
#[test]
fn test_public_key_hash160() {
let hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let pubkey = PublicKey::from_hex(hex).unwrap();
let h160 = pubkey.hash160();
assert_eq!(h160.len(), 20);
}
#[test]
fn test_public_key_to_address() {
let hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let pubkey = PublicKey::from_hex(hex).unwrap();
let address = pubkey.to_address();
assert_eq!(address, "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH");
}
#[test]
fn test_public_key_equality() {
let hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let pubkey1 = PublicKey::from_hex(hex).unwrap();
let pubkey2 = PublicKey::from_hex(hex).unwrap();
assert_eq!(pubkey1, pubkey2);
}
#[test]
fn test_public_key_invalid_hex() {
assert!(PublicKey::from_hex("invalid").is_err());
assert!(PublicKey::from_hex("02").is_err());
}
#[test]
fn test_public_key_mul_scalar() {
let hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let pubkey = PublicKey::from_hex(hex).unwrap();
let mut scalar = [0u8; 32];
scalar[31] = 2;
let result = pubkey.mul_scalar(&scalar).unwrap();
assert!(result.to_hex() != pubkey.to_hex());
}
#[test]
fn test_from_scalar_mul_generator() {
let mut scalar_one = [0u8; 32];
scalar_one[31] = 1;
let result = PublicKey::from_scalar_mul_generator(&scalar_one).unwrap();
let g_hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let g = PublicKey::from_hex(g_hex).unwrap();
assert_eq!(result.to_compressed(), g.to_compressed());
}
#[test]
fn test_from_scalar_mul_generator_matches_private_key() {
use crate::primitives::PrivateKey;
let priv_key = PrivateKey::random();
let pub_key = priv_key.public_key();
let scalar_bytes = priv_key.to_bytes();
let from_scalar = PublicKey::from_scalar_mul_generator(&scalar_bytes).unwrap();
assert_eq!(pub_key.to_compressed(), from_scalar.to_compressed());
}
#[test]
fn test_public_key_add() {
let g_hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let g = PublicKey::from_hex(g_hex).unwrap();
let two_g_from_add = g.add(&g).unwrap();
let mut scalar_two = [0u8; 32];
scalar_two[31] = 2;
let two_g_from_mul = PublicKey::from_scalar_mul_generator(&scalar_two).unwrap();
assert_eq!(
two_g_from_add.to_compressed(),
two_g_from_mul.to_compressed()
);
}
#[test]
fn test_public_key_add_associative() {
use crate::primitives::PrivateKey;
let a = PrivateKey::random().public_key();
let b = PrivateKey::random().public_key();
let c = PrivateKey::random().public_key();
let ab = a.add(&b).unwrap();
let ab_c = ab.add(&c).unwrap();
let bc = b.add(&c).unwrap();
let a_bc = a.add(&bc).unwrap();
assert_eq!(ab_c.to_compressed(), a_bc.to_compressed());
}
#[test]
fn test_public_key_add_commutative() {
use crate::primitives::PrivateKey;
let a = PrivateKey::random().public_key();
let b = PrivateKey::random().public_key();
let a_plus_b = a.add(&b).unwrap();
let b_plus_a = b.add(&a).unwrap();
assert_eq!(a_plus_b.to_compressed(), b_plus_a.to_compressed());
}
#[test]
fn test_public_key_is_valid() {
use crate::primitives::PrivateKey;
let pubkey = PrivateKey::random().public_key();
assert!(pubkey.is_valid());
let g_hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
let g = PublicKey::from_hex(g_hex).unwrap();
assert!(g.is_valid());
assert!(PublicKey::from_hex(
"020000000000000000000000000000000000000000000000000000000000000000"
)
.is_err());
}
#[test]
fn test_public_key_uncompressed_x_changed_off_curve() {
let bytes: [u8; 65] = [
0x04, 0x15, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c,
0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1,
0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74,
0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f,
0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12, 0xa3,
];
assert!(PublicKey::from_bytes(&bytes).is_err());
}
#[test]
fn test_public_key_uncompressed_y_changed_off_curve() {
let bytes: [u8; 65] = [
0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c,
0x53, 0xbc, 0x1e, 0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 0xd7, 0xb1,
0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74,
0x44, 0x64, 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 0xd4, 0xc0, 0x3f,
0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 0xb4, 0x12, 0xa4,
];
assert!(PublicKey::from_bytes(&bytes).is_err());
}
#[test]
fn test_public_key_compressed_x_not_on_curve() {
let mut bytes = [0u8; 33];
bytes[0] = 0x02;
bytes[32] = 0x05;
assert!(PublicKey::from_bytes(&bytes).is_err());
}
}