pub mod backend;
pub mod bls381;
pub mod bn254;
pub mod ecdsa;
pub mod ed25519;
pub mod error;
pub mod sr25519;
#[cfg(test)]
mod tests;
use crate::clients::tangle::runtime::TangleConfig;
#[cfg(any(feature = "std", feature = "wasm"))]
use alloy_signer_local::LocalSigner;
use eigensdk::crypto_bls;
pub use error::Error;
use k256::ecdsa::SigningKey;
use sp_core::{
crypto::{DeriveError, SecretStringError},
DeriveJunction, Pair,
};
use std::path::{Path, PathBuf};
use subxt_core::{
tx::signer::{PairSigner, Signer},
utils::{AccountId32, MultiAddress, MultiSignature},
};
#[cfg(any(feature = "std", feature = "wasm"))]
use tangle_subxt::subxt;
use w3f_bls::{Keypair, TinyBLS381};
#[cfg(any(feature = "std", feature = "wasm"))]
#[derive(Clone, Debug)]
pub struct TanglePairSigner<Pair> {
pub(crate) pair: subxt::tx::PairSigner<TangleConfig, Pair>,
}
#[cfg(any(feature = "std", feature = "wasm"))]
impl<Pair: sp_core::Pair> sp_core::crypto::CryptoType for TanglePairSigner<Pair> {
type Pair = Pair;
}
#[cfg(any(feature = "std", feature = "wasm"))]
impl<Pair: sp_core::Pair> TanglePairSigner<Pair>
where
<Pair as sp_core::Pair>::Signature: Into<MultiSignature>,
subxt::ext::sp_runtime::MultiSigner: From<<Pair as sp_core::Pair>::Public>,
{
pub fn new(pair: Pair) -> Self {
TanglePairSigner {
pair: PairSigner::new(pair),
}
}
pub fn into_inner(self) -> PairSigner<TangleConfig, Pair> {
self.pair
}
pub fn signer(&self) -> &Pair {
self.pair.signer()
}
}
#[cfg(any(feature = "std", feature = "wasm"))]
impl<Pair> Signer<TangleConfig> for TanglePairSigner<Pair>
where
Pair: sp_core::Pair,
Pair::Signature: Into<MultiSignature>,
{
fn account_id(&self) -> AccountId32 {
self.pair.account_id()
}
fn address(&self) -> MultiAddress<AccountId32, ()> {
self.pair.address()
}
fn sign(&self, signer_payload: &[u8]) -> MultiSignature {
self.pair.sign(signer_payload)
}
}
#[cfg(any(feature = "std", feature = "wasm"))]
impl<Pair: sp_core::Pair> sp_core::Pair for TanglePairSigner<Pair>
where
<Pair as sp_core::Pair>::Signature: Into<subxt::utils::MultiSignature>,
subxt::ext::sp_runtime::MultiSigner: From<<Pair as sp_core::Pair>::Public>,
{
type Public = Pair::Public;
type Seed = Pair::Seed;
type Signature = Pair::Signature;
fn derive<Iter: Iterator<Item = DeriveJunction>>(
&self,
path: Iter,
seed: Option<Self::Seed>,
) -> Result<(Self, Option<Self::Seed>), DeriveError> {
Pair::derive(self.pair.signer(), path, seed).map(|(pair, seed)| {
(
TanglePairSigner {
pair: PairSigner::new(pair),
},
seed,
)
})
}
fn from_seed_slice(seed: &[u8]) -> Result<Self, SecretStringError> {
Pair::from_seed_slice(seed).map(|pair| TanglePairSigner {
pair: PairSigner::new(pair),
})
}
fn sign(&self, message: &[u8]) -> Self::Signature {
Pair::sign(self.pair.signer(), message)
}
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
Pair::verify(sig, message, pubkey)
}
fn public(&self) -> Self::Public {
Pair::public(self.pair.signer())
}
fn to_raw_vec(&self) -> Vec<u8> {
Pair::to_raw_vec(self.pair.signer())
}
}
impl TanglePairSigner<sp_core::ecdsa::Pair> {
pub fn alloy_key(&self) -> Result<LocalSigner<SigningKey>, Error> {
let k256_ecdsa_secret_key = self.pair.signer().seed();
let res = LocalSigner::from_slice(&k256_ecdsa_secret_key)
.map_err(|err| Error::Alloy(err.to_string()))?;
Ok(res)
}
pub fn alloy_address(&self) -> Result<alloy_primitives::Address, Error> {
Ok(self.alloy_key()?.address())
}
}
pub trait Backend {
fn sr25519_generate_new(&self, seed: Option<&[u8]>) -> Result<sr25519::Public, Error>;
fn sr25519_sign(
&self,
public: &sr25519::Public,
msg: &[u8],
) -> Result<Option<sr25519::Signature>, Error>;
fn ed25519_generate_new(&self, seed: Option<&[u8]>) -> Result<ed25519::Public, Error>;
fn ed25519_sign(
&self,
public: &ed25519::Public,
msg: &[u8],
) -> Result<Option<ed25519::Signature>, Error>;
fn ecdsa_generate_new(&self, seed: Option<&[u8]>) -> Result<ecdsa::Public, Error>;
fn ecdsa_generate_from_string(&self, string: &str) -> Result<ecdsa::Public, Error>;
fn ecdsa_sign(
&self,
public: &ecdsa::Public,
msg: &[u8],
) -> Result<Option<ecdsa::Signature>, Error>;
fn bls381_generate_new(&self, seed: Option<&[u8]>) -> Result<bls381::Public, Error>;
fn bls381_sign(
&self,
public: &bls381::Public,
msg: &[u8],
) -> Result<Option<bls381::Signature>, Error>;
fn bls_bn254_generate_new(&self, seed: Option<&[u8]>) -> Result<bn254::Public, Error>;
fn bls_bn254_generate_from_string(&self, secret: String) -> Result<bn254::Public, Error>;
fn bls_bn254_sign(
&self,
public: &bn254::Public,
msg: &[u8; 32],
) -> Result<Option<bn254::Signature>, Error>;
fn expose_sr25519_secret(
&self,
public: &sr25519::Public,
) -> Result<Option<sr25519::Secret>, Error>;
fn expose_ecdsa_secret(&self, public: &ecdsa::Public) -> Result<Option<ecdsa::Secret>, Error>;
fn get_ecdsa_signer_string(&self, public: &k256::PublicKey) -> Result<String, Error>;
fn expose_ed25519_secret(
&self,
public: &ed25519::Public,
) -> Result<Option<ed25519::Secret>, Error>;
fn expose_bls381_secret(
&self,
public: &bls381::Public,
) -> Result<Option<bls381::Secret>, Error>;
fn expose_bls_bn254_secret(
&self,
public: &bn254::Public,
) -> Result<Option<bn254::Secret>, Error>;
fn iter_sr25519(&self) -> impl Iterator<Item = sr25519::Public>;
fn iter_ecdsa(&self) -> impl Iterator<Item = ecdsa::Public>;
fn iter_ed25519(&self) -> impl Iterator<Item = ed25519::Public>;
fn iter_bls381(&self) -> impl Iterator<Item = bls381::Public>;
fn iter_bls_bn254(&self) -> impl Iterator<Item = bn254::Public>;
}
pub trait BackendExt: Backend {
#[cfg(any(feature = "std", feature = "wasm"))]
fn ecdsa_key(&self) -> Result<TanglePairSigner<sp_core::ecdsa::Pair>, Error> {
let first_key = self
.iter_ecdsa()
.next()
.ok_or_else(|| Error::Ecdsa("No ECDSA Public Keys".to_string()))?;
let ecdsa_secret = self
.expose_ecdsa_secret(&first_key)?
.ok_or_else(|| Error::Ecdsa("No corresponding ECDSA secret key found".to_string()))?;
let mut seed = [0u8; 32];
seed.copy_from_slice(&ecdsa_secret.to_bytes()[0..32]);
Ok(TanglePairSigner {
pair: subxt::tx::PairSigner::new(sp_core::ecdsa::Pair::from_seed(&seed)),
})
}
#[cfg(any(feature = "std", feature = "wasm"))]
fn sr25519_key(&self) -> Result<TanglePairSigner<sp_core::sr25519::Pair>, Error> {
let first_key = self
.iter_sr25519()
.next()
.ok_or_else(|| Error::Sr25519("No Sr25519 public key found".to_string()))?;
let secret = self
.expose_sr25519_secret(&first_key)?
.ok_or_else(|| Error::Sr25519("No SR25519 secret found".to_string()))?;
let schnorrkel_kp = schnorrkel::Keypair::from(secret);
let pair = subxt::tx::PairSigner::new(schnorrkel_kp.into());
Ok(TanglePairSigner { pair })
}
fn ed25519_key(&self) -> Result<TanglePairSigner<sp_core::ed25519::Pair>, Error> {
let first_key = self
.iter_ed25519()
.next()
.ok_or_else(|| Error::Ed25519("No ED25519 keys found".to_string()))?;
let ed25519_secret = self
.expose_ed25519_secret(&first_key)?
.ok_or_else(|| Error::Ed25519("No ED25519 secret found".to_string()))?;
let mut seed = [0u8; 32];
seed.copy_from_slice(&ed25519_secret.as_ref()[0..32]);
Ok(TanglePairSigner {
pair: subxt::tx::PairSigner::new(sp_core::ed25519::Pair::from_seed(&seed)),
})
}
#[cfg(any(feature = "std", feature = "wasm"))]
fn bls381_key(&self) -> Result<Keypair<TinyBLS381>, Error> {
let first_key = self
.iter_bls381()
.next()
.ok_or_else(|| Error::Bls("No BLS 381 keys found".to_string()))?;
let bls_secret = self
.expose_bls381_secret(&first_key)?
.ok_or_else(|| Error::Bls("No BLS 381 secret found".to_string()))?;
Ok(w3f_bls::Keypair {
public: first_key,
secret: bls_secret,
})
}
#[cfg(any(feature = "std", feature = "wasm"))]
fn bls_bn254_key(&self) -> Result<crypto_bls::BlsKeyPair, Error> {
let first_key = self
.iter_bls_bn254()
.next()
.ok_or_else(|| Error::BlsBn254("No BLS BN254 keys found".to_string()))?;
let bls_secret = self
.expose_bls_bn254_secret(&first_key)?
.ok_or_else(|| Error::BlsBn254("No BLS BN254 secret found".to_string()))?;
crypto_bls::BlsKeyPair::new(bls_secret.to_string())
.map_err(|e| Error::BlsBn254(e.to_string()))
}
}
impl<T: Backend> BackendExt for T {}
pub trait KeystoreUriSanitizer: AsRef<Path> {
fn sanitize_file_path(&self) -> PathBuf {
let this: PathBuf = self.as_ref().to_path_buf();
let mut path = format!("{:?}", this.display());
path = path.replace("file:///", "/");
path = path.replace("file://", "/");
path = path.replace("file:/", "/");
path = path.replace("file:", "");
path = path.replace("\"", "");
path.into()
}
}
impl<T: AsRef<Path>> KeystoreUriSanitizer for T {}