use crate::{
address::{SubstrateAddress, SubstrateCryptoScheme},
error::{Result, SignerError},
ext::PairExt,
};
use alloc::{format, string::String, vec::Vec};
use derive_more::{AsRef, From, Into};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use sp_core::{
crypto::{ByteArray, Pair as PairTrait},
ed25519::{Pair as SpPair, Public as SpPublic, Signature as SpSignature},
};
#[cfg(all(feature = "serde", feature = "keyring"))]
pub mod keyring;
#[cfg(all(feature = "serde", feature = "keyring"))]
pub use keyring::{Ed25519Codec, Keyring, Keystore};
pub type Seed = <SpPair as PairTrait>::Seed;
#[derive(Debug, Clone, Copy)]
pub struct Ed25519;
#[derive(Clone, From)]
pub struct PrivateKey(SpPair);
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "codec",
derive(parity_scale_codec::Encode, parity_scale_codec::Decode)
)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, From, Into, AsRef)]
pub struct PublicKey(SpPublic);
#[cfg_attr(
feature = "codec",
derive(parity_scale_codec::Encode, parity_scale_codec::Decode)
)]
#[derive(Clone, Copy, PartialEq, Eq, From, Into, AsRef)]
pub struct Signature(SpSignature);
impl PrivateKey {
#[cfg(feature = "std")]
pub fn random() -> Self {
Self(SpPair::generate().0)
}
pub fn from_pair_seed(seed: Seed) -> Self {
Self(SpPair::from_seed(&seed))
}
pub fn from_seed(seed: [u8; 32]) -> Result<Self> {
SpPair::from_seed_bytes(&seed).map(Self)
}
pub fn from_suri(suri: &str, password: Option<&str>) -> Result<Self> {
SpPair::from_suri_ext(suri, password).map(Self)
}
pub fn from_phrase(phrase: &str, password: Option<&str>) -> Result<Self> {
SpPair::from_phrase_ext(phrase, password).map(Self)
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0.seed()
}
pub fn as_pair(&self) -> &SpPair {
&self.0
}
pub fn public_key(&self) -> PublicKey {
PublicKey(self.0.public())
}
pub fn seed(&self) -> Seed {
self.0.seed()
}
}
impl core::fmt::Debug for PrivateKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "PrivateKey(0x{}...)", &hex::encode(&self.seed()[..4]))
}
}
#[cfg(feature = "keyring")]
impl crate::keyring::PrivateKeyOps for PrivateKey {
type PublicKey = PublicKey;
fn public_key(&self) -> Self::PublicKey {
self.public_key()
}
fn random() -> Self {
Self::random()
}
}
#[cfg(feature = "keyring")]
impl crate::keyring::PublicKeyBytes for PublicKey {
fn to_bytes(&self) -> [u8; 32] {
self.0
.as_slice()
.try_into()
.expect("ed25519 public key is 32 bytes")
}
fn from_bytes(bytes: [u8; 32]) -> Self {
Self(sp_core::ed25519::Public::from_raw(bytes))
}
}
impl core::fmt::Display for PrivateKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("<redacted>")
}
}
impl PartialEq for PrivateKey {
fn eq(&self, other: &Self) -> bool {
self.to_bytes() == other.to_bytes()
}
}
impl Eq for PrivateKey {}
#[cfg(feature = "serde")]
impl Serialize for PrivateKey {
fn serialize<S: serde::Serializer>(&self, s: S) -> core::result::Result<S::Ok, S::Error> {
s.serialize_bytes(self.seed().as_ref())
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for PrivateKey {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> core::result::Result<Self, D::Error> {
let bytes = <Vec<u8>>::deserialize(d)?;
if bytes.len() != 32 {
return Err(serde::de::Error::custom("Invalid ed25519 seed length"));
}
let mut seed = Seed::default();
seed.as_mut().copy_from_slice(&bytes);
Ok(Self::from_pair_seed(seed))
}
}
impl PublicKey {
pub fn from_bytes(bytes: [u8; 32]) -> Self {
Self(SpPublic::from_raw(bytes))
}
pub fn to_bytes(self) -> [u8; 32] {
self.0
.as_slice()
.try_into()
.expect("ed25519 public key is 32 bytes")
}
pub fn to_hex(self) -> String {
hex::encode(self.0.as_slice())
}
pub fn to_address(self) -> Result<SubstrateAddress> {
SubstrateAddress::new(self.to_bytes(), SubstrateCryptoScheme::Ed25519)
.map_err(|e| SignerError::InvalidAddress(e.to_string()))
}
}
impl core::fmt::Debug for PublicKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "PublicKey(0x{})", self.to_hex())
}
}
impl core::fmt::Display for PublicKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "0x{}", self.to_hex())
}
}
impl Signature {
pub fn from_bytes(bytes: [u8; 64]) -> Self {
Self(SpSignature::from_raw(bytes))
}
pub fn to_bytes(self) -> [u8; 64] {
self.0.into()
}
pub fn to_hex(self) -> String {
hex::encode(self.to_bytes())
}
}
impl core::fmt::Debug for Signature {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Signature(0x{}...)", &hex::encode(&self.to_bytes()[..8]))
}
}
#[cfg(feature = "serde")]
impl Serialize for Signature {
fn serialize<S: serde::Serializer>(&self, s: S) -> core::result::Result<S::Ok, S::Error> {
s.serialize_bytes(&self.to_bytes())
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Signature {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> core::result::Result<Self, D::Error> {
let bytes = <Vec<u8>>::deserialize(d)?;
if bytes.len() != 64 {
return Err(serde::de::Error::custom("Invalid ed25519 signature length"));
}
let mut arr = [0u8; 64];
arr.copy_from_slice(&bytes);
Ok(Self::from_bytes(arr))
}
}
impl crate::scheme::CryptoScheme for Ed25519 {
const NAME: &'static str = "ed25519";
const NAMESPACE: &'static str = "ed";
const PUBLIC_KEY_SIZE: usize = 32;
const SIGNATURE_SIZE: usize = 64;
type PrivateKey = PrivateKey;
type PublicKey = PublicKey;
type Signature = Signature;
type Address = SubstrateAddress;
type Seed = Seed;
#[cfg(feature = "std")]
fn generate_keypair() -> (Self::PrivateKey, Self::PublicKey) {
let private = PrivateKey::random();
let public = private.public_key();
(private, public)
}
fn public_key(private_key: &Self::PrivateKey) -> Self::PublicKey {
private_key.public_key()
}
fn sign(private_key: &Self::PrivateKey, data: &[u8]) -> Result<Self::Signature> {
Ok(Signature(private_key.as_pair().sign(data)))
}
fn verify(
public_key: &Self::PublicKey,
data: &[u8],
signature: &Self::Signature,
) -> Result<()> {
if SpPair::verify(&signature.0, data, &public_key.0) {
Ok(())
} else {
Err(SignerError::Crypto("Verification failed".into()))
}
}
fn to_address(public_key: &Self::PublicKey) -> Self::Address {
public_key.to_address().expect("valid address")
}
fn public_key_to_bytes(public_key: &Self::PublicKey) -> Vec<u8> {
public_key.to_bytes().to_vec()
}
fn public_key_from_bytes(bytes: &[u8]) -> Result<Self::PublicKey> {
if bytes.len() != 32 {
return Err(SignerError::InvalidKey(format!(
"Invalid ed25519 public key length: expected 32, got {}",
bytes.len()
)));
}
let mut arr = [0u8; 32];
arr.copy_from_slice(bytes);
Ok(PublicKey::from_bytes(arr))
}
fn signature_to_bytes(signature: &Self::Signature) -> Vec<u8> {
signature.to_bytes().to_vec()
}
fn signature_from_bytes(bytes: &[u8]) -> Result<Self::Signature> {
if bytes.len() != 64 {
return Err(SignerError::InvalidSignature(format!(
"Invalid ed25519 signature length: expected 64, got {}",
bytes.len()
)));
}
let mut arr = [0u8; 64];
arr.copy_from_slice(bytes);
Ok(Signature::from_bytes(arr))
}
fn address_to_string(address: &Self::Address) -> String {
address.to_string()
}
fn private_key_from_seed(seed: Self::Seed) -> Result<Self::PrivateKey> {
Ok(PrivateKey::from_pair_seed(seed))
}
fn private_key_to_seed(private_key: &Self::PrivateKey) -> Self::Seed {
private_key.seed()
}
#[cfg(feature = "std")]
fn private_key_from_suri(suri: &str, password: Option<&str>) -> Result<Self::PrivateKey> {
PrivateKey::from_suri(suri, password)
}
}
#[cfg(all(feature = "std", feature = "keyring", feature = "serde"))]
impl crate::keyring::KeyringScheme for Ed25519 {
type Keystore = keyring::Keystore;
fn namespace() -> &'static str {
crate::keyring::NAMESPACE_ED
}
fn keystore_from_private(
name: &str,
private_key: &Self::PrivateKey,
password: Option<&str>,
) -> Result<Self::Keystore> {
Ok(Self::Keystore::from_private_key_with_password(
name,
private_key.clone(),
password,
)?)
}
fn keystore_private(
keystore: &Self::Keystore,
password: Option<&str>,
) -> Result<Self::PrivateKey> {
Ok(keystore.private_key_with_password(password)?)
}
fn keystore_public(keystore: &Self::Keystore) -> Result<Self::PublicKey> {
Ok(keystore.public_key()?)
}
fn keystore_address(keystore: &Self::Keystore) -> Result<Self::Address> {
Ok(keystore.address()?)
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
use crate::scheme::CryptoScheme;
#[test]
fn keypair_generation() {
let (private, public) = Ed25519::generate_keypair();
assert_eq!(public, Ed25519::public_key(&private));
}
#[test]
fn sign_and_verify() {
let (private, public) = Ed25519::generate_keypair();
let sig = Ed25519::sign(&private, b"hello").unwrap();
Ed25519::verify(&public, b"hello", &sig).unwrap();
}
}