use core::fmt;
use std::{
cmp::Ordering,
fmt::Debug,
hash::{Hash, Hasher},
};
use crate::{
codec::{Decoder, Encoder, NeoSerializable},
config::NeoConstants,
crypto::CryptoError,
neo_crypto::utils::{FromHexString, ToHexString},
};
use p256::{
ecdsa::{signature::Signer, Signature, SigningKey, VerifyingKey},
elliptic_curve::{
sec1::{FromEncodedPoint, ToEncodedPoint},
Field,
},
EncodedPoint, FieldBytes, PublicKey, SecretKey,
};
use primitive_types::U256;
use rand_core::OsRng;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use signature::{hazmat::PrehashSigner, SignerMut, Verifier};
#[cfg_attr(feature = "substrate", serde(crate = "serde_substrate"))]
#[derive(Debug, Clone)]
pub struct Secp256r1PublicKey {
inner: PublicKey,
}
#[derive(Debug, Clone)]
pub struct Secp256r1PrivateKey {
inner: SecretKey,
}
#[derive(Clone)]
pub struct Secp256r1Signature {
inner: Signature,
}
impl Debug for Secp256r1Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Secp256r1Signature")
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Secp256r1SignedMsg<T: Serialize> {
pub msg: T,
pub signature: Secp256r1Signature,
}
impl Secp256r1PublicKey {
pub fn new(gx: [u8; 32], gy: [u8; 32]) -> Option<Self> {
let mut uncompressed_point = Vec::with_capacity(65);
uncompressed_point.push(0x04);
uncompressed_point.extend_from_slice(&gx);
uncompressed_point.extend_from_slice(&gy);
let encoded_point = EncodedPoint::from_bytes(&uncompressed_point).ok()?;
let public_key_option = PublicKey::from_encoded_point(&encoded_point);
if public_key_option.is_some().into() {
let public_key = public_key_option.unwrap();
Some(Secp256r1PublicKey { inner: public_key })
} else {
None
}
}
pub fn from_public_key(public_key: PublicKey) -> Self {
Secp256r1PublicKey { inner: public_key }
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
if bytes.len() != 33 && bytes.len() != 65 {
return Err(CryptoError::InvalidPublicKey);
}
let point = if bytes.len() == 33 {
EncodedPoint::from_bytes(bytes).map_err(|_| CryptoError::InvalidPublicKey)?
} else {
EncodedPoint::from_bytes(bytes).map_err(|_| CryptoError::InvalidPublicKey)?
};
let public_key = PublicKey::from_encoded_point(&point);
if public_key.is_some().into() {
Ok(Self { inner: public_key.unwrap() })
} else {
Err(CryptoError::InvalidPublicKey)
}
}
pub fn verify(
&self,
message: &[u8],
signature: &Secp256r1Signature,
) -> Result<(), CryptoError> {
let verifying_key = VerifyingKey::from(&self.inner);
verifying_key
.verify(message, &signature.inner)
.map_err(|_| CryptoError::SignatureVerificationError)
}
pub fn get_encoded(&self, compressed: bool) -> Vec<u8> {
self.inner.to_encoded_point(compressed).as_bytes().to_vec()
}
pub fn get_encoded_point(&self, compressed: bool) -> EncodedPoint {
self.inner.to_encoded_point(compressed)
}
pub fn get_encoded_compressed_hex(&self) -> String {
let encoded = self.get_encoded(true);
encoded.to_hex_string()
}
pub fn from_encoded(encoded: &str) -> Option<Self> {
let encoded = &encoded.replace("0x", "");
let encoded = encoded.from_hex_string().ok()?;
Secp256r1PublicKey::from_bytes(encoded.as_slice()).ok()
}
fn get_size(&self) -> usize {
if self.inner.to_encoded_point(false).is_identity() {
1
} else {
NeoConstants::PUBLIC_KEY_SIZE_COMPRESSED as usize
}
}
}
impl Secp256r1PrivateKey {
pub fn new_random() -> Self {
let mut rng = OsRng;
Self::random(&mut rng)
}
pub fn random(rng: &mut OsRng) -> Self {
Self { inner: SecretKey::random(rng) }
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
if bytes.len() != 32 {
return Err(CryptoError::InvalidPrivateKey);
}
SecretKey::from_slice(bytes)
.map(|inner| Self { inner })
.map_err(|_| CryptoError::InvalidPrivateKey)
}
pub fn to_raw_bytes(&self) -> [u8; 32] {
self.inner
.clone()
.to_bytes()
.as_slice()
.try_into()
.expect("Private key should always be 32 bytes")
}
pub fn to_public_key(&self) -> Secp256r1PublicKey {
Secp256r1PublicKey::from_public_key(self.inner.public_key())
}
pub fn erase(&mut self) {
let bytes = [1u8; 32];
self.inner = SecretKey::from_bytes(&bytes.into())
.expect("Creating SecretKey from fixed bytes should never fail");
}
pub fn sign_tx(&self, message: &[u8]) -> Result<Secp256r1Signature, CryptoError> {
let signing_key = SigningKey::from_slice(&self.inner.to_bytes().as_slice())
.map_err(|_| CryptoError::InvalidPrivateKey)?;
let (signature, _) =
signing_key.try_sign(message).map_err(|_| CryptoError::SigningError)?;
Ok(Secp256r1Signature { inner: signature })
}
pub fn sign_prehash(&self, message: &[u8]) -> Result<Secp256r1Signature, CryptoError> {
let signing_key = SigningKey::from_slice(&self.inner.to_bytes().as_slice())
.map_err(|_| CryptoError::InvalidPrivateKey)?;
let (signature, _) =
signing_key.sign_prehash(message).map_err(|_| CryptoError::SigningError)?;
Ok(Secp256r1Signature { inner: signature })
}
}
impl Secp256r1Signature {
pub fn from_scalars(r: &[u8; 32], s: &[u8; 32]) -> Result<Self, CryptoError> {
let r_field: FieldBytes = (*r).into();
let s_field: FieldBytes = (*s).into();
let signature = Signature::from_scalars(r_field, s_field)
.map_err(|_| CryptoError::SignatureVerificationError)?;
Ok(Self { inner: signature })
}
pub fn from_u256(r: U256, s: U256) -> Result<Self, CryptoError> {
let x = r.to_big_endian();
let y = s.to_big_endian();
Secp256r1Signature::from_scalars(&x, &y)
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
if bytes.len() != 64 {
return Err(CryptoError::InvalidFormat("Invalid signature length".to_string()));
}
Signature::from_slice(bytes)
.map(|inner| Secp256r1Signature { inner })
.map_err(|_| CryptoError::InvalidFormat("Invalid signature format".to_string()))
}
pub fn to_bytes(&self) -> [u8; 64] {
let r_bytes: FieldBytes = self.inner.r().into();
let s_bytes: FieldBytes = self.inner.s().into();
let mut bytes = [0u8; 64];
bytes[..32].copy_from_slice(r_bytes.as_ref());
bytes[32..].copy_from_slice(s_bytes.as_ref());
bytes
}
}
impl fmt::Display for Secp256r1PrivateKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Secp256r1PrivateKey: {}\n", hex::encode(self.inner.to_bytes().as_slice()))
}
}
impl fmt::Display for Secp256r1PublicKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Secp256r1PublicKey: {}\n",
hex::encode(self.inner.to_encoded_point(false).as_bytes())
)
}
}
impl fmt::Display for Secp256r1Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Secp256r1Signature\n")?;
write!(f, "x: {}\n", hex::encode(&self.to_bytes()))
}
}
impl Serialize for Secp256r1PublicKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self.get_encoded(true))
}
}
impl Serialize for Secp256r1PrivateKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self.to_raw_bytes())
}
}
impl Serialize for Secp256r1Signature {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self.to_bytes())
}
}
impl<'de> Deserialize<'de> for Secp256r1PublicKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let bytes = <Vec<u8>>::deserialize(deserializer)?;
Secp256r1PublicKey::from_bytes(&bytes)
.map_err(|_| serde::de::Error::custom("Invalid public key"))
}
}
impl<'de> Deserialize<'de> for Secp256r1PrivateKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let bytes = <Vec<u8>>::deserialize(deserializer)?;
Secp256r1PrivateKey::from_bytes(&bytes)
.map_err(|_| serde::de::Error::custom("Invalid private key"))
}
}
impl<'de> Deserialize<'de> for Secp256r1Signature {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let bytes = <Vec<u8>>::deserialize(deserializer)?;
Secp256r1Signature::from_bytes(&bytes)
.map_err(|_| serde::de::Error::custom("Invalid signature"))
}
}
impl PartialEq for Secp256r1PublicKey {
fn eq(&self, other: &Secp256r1PublicKey) -> bool {
self.get_encoded(true) == other.get_encoded(true)
}
}
impl PartialOrd for Secp256r1PublicKey {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
let self_bytes = self.get_encoded(true);
let other_bytes = other.get_encoded(true);
self_bytes.partial_cmp(&other_bytes)
}
}
impl Eq for Secp256r1PublicKey {}
impl Ord for Secp256r1PublicKey {
fn cmp(&self, other: &Self) -> Ordering {
let self_bytes = self.get_encoded(true);
let other_bytes = other.get_encoded(true);
self_bytes.cmp(&other_bytes)
}
}
impl Hash for Secp256r1PublicKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.get_encoded(false).hash(state);
}
}
impl Hash for Secp256r1PrivateKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.to_raw_bytes().hash(state);
}
}
impl Hash for Secp256r1Signature {
fn hash<H: Hasher>(&self, state: &mut H) {
self.to_bytes().hash(state);
}
}
impl PartialEq for Secp256r1PrivateKey {
fn eq(&self, other: &Self) -> bool {
self.to_raw_bytes() == other.to_raw_bytes()
}
}
impl PartialEq for Secp256r1Signature {
fn eq(&self, other: &Self) -> bool {
self.to_bytes() == other.to_bytes()
}
}
impl From<Vec<u8>> for Secp256r1PublicKey {
fn from(bytes: Vec<u8>) -> Self {
Secp256r1PublicKey::from_bytes(&bytes).unwrap_or_else(|e| {
eprintln!("Warning: Failed to create public key from bytes: {}", e);
Secp256r1PublicKey::from_encoded(
"036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
)
.expect("Generator point should always be valid")
})
}
}
pub trait PrivateKeyExtension
where
Self: Sized,
{
fn to_vec(&self) -> Vec<u8>;
fn from_slice(slice: &[u8]) -> Result<Self, CryptoError>;
}
impl PrivateKeyExtension for Secp256r1PrivateKey {
fn to_vec(&self) -> Vec<u8> {
self.to_raw_bytes().to_vec()
}
fn from_slice(slice: &[u8]) -> Result<Self, CryptoError> {
if slice.len() != 32 {
return Err(CryptoError::InvalidPublicKey);
}
let mut arr = [0u8; 32];
arr.copy_from_slice(slice);
Self::from_bytes(&arr).map_err(|_| CryptoError::InvalidPublicKey)
}
}
pub trait PublicKeyExtension
where
Self: Sized,
{
fn to_vec(&self) -> Vec<u8>;
fn from_slice(slice: &[u8]) -> Result<Self, CryptoError>;
}
impl PublicKeyExtension for Secp256r1PublicKey {
fn to_vec(&self) -> Vec<u8> {
self.get_encoded(true)
}
fn from_slice(slice: &[u8]) -> Result<Self, CryptoError> {
if slice.len() != 64 && slice.len() != 33 {
return Err(CryptoError::InvalidPublicKey);
}
Self::from_slice(slice).map_err(|_| CryptoError::InvalidPublicKey)
}
}
impl NeoSerializable for Secp256r1PublicKey {
type Error = CryptoError;
fn size(&self) -> usize {
NeoConstants::PUBLIC_KEY_SIZE_COMPRESSED as usize
}
fn encode(&self, writer: &mut Encoder) {
writer.write_bytes(&self.get_encoded(true));
}
fn decode(reader: &mut Decoder) -> Result<Self, Self::Error> {
let bytes = reader
.read_bytes(NeoConstants::PUBLIC_KEY_SIZE_COMPRESSED as usize)
.map_err(|_| CryptoError::InvalidPublicKey)?;
Secp256r1PublicKey::from_bytes(&bytes).map_err(|_| CryptoError::InvalidPublicKey)
}
fn to_array(&self) -> Vec<u8> {
let mut writer = Encoder::new();
self.encode(&mut writer);
writer.to_bytes()
}
}
#[cfg(test)]
mod tests {
use hex_literal::hex;
use p256::EncodedPoint;
use crate::{
codec::{Decoder, NeoSerializable},
crypto::{
HashableForVec, Secp256r1PrivateKey, Secp256r1PublicKey, Secp256r1Signature, ToArray32,
},
neo_crypto::utils::{FromHexString, ToHexString},
};
const ENCODED_POINT: &str =
"03b4af8d061b6b320cce6c63bc4ec7894dce107bfc5f5ef5c68a93b4ad1e136816";
#[test]
fn test_new_public_key_from_point() {
let expected_x = hex!("b4af8d061b6b320cce6c63bc4ec7894dce107bfc5f5ef5c68a93b4ad1e136816");
let expected_y = hex!("5f4f7fb1c5862465543c06dd5a2aa414f6583f92a5cc3e1d4259df79bf6839c9");
let expected_ec_point =
EncodedPoint::from_affine_coordinates(&expected_x.into(), &expected_y.into(), false);
let enc_ec_point = "03b4af8d061b6b320cce6c63bc4ec7894dce107bfc5f5ef5c68a93b4ad1e136816";
let enc_ec_point_bytes = hex::decode(enc_ec_point).unwrap();
let pub_key = Secp256r1PublicKey::from_encoded(&enc_ec_point).unwrap();
assert_eq!(pub_key.get_encoded_point(false), expected_ec_point);
assert_eq!(pub_key.get_encoded(true), enc_ec_point_bytes);
assert_eq!(pub_key.get_encoded_compressed_hex(), enc_ec_point);
}
#[test]
fn test_new_public_key_from_uncompressed_point() {
let uncompressed = "04b4af8d061b6b320cce6c63bc4ec7894dce107bfc5f5ef5c68a93b4ad1e1368165f4f7fb1c5862465543c06dd5a2aa414f6583f92a5cc3e1d4259df79bf6839c9";
assert_eq!(
Secp256r1PublicKey::from_encoded(uncompressed)
.unwrap()
.get_encoded_compressed_hex(),
ENCODED_POINT
);
}
#[test]
fn test_new_public_key_from_string_with_invalid_size() {
let too_small = "03b4af8d061b6b320cce6c63bc4ec7894dce107bfc5f5ef5c68a93b4ad1e1368"; assert!(Secp256r1PublicKey::from_encoded(too_small).is_none());
}
#[test]
fn test_new_public_key_from_point_with_hex_prefix() {
let prefixed = format!("0x{ENCODED_POINT}");
let a = Secp256r1PublicKey::from_encoded(&prefixed).unwrap();
assert_eq!(a.get_encoded_compressed_hex(), ENCODED_POINT);
}
#[test]
fn test_serialize_public_key() {
let enc_point = "03b4af8d061b6b320cce6c63bc4ec7894dce107bfc5f5ef5c68a93b4ad1e136816";
let pub_key = Secp256r1PublicKey::from_encoded(&enc_point).unwrap();
assert_eq!(pub_key.to_array(), hex::decode(enc_point).unwrap());
}
#[test]
fn test_deserialize_public_key() {
let data = hex!("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296");
let mut decoder = Decoder::new(&data);
let public_key = Secp256r1PublicKey::decode(&mut decoder).unwrap();
assert_eq!(public_key.get_encoded(true).to_hex_string(), hex::encode(data));
}
#[test]
fn test_public_key_size() {
let mut key = Secp256r1PublicKey::from_encoded(
"036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
)
.unwrap();
assert_eq!(key.get_size(), 33);
}
#[test]
fn test_private_key_should_be_zero_after_erasing() {
let mut key = Secp256r1PrivateKey::from_bytes(&hex!(
"a7038726c5a127989d78593c423e3dad93b2d74db90a16c0a58468c9e6617a87"
))
.unwrap();
key.erase();
assert_eq!(key.to_raw_bytes(), [1u8; 32]);
}
#[test]
fn test_public_key_comparable() {
let encoded_key2 = "036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296";
let encoded_key1_uncompressed = "04b4af8d061b6b320cce6c63bc4ec7894dce107bfc5f5ef5c68a93b4ad1e1368165f4f7fb1c5862465543c06dd5a2aa414f6583f92a5cc3e1d4259df79bf6839c9";
let key1 = Secp256r1PublicKey::from_encoded(ENCODED_POINT).unwrap();
let key2 = Secp256r1PublicKey::from_encoded(encoded_key2).unwrap();
let key1_uncompressed =
Secp256r1PublicKey::from_encoded(encoded_key1_uncompressed).unwrap();
assert!(key1 > key2);
assert!(key1 == key1_uncompressed);
assert!(!(key1 < key1_uncompressed));
assert!(!(key1 > key1_uncompressed));
}
#[test]
fn test_sign_message() {
let private_key_hex = "9117f4bf9be717c9a90994326897f4243503accd06712162267e77f18b49c3a3";
let public_key_hex = "0265bf906bf385fbf3f777832e55a87991bcfbe19b097fb7c5ca2e4025a4d5e5d6";
let test_message = "A test message";
let private_key =
Secp256r1PrivateKey::from_bytes(&hex::decode(private_key_hex).unwrap()).unwrap();
let public_key =
Secp256r1PublicKey::from_bytes(&hex::decode(public_key_hex).unwrap()).unwrap();
assert_eq!(public_key.clone(), private_key.clone().to_public_key());
let hashed_msg = test_message.as_bytes().hash256();
let signature: Secp256r1Signature = private_key.clone().sign_tx(&hashed_msg).unwrap();
assert!(public_key.verify(&hashed_msg, &signature).is_ok());
}
}