1use defuse_crypto::{Curve, ed25519::Ed25519};
4use defuse_digest::{Digest, sha2::Sha256};
5
6pub struct Sep53;
8
9impl Sep53 {
10 #[must_use = "check if verification passed"]
13 #[inline]
14 pub fn verify(
15 public_key: &<Ed25519 as Curve>::PublicKey,
16 msg: impl AsRef<[u8]>,
17 signature: &<Ed25519 as Curve>::Signature,
18 ) -> bool {
19 Ed25519::verify(public_key, &Self::prehash(msg.as_ref()), signature)
20 }
21
22 #[inline]
28 pub fn prehash(msg: impl AsRef<[u8]>) -> [u8; 32] {
29 Sha256::new_with_prefix(b"Stellar Signed Message:\n")
30 .chain_update(msg)
32 .finalize()
33 .into()
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use defuse_crypto::ed25519::{Ed25519PublicKey, Ed25519Signature};
40 use hex_literal::hex;
41 use rstest::rstest;
42 use stellar_strkey::Strkey;
43
44 use super::*;
45
46 #[rstest]
48 #[case::ascii(
49 "GBXFXNDLV4LSWA4VB7YIL5GBD7BVNR22SGBTDKMO2SBZZHDXSKZYCP7L",
50 "Hello, World!",
51 hex!("7cee5d6d885752104c85eea421dfdcb95abf01f1271d11c4bec3fcbd7874dccd6e2e98b97b8eb23b643cac4073bb77de5d07b0710139180ae9f3cbba78f2ba04"),
52 )]
53 #[case::japanese(
54 "GBXFXNDLV4LSWA4VB7YIL5GBD7BVNR22SGBTDKMO2SBZZHDXSKZYCP7L",
55 "こんにちは、世界!",
56 hex!("083536eb95ecf32dce59b07fe7a1fd8cf814b2ce46f40d2a16e4ea1f6cecd980e04e6fbef9d21f98011c785a81edb85f3776a6e7d942b435eb0adc07da4d4604"),
57 )]
58 #[case::binary(
59 "GBXFXNDLV4LSWA4VB7YIL5GBD7BVNR22SGBTDKMO2SBZZHDXSKZYCP7L",
60 hex!("db36433f5b1ad415417cb3fb4de78c937b146dac4091484184388d76b92c685a"),
61 hex!("540d7eee179f370bf634a49c1fa9fe4a58e3d7990b0207be336c04edfcc539ff8bd0c31bb2c0359b07c9651cb2ae104e4504657b5d17d43c69c7e50e23811b0d"),
62 )]
63 fn verify_ok(
64 #[case] address: &str,
65 #[case] msg: impl AsRef<[u8]>,
66 #[case] signature: impl Into<Ed25519Signature>,
67 ) {
68 let Strkey::PublicKeyEd25519(stellar_strkey::ed25519::PublicKey(public_key)) =
69 address.parse().unwrap()
70 else {
71 panic!("invalid ed25519 public key address");
72 };
73
74 assert!(
75 Sep53::verify(
76 &Ed25519PublicKey(public_key).try_into().unwrap(),
77 msg,
78 &signature.into().into(),
79 ),
80 "invalid signature",
81 );
82 }
83}