use crate::PrimitiveError;
use alloy::{primitives::Address, signers::local::PrivateKeySigner};
use eddsa_babyjubjub::{EdDSAPrivateKey, EdDSAPublicKey};
use secrecy::{ExposeSecret, SecretBox};
#[derive(Debug)]
pub struct Signer {
onchain_signer: PrivateKeySigner,
offchain_signer: SecretBox<EdDSAPrivateKey>,
}
impl Signer {
pub fn from_seed_bytes(seed: &[u8]) -> Result<Self, PrimitiveError> {
if seed.len() != 32 {
return Err(PrimitiveError::InvalidInput {
attribute: "seed".to_string(),
reason: format!("must be 32 bytes, got {} bytes", seed.len()),
});
}
let bytes: [u8; 32] = seed.try_into().map_err(|_| PrimitiveError::InvalidInput {
attribute: "seed".to_string(),
reason: "failed to convert to [u8; 32]".to_string(),
})?;
let onchain_signer = PrivateKeySigner::from_bytes(&bytes.into()).map_err(|e| {
PrimitiveError::InvalidInput {
attribute: "seed".to_string(),
reason: format!("invalid private key: {e}"),
}
})?;
let offchain_signer = SecretBox::new(Box::new(EdDSAPrivateKey::from_bytes(bytes)));
Ok(Self {
onchain_signer,
offchain_signer,
})
}
#[expect(
clippy::missing_const_for_fn,
reason = "cannot be initialized at compile time"
)]
pub fn onchain_signer(&self) -> &PrivateKeySigner {
&self.onchain_signer
}
pub const fn offchain_signer_private_key(&self) -> &SecretBox<EdDSAPrivateKey> {
&self.offchain_signer
}
pub const fn onchain_signer_address(&self) -> Address {
self.onchain_signer.address()
}
pub fn offchain_signer_pubkey(&self) -> EdDSAPublicKey {
self.offchain_signer.expose_secret().public()
}
}