soroban_sdk/testutils/
sign.rs

1#![cfg(any(test, feature = "testutils"))]
2
3/// Sign implementations produce signatures for types that can be represented as
4/// the MSG.
5pub trait Sign<MSG> {
6    type Signature;
7    type Error;
8    /// Sign produces a signature for MSGs.
9    fn sign(&self, m: MSG) -> Result<Self::Signature, Self::Error>;
10}
11
12// TODO: Add a Verify interface and ed25519 implementation to counter the Sign
13// interface.
14
15pub mod ed25519 {
16    use crate::xdr;
17    use xdr::{Limited, Limits, WriteXdr};
18
19    #[derive(Debug)]
20    pub enum Error<E: std::error::Error> {
21        XdrError(xdr::Error),
22        Ed25519SignatureError(ed25519_dalek::SignatureError),
23        ConversionError(E),
24    }
25
26    impl<E: std::error::Error> std::error::Error for Error<E> {
27        #[must_use]
28        fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
29            match self {
30                Self::XdrError(e) => e.source(),
31                Self::Ed25519SignatureError(e) => e.source(),
32                Self::ConversionError(e) => e.source(),
33            }
34        }
35    }
36
37    impl<E: std::error::Error> std::fmt::Display for Error<E> {
38        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
39            match self {
40                Self::XdrError(e) => write!(f, "{}", e),
41                Self::Ed25519SignatureError(e) => write!(f, "{}", e),
42                Self::ConversionError(e) => write!(f, "{}", e),
43            }
44        }
45    }
46
47    impl<E: std::error::Error> From<xdr::Error> for Error<E> {
48        fn from(e: xdr::Error) -> Self {
49            Error::XdrError(e)
50        }
51    }
52
53    impl<E: std::error::Error> From<ed25519_dalek::SignatureError> for Error<E> {
54        fn from(e: ed25519_dalek::SignatureError) -> Self {
55            Error::Ed25519SignatureError(e)
56        }
57    }
58
59    pub use super::Sign;
60
61    impl<S, M> Sign<M> for S
62    where
63        S: ed25519_dalek::Signer<ed25519_dalek::Signature>,
64        M: TryInto<xdr::ScVal>,
65        <M as TryInto<xdr::ScVal>>::Error: std::error::Error,
66    {
67        type Error = Error<<M as TryInto<xdr::ScVal>>::Error>;
68        type Signature = [u8; 64];
69        fn sign(&self, m: M) -> Result<Self::Signature, Self::Error> {
70            let mut buf = Vec::<u8>::new();
71            let val: xdr::ScVal = m.try_into().map_err(Self::Error::ConversionError)?;
72            val.write_xdr(&mut Limited::new(&mut buf, Limits::none()))?;
73            Ok(self.try_sign(&buf)?.to_bytes())
74        }
75    }
76
77    #[cfg(test)]
78    mod test {
79        use super::Sign;
80        use ed25519_dalek::SigningKey;
81
82        #[test]
83        fn sign() {
84            let sk = SigningKey::from_bytes(
85                &hex::decode("5acc7253295dfc356c046297925a369f3d2762d00afdf2583ecbe92180b07c37")
86                    .unwrap()
87                    .try_into()
88                    .unwrap(),
89            );
90            let sig = sk.sign(128i64).unwrap();
91            assert_eq!(
92                hex::encode(sig),
93                // Verified with https://go.dev/play/p/XiK8sOmvPsh
94                "a9b9dfac10bc1e5c8bc565e9515e5d086e3264b71bf4daf2c7340e1d10fae86e2563fa1d639ff153559a9710dfa270a9462fe87faa0e18a7a54a8a1a6151e909",
95            );
96        }
97    }
98}