molpha_verifier/
message.rs1use solana_keccak_hasher::hashv;
4
5use crate::payload::AttestationPayload;
6
7pub const MESSAGE_PREFIX: [u8; 32] = [
11 0xa7, 0x55, 0x23, 0xa2, 0xab, 0x7b, 0x71, 0x8d, 0x9c, 0xff, 0xd2, 0xfa, 0x97, 0xed, 0x06, 0x9f,
12 0xc1, 0x21, 0x84, 0xea, 0xbe, 0xe7, 0xd5, 0x07, 0x85, 0x4d, 0x09, 0x22, 0xf7, 0x0e, 0x7f, 0xe7,
13];
14
15pub fn compute_message_hash(payload: &AttestationPayload, signers_bitmap: [u8; 32]) -> [u8; 32] {
25 let registry_version_bytes = payload.registry_version.to_be_bytes();
26 let signatures_required_bytes = payload.signatures_required.to_be_bytes();
27 let canonical_timestamp_bytes = payload.canonical_timestamp.to_be_bytes();
28
29 hashv(&[
30 MESSAGE_PREFIX.as_slice(),
31 payload.value.as_slice(),
32 payload.source_id.as_slice(),
33 registry_version_bytes.as_slice(),
34 signatures_required_bytes.as_slice(),
35 canonical_timestamp_bytes.as_slice(),
36 signers_bitmap.as_slice(),
37 ])
38 .to_bytes()
39}
40
41#[cfg(test)]
42mod tests {
43 use super::*;
44 use crate::fixtures::{
45 CANONICAL_TIMESTAMP, REGISTRY_VERSION, SIGNATURES_REQUIRED, SIGNERS_BITMAP, SOURCE_ID,
46 VALUE,
47 };
48
49 fn fixture_payload() -> AttestationPayload {
50 AttestationPayload {
51 value: VALUE,
52 source_id: SOURCE_ID,
53 registry_version: REGISTRY_VERSION,
54 signatures_required: SIGNATURES_REQUIRED,
55 canonical_timestamp: CANONICAL_TIMESTAMP,
56 }
57 }
58
59 fn fixture_signers_bitmap() -> [u8; 32] {
60 SIGNERS_BITMAP
61 }
62
63 #[test]
64 fn message_prefix_is_keccak_of_domain() {
65 let expected = hashv(&[b"MOLPHA_MESSAGE_V1"]).to_bytes();
66 assert_eq!(MESSAGE_PREFIX, expected);
67 }
68
69 #[test]
70 fn compute_message_hash_is_deterministic() {
71 let p = fixture_payload();
72 assert_eq!(
73 compute_message_hash(&p, fixture_signers_bitmap()),
74 compute_message_hash(&p, fixture_signers_bitmap())
75 );
76 }
77
78 #[test]
79 fn compute_message_hash_is_sensitive_to_each_field() {
80 let base = fixture_payload();
81 let base_hash = compute_message_hash(&base, fixture_signers_bitmap());
82
83 let mut a = fixture_payload();
84 a.registry_version += 1;
85 assert_ne!(
86 compute_message_hash(&a, fixture_signers_bitmap()),
87 base_hash
88 );
89
90 let mut b = fixture_payload();
91 b.signatures_required += 1;
92 assert_ne!(
93 compute_message_hash(&b, fixture_signers_bitmap()),
94 base_hash
95 );
96
97 let c = fixture_payload();
98 let mut signers_bitmap = fixture_signers_bitmap();
99 signers_bitmap[31] ^= 0x01;
100 assert_ne!(compute_message_hash(&c, signers_bitmap), base_hash);
101
102 let mut d = fixture_payload();
103 d.value[0] ^= 0xff;
104 assert_ne!(
105 compute_message_hash(&d, fixture_signers_bitmap()),
106 base_hash
107 );
108
109 let mut e = fixture_payload();
110 e.canonical_timestamp += 1;
111 assert_ne!(
112 compute_message_hash(&e, fixture_signers_bitmap()),
113 base_hash
114 );
115
116 let mut f = fixture_payload();
117 f.source_id[0] ^= 0xff;
118 assert_ne!(
119 compute_message_hash(&f, fixture_signers_bitmap()),
120 base_hash
121 );
122 }
123}