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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! Arbiter contract signature verification for client-side use.
//!
//! ## Trust model
//!
//! The Arbiter Service signs every contract it issues with an Ed25519 key derived
//! from its master seed. The public key is served at:
//!
//! ```text
//! POST https://harmoniis.com/api/graphql
//! { "query": "{ arbiterPubkey }" }
//! ```
//!
//! **The pubkey is never stored in the contract itself.** Clients must always
//! fetch it from the legitimate Harmoniis server — the same server they are
//! transacting with. This mirrors how browsers verify TLS certificates against
//! trusted certificate authorities: you don't trust a cert just because someone
//! hands it to you; you trust it because a known authority signed it.
//!
//! ## What is signed
//!
//! The signature covers **all immutable contract fields** via a SHA256 hash:
//!
//! ```text
//! SHA256(
//! len(contract_id) || contract_id
//! len(buyer_fp) || buyer_fp
//! len(amount_str) || amount_str (atomic units as integer string, e.g. "50000")
//! len(deadline) || deadline (RFC 3339)
//! len(contract_type) || contract_type ("service" | "product_digital" | "product_physical")
//! len(work_spec) || work_spec
//! len(reference_post) || reference_post
//! len(buyer_pk) || buyer_pk (armored PGP public key)
//! )
//! ```
//!
//! Length-prefix encoding ensures there is no ambiguity even when field values
//! contain special characters. If any field in DynamoDB is tampered with, the
//! Arbiter's own signature check fails on every subsequent contract operation.
//!
//! ## Usage
//!
//! ```no_run
//! use harmoniis_wallet::client::HarmoniisClient;
//! use harmoniis_wallet::arbiter;
//!
//! # async fn example() -> harmoniis_wallet::Result<()> {
//! let client = HarmoniisClient::new("https://harmoniis.com");
//!
//! // After receiving a contract from contracts/buy:
//! let ok = client.verify_contract_signature(
//! "CTR_2026_001234",
//! "buyer_fingerprint_hex",
//! 50_000_000,
//! "2026-03-01T12:00:00Z",
//! "service",
//! "500-word technical article",
//! "post_id_of_seller_listing",
//! "-----BEGIN PGP PUBLIC KEY BLOCK-----...",
//! "arbiter_signature_hex_from_issue_response",
//! ).await?;
//! assert!(ok, "reject contract if arbiter signature is invalid");
//! # Ok(())
//! # }
//! ```
use ;
use crateResult;
use crateIdentity;
/// Compute the canonical signed message for a contract issuance.
///
/// **Must match** `ArbiterKey::canonical_message` in the Harmoniis backend.
/// If you change the field list or encoding here, update both sides.
/// Verify an arbiter signature given a trusted public key (64-char hex Ed25519).
///
/// Prefer [`HarmoniisClient::verify_contract_signature`] which fetches the
/// pubkey from the server automatically. Only use this directly if you have
/// already obtained and cached a trusted pubkey from the legitimate server.