world_id_primitives/
signer.rs1use crate::PrimitiveError;
2use alloy::{primitives::Address, signers::local::PrivateKeySigner};
3use eddsa_babyjubjub::{EdDSAPrivateKey, EdDSAPublicKey};
4use secrecy::{ExposeSecret, SecretBox};
5
6#[derive(Debug)]
10pub struct Signer {
11 onchain_signer: PrivateKeySigner,
13 offchain_signer: SecretBox<EdDSAPrivateKey>,
15}
16
17impl Signer {
18 pub fn from_seed_bytes(seed: &[u8]) -> Result<Self, PrimitiveError> {
23 if seed.len() != 32 {
24 return Err(PrimitiveError::InvalidInput {
25 attribute: "seed".to_string(),
26 reason: format!("must be 32 bytes, got {} bytes", seed.len()),
27 });
28 }
29 let bytes: [u8; 32] = seed.try_into().map_err(|_| PrimitiveError::InvalidInput {
30 attribute: "seed".to_string(),
31 reason: "failed to convert to [u8; 32]".to_string(),
32 })?;
33 let onchain_signer = PrivateKeySigner::from_bytes(&bytes.into()).map_err(|e| {
34 PrimitiveError::InvalidInput {
35 attribute: "seed".to_string(),
36 reason: format!("invalid private key: {e}"),
37 }
38 })?;
39 let offchain_signer = SecretBox::new(Box::new(EdDSAPrivateKey::from_bytes(bytes)));
40
41 Ok(Self {
42 onchain_signer,
43 offchain_signer,
44 })
45 }
46
47 #[expect(
49 clippy::missing_const_for_fn,
50 reason = "cannot be initialized at compile time"
51 )]
52 pub fn onchain_signer(&self) -> &PrivateKeySigner {
53 &self.onchain_signer
54 }
55
56 pub const fn offchain_signer_private_key(&self) -> &SecretBox<EdDSAPrivateKey> {
58 &self.offchain_signer
59 }
60
61 pub const fn onchain_signer_address(&self) -> Address {
63 self.onchain_signer.address()
64 }
65
66 pub fn offchain_signer_pubkey(&self) -> EdDSAPublicKey {
68 self.offchain_signer.expose_secret().public()
69 }
70}