solders_keypair/presigner.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
use pyo3::prelude::*;
use solana_sdk::signer::{presigner::Presigner as PresignerOriginal, Signer as SignerTrait};
use solders_macros::{pyhash, richcmp_signer};
use solders_pubkey::Pubkey;
use solders_signature::Signature;
use solders_traits::{
handle_py_err, impl_signer_hash, RichcmpSigner, SignerTraitWrapper, ToSignerOriginal,
};
use solders_traits_core::{impl_display, PyHash};
#[derive(Clone, Debug, Default, PartialEq)]
#[pyclass(module = "solders.presigner", subclass)]
/// A signer that represents a :class:`~solders.signature.Signature` that has been
/// constructed externally. Performs a signature verification against the
/// expected message upon ``sign()`` requests to affirm its relationship to
/// the ``message`` bytes.
///
/// Args:
/// pubkey (Pubkey): The pubkey of the signer.
/// signature (Signature): The signature created by signing the message.
///
pub struct Presigner(pub PresignerOriginal);
#[pyhash]
#[richcmp_signer]
#[pymethods]
impl Presigner {
#[new]
pub fn new(pubkey: &Pubkey, signature: &Signature) -> Self {
PresignerOriginal::new(pubkey.as_ref(), signature.as_ref()).into()
}
#[pyo3(name = "pubkey")]
/// Get this signer's :class:`~solders.pubkey.Pubkey`.
///
/// Returns:
/// Pubkey: The pubkey of the presigner.
///
/// Example:
/// >>> from solders.keypair import Keypair
/// >>> from solders.pubkey import Pubkey
/// >>> seed_bytes = bytes([0] * 32)
/// >>> pubkey_bytes = b";j'\xbc\xce\xb6\xa4-b\xa3\xa8\xd0*o\rse2\x15w\x1d\xe2C\xa6:\xc0H\xa1\x8bY\xda)"
/// >>> kp = Keypair.from_bytes(seed_bytes + pubkey_bytes)
/// >>> assert kp.pubkey() == Pubkey(pubkey_bytes)
///
pub fn py_pubkey(&self) -> Pubkey {
self.pubkey().into()
}
#[pyo3(name = "sign_message")]
/// Verifies the signature of the presigner and returns it if valid.
///
/// Returns:
/// Signature: The signature assigned to this object.
///
/// Raises:
/// SignerError: if the signature is invalid.
///
/// Example:
///
/// >>> from solders.keypair import Keypair
/// >>> from solders.presigner import Presigner
/// >>> keypair = Keypair.from_seed(bytes([0] * 32))
/// >>> pubkey = keypair.pubkey()
/// >>> data = bytes([1])
/// >>> sig = keypair.sign_message(data)
/// >>> presigner = Presigner(pubkey, sig)
/// >>> assert presigner.pubkey() == pubkey
/// >>> assert presigner.sign_message(data) == sig
///
pub fn py_sign_message(&self, message: &[u8]) -> PyResult<Signature> {
handle_py_err(self.try_sign_message(message))
}
#[staticmethod]
#[pyo3(name = "default")]
/// Create a new default presigner.
///
/// Returns:
/// Presigner: The default presigner.
///
pub fn new_default() -> Self {
Self::default()
}
fn __repr__(&self) -> String {
format!("{self:#?}")
}
}
impl_display!(Presigner);
impl_signer_hash!(Presigner);
impl PyHash for Presigner {}
impl From<PresignerOriginal> for Presigner {
fn from(signer: PresignerOriginal) -> Self {
Self(signer)
}
}
impl ToSignerOriginal for Presigner {
fn to_inner(&self) -> Box<dyn SignerTrait> {
Box::new(self.0.clone())
}
}
impl SignerTraitWrapper for Presigner {}
impl RichcmpSigner for Presigner {}