Skip to main content

offline_protocol_core/
address.rs

1//! Self-certifying protocol addresses.
2//!
3//! An address is a bech32m encoding of `0x01 ‖ SHA-256(ed25519_pub)[..20]`,
4//! rendered as `off1…` (44 characters). Because the payload is a hash of the
5//! identity key, an address authenticates itself: a peer claiming an address
6//! can be checked by re-deriving it from the public key it presents, with no
7//! trust-on-first-use pin store in between.
8//!
9//! This module never touches key material — hashing happens upstream (see
10//! `MlsManager::derive_address`); [`Address`] is constructed from the already
11//! truncated hash.
12//!
13//! # Exactly one string form
14//!
15//! Every payload has exactly one accepted spelling. [`Address::from_str`]
16//! rejects uppercase input, the non-`m` bech32 checksum, wrong HRP, wrong
17//! version byte, wrong payload length, and — critically — encodings that
18//! decode to the right payload but are not the canonical spelling of it.
19//! The last class is not hypothetical: the `bech32` crate's decoder discards
20//! the trailing sub-byte bits without checking they are zero, and its
21//! fes-to-bytes length rule (`n * 5 / 8`) maps both 34- and 35-character data
22//! parts onto a 21-byte payload. Both shapes are checksum-valid and both are
23//! caught here by re-encoding and requiring byte-for-byte equality with the
24//! input. Briar's "spare bit" address bug is the reference failure for what
25//! happens when this is skipped.
26
27use alloc::string::{String, ToString};
28use alloc::vec::Vec;
29use core::fmt;
30use core::str::FromStr;
31
32use bech32::primitives::decode::CheckedHrpstring;
33use bech32::{Bech32m, Hrp};
34use serde::{Deserialize, Serialize};
35
36/// Why an address string was rejected by [`Address::from_str`].
37// Adding a variant to a public error enum is a breaking change without
38// this attribute; downstream crates must carry a wildcard arm.
39#[non_exhaustive]
40#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
41pub enum AddressError {
42    /// The string contains ASCII uppercase.
43    ///
44    /// BIP-173 permits an all-uppercase spelling and the `bech32` crate
45    /// accepts it; the protocol admits the lowercase form only.
46    #[error("address is not lowercase (the canonical form is lowercase-only)")]
47    NotLowercase,
48    /// The string is not structurally valid bech32m: bad charset, missing or
49    /// misplaced separator, mixed case, or a checksum that is absent, corrupt,
50    /// or computed with the original bech32 constant instead of bech32m.
51    #[error("address is not valid bech32m: {reason}")]
52    InvalidBech32m {
53        /// Rendering of the underlying `bech32` decode error.
54        reason: String,
55    },
56    /// Valid bech32m, but the human-readable part is not [`Address::HRP_STR`].
57    #[error("address has human-readable part '{found}', expected '{expected}'")]
58    HrpMismatch {
59        /// Human-readable part found in the input.
60        found: String,
61        /// The required human-readable part.
62        expected: &'static str,
63    },
64    /// The decoded payload is not [`Address::PAYLOAD_LEN`] bytes.
65    #[error("address payload is {len} bytes, expected {expected}")]
66    PayloadLength {
67        /// Decoded payload length.
68        len: usize,
69        /// Required payload length.
70        expected: usize,
71    },
72    /// The payload does not start with a supported version byte.
73    #[error("address version byte is {found:#04x}, expected {expected:#04x}")]
74    VersionMismatch {
75        /// Version byte found in the payload.
76        found: u8,
77        /// The only version byte this build understands.
78        expected: u8,
79    },
80    /// The string decodes to a well-formed payload but is not that payload's
81    /// canonical spelling — non-zero padding bits, or a data part padded out
82    /// with extra characters that truncate to the same bytes.
83    ///
84    /// Accepting these would give one identity several valid addresses, so
85    /// they are rejected rather than normalized.
86    #[error("address is a non-canonical encoding of its payload")]
87    NonCanonical,
88}
89
90/// A self-certifying protocol address: `off1…`.
91///
92/// # Ordering
93///
94/// [`Ord`] compares the underlying hash bytes, **not** the rendered string.
95/// The two orders differ: the bech32 charset (`qpzry9x8gf2tvdw0s3jn54khce6mua7l`)
96/// is not monotonic in ASCII — value 4 renders as `y` (0x79) and value 5 as
97/// `9` (0x39) — and a string comparison would also weigh the checksum
98/// characters.
99///
100/// **Which order a tiebreaker uses is fixed per site, and the sites disagree.**
101/// Both-create session ownership compares `Address` values (hash bytes); group
102/// leave election, admin auto-promotion and fork leader election sort rendered
103/// strings. Each converges on its own, because every peer running that
104/// tiebreaker sorts the same way.
105///
106/// Do not "harmonize" one site onto the other order. Peers that changed and
107/// peers that did not would then elect different winners from identical input,
108/// with no way to detect the disagreement locally. Prefer hash-byte order for
109/// anything new. See `docs/adr/0003-self-certifying-addresses.md`.
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
111pub struct Address {
112    hash: [u8; Address::HASH_LEN],
113}
114
115impl Address {
116    /// Human-readable part carried by every address.
117    pub const HRP_STR: &'static str = "off";
118
119    /// The only address version this build understands.
120    pub const VERSION: u8 = 0x01;
121
122    /// Length of the truncated identity-key hash, in bytes.
123    ///
124    /// 160 bits, which is a **second-preimage** margin of ~2^160 and a
125    /// **collision** margin of ~2^80 — the birthday bound on the same
126    /// truncation. Both are stated here because they buy different things and
127    /// only the first is what the impersonation claim rests on:
128    ///
129    /// - ~2^160 is the cost of aiming at an address that already exists:
130    ///   producing a key that derives to *someone else's* address. That is the
131    ///   attack the sender-derivation gate replaced the trust-pin store to
132    ///   stop, and it is the figure the guides and changelog quote.
133    /// - ~2^80 is the cost of producing *two* identity keys that share one
134    ///   address, neither fixed in advance. It impersonates nobody, but it does
135    ///   let a single entity hold two signing keys that are indistinguishable
136    ///   at the address layer — enough to equivocate, and enough to defeat the
137    ///   "one identity cannot hold two leaves" property that the MLS leaf
138    ///   binding otherwise inherits from MLS signature-key uniqueness.
139    ///
140    /// ~2^80 is below the ~2^128 a greenfield design would target, and is a
141    /// deliberate trade rather than an oversight: every mesh frame carries a
142    /// sender and a recipient address, and BLE budget is the binding
143    /// constraint. Widening the hash changes the wire, so it is a [`VERSION`]
144    /// bump and a migration, not a patch.
145    ///
146    /// [`VERSION`]: Address::VERSION
147    pub const HASH_LEN: usize = 20;
148
149    /// Length of the encoded payload: version byte followed by the hash.
150    pub const PAYLOAD_LEN: usize = 1 + Self::HASH_LEN;
151
152    /// Length of the canonical string form.
153    ///
154    /// `off` (3) + separator (1) + data (34) + checksum (6). The data part is
155    /// 34 characters because 21 bytes is 168 bits, which needs 34 five-bit
156    /// groups and leaves 2 padding bits.
157    pub const ENCODED_LEN: usize = 44;
158
159    /// `Hrp` form of [`Self::HRP_STR`].
160    ///
161    /// `parse_unchecked` is the only `const` constructor and performs no
162    /// validation; `hrp_const_matches_parsed` pins it against the checked
163    /// parser.
164    const HRP: Hrp = Hrp::parse_unchecked(Self::HRP_STR);
165
166    /// Builds an address from a truncated identity-key hash.
167    ///
168    /// Infallible: every 20-byte value is a valid address payload.
169    pub fn from_hash_bytes(hash: [u8; Self::HASH_LEN]) -> Self {
170        Self { hash }
171    }
172
173    /// Builds an address from a `version ‖ hash` payload.
174    pub fn from_payload(payload: &[u8]) -> Result<Self, AddressError> {
175        if payload.len() != Self::PAYLOAD_LEN {
176            return Err(AddressError::PayloadLength {
177                len: payload.len(),
178                expected: Self::PAYLOAD_LEN,
179            });
180        }
181        if payload[0] != Self::VERSION {
182            return Err(AddressError::VersionMismatch {
183                found: payload[0],
184                expected: Self::VERSION,
185            });
186        }
187        let mut hash = [0u8; Self::HASH_LEN];
188        hash.copy_from_slice(&payload[1..]);
189        Ok(Self { hash })
190    }
191
192    /// Returns the truncated identity-key hash.
193    pub fn hash_bytes(&self) -> &[u8; Self::HASH_LEN] {
194        &self.hash
195    }
196
197    /// Returns the `version ‖ hash` payload.
198    pub fn payload(&self) -> [u8; Self::PAYLOAD_LEN] {
199        let mut payload = [0u8; Self::PAYLOAD_LEN];
200        payload[0] = Self::VERSION;
201        payload[1..].copy_from_slice(&self.hash);
202        payload
203    }
204
205    /// Returns the address version byte.
206    pub fn version(&self) -> u8 {
207        Self::VERSION
208    }
209}
210
211impl fmt::Display for Address {
212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213        // `encode_lower_to_fmt` writes straight to the formatter and always
214        // emits lowercase. Its error covers only a formatter failure and an
215        // over-long code, the latter unreachable for a fixed 21-byte payload.
216        bech32::encode_lower_to_fmt::<Bech32m, _>(f, Self::HRP, &self.payload())
217            .map_err(|_| fmt::Error)
218    }
219}
220
221impl FromStr for Address {
222    type Err = AddressError;
223
224    fn from_str(s: &str) -> Result<Self, Self::Err> {
225        // The crate rejects mixed case but accepts an all-uppercase string;
226        // the protocol accepts one spelling, so screen case out first.
227        if s.bytes().any(|b| b.is_ascii_uppercase()) {
228            return Err(AddressError::NotLowercase);
229        }
230
231        // `CheckedHrpstring::new::<Bech32m>` pins the checksum algorithm.
232        // `bech32::decode` must never be used here: it validates bech32m and
233        // then silently falls back to the original bech32 constant.
234        let checked =
235            CheckedHrpstring::new::<Bech32m>(s).map_err(|e| AddressError::InvalidBech32m {
236                reason: e.to_string(),
237            })?;
238
239        if checked.hrp() != Self::HRP {
240            return Err(AddressError::HrpMismatch {
241                found: checked.hrp().to_string(),
242                expected: Self::HRP_STR,
243            });
244        }
245
246        let payload: Vec<u8> = checked.byte_iter().collect();
247        let address = Self::from_payload(&payload)?;
248
249        // Every remaining degree of freedom — the two padding bits, and a
250        // 35-character data part that truncates to the same 21 bytes — leaves
251        // a checksum-valid string that decodes to this exact payload, so no
252        // earlier check can see it. Re-encoding and requiring byte equality
253        // collapses them all: one payload, one string.
254        if address.to_string() != s {
255            return Err(AddressError::NonCanonical);
256        }
257
258        Ok(address)
259    }
260}
261
262impl Serialize for Address {
263    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
264        serializer.collect_str(self)
265    }
266}
267
268impl<'de> Deserialize<'de> for Address {
269    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
270        let s = String::deserialize(deserializer)?;
271        s.parse().map_err(serde::de::Error::custom)
272    }
273}
274
275#[cfg(all(test, feature = "std"))]
276mod tests {
277    use super::*;
278
279    // Golden vectors. Generated with the BIP-350 reference implementation
280    // (github.com/sipa/bech32, ref/python/segwit_addr.py) — an implementation
281    // independent of the `bech32` crate, so agreement between these literals
282    // and the code below is a genuine two-implementation cross-check.
283    //
284    // These strings are the protocol's addressing format. Changing one means
285    // every peer's identity changed: re-derive them from the reference
286    // implementation, never edit them to match new code output.
287
288    /// SHA-256 of the RFC 8032 §7.1 TEST 1 Ed25519 public key, truncated.
289    const RFC8032_TV1_HASH: [u8; 20] = [
290        0x21, 0xfe, 0x31, 0xdf, 0xa1, 0x54, 0xa2, 0x61, 0x62, 0x6b, 0xf8, 0x54, 0x04, 0x6f, 0xd2,
291        0x27, 0x1b, 0x7b, 0xed, 0x4b,
292    ];
293    const RFC8032_TV1_ADDR: &str = "off1qysluvwl5922yctzd0u9gpr06gn3k7ldfvgtwgvn";
294
295    const ZEROS_HASH: [u8; 20] = [0u8; 20];
296    const ZEROS_ADDR: &str = "off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqn8antf";
297
298    const FF_HASH: [u8; 20] = [0xffu8; 20];
299    const FF_ADDR: &str = "off1q8llllllllllllllllllllllllllllllluvweh4p";
300
301    const RAMP_HASH: [u8; 20] = [
302        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
303    ];
304    const RAMP_ADDR: &str = "off1qyqqzqsrqszsvpcgpy9qkrqdpc83qygjzvpgkpr5";
305
306    fn vectors() -> [([u8; 20], &'static str); 4] {
307        [
308            (RFC8032_TV1_HASH, RFC8032_TV1_ADDR),
309            (ZEROS_HASH, ZEROS_ADDR),
310            (FF_HASH, FF_ADDR),
311            (RAMP_HASH, RAMP_ADDR),
312        ]
313    }
314
315    #[test]
316    fn encodes_reference_vectors() {
317        for (hash, expected) in vectors() {
318            let rendered = Address::from_hash_bytes(hash).to_string();
319            assert_eq!(rendered, expected);
320            assert_eq!(rendered.len(), Address::ENCODED_LEN);
321        }
322    }
323
324    #[test]
325    fn decodes_reference_vectors() {
326        for (hash, encoded) in vectors() {
327            let address: Address = encoded.parse().expect("reference vector must parse");
328            assert_eq!(address.hash_bytes(), &hash);
329            assert_eq!(address.version(), Address::VERSION);
330        }
331    }
332
333    #[test]
334    fn reencoding_a_parsed_vector_is_byte_identical() {
335        for (_, encoded) in vectors() {
336            let address: Address = encoded.parse().expect("reference vector must parse");
337            assert_eq!(address.to_string(), encoded);
338        }
339    }
340
341    #[test]
342    fn roundtrips_arbitrary_hashes() {
343        // Deterministic spread without pulling in a rng dev-dependency.
344        let mut state: u64 = 0x2545_F491_4F6C_DD1D;
345        for _ in 0..256 {
346            let mut hash = [0u8; Address::HASH_LEN];
347            for byte in hash.iter_mut() {
348                state = state
349                    .wrapping_mul(6364136223846793005)
350                    .wrapping_add(1442695040888963407);
351                *byte = (state >> 33) as u8;
352            }
353            let address = Address::from_hash_bytes(hash);
354            let encoded = address.to_string();
355            assert_eq!(encoded.len(), Address::ENCODED_LEN);
356            assert_eq!(encoded.parse::<Address>().expect("roundtrip"), address);
357        }
358    }
359
360    #[test]
361    fn payload_roundtrips() {
362        let address = Address::from_hash_bytes(RAMP_HASH);
363        let payload = address.payload();
364        assert_eq!(payload[0], Address::VERSION);
365        assert_eq!(&payload[1..], &RAMP_HASH);
366        assert_eq!(Address::from_payload(&payload), Ok(address));
367    }
368
369    #[test]
370    fn hrp_const_matches_parsed() {
371        // `Hrp::parse_unchecked` performs no validation, so pin the const
372        // against the checked parser.
373        let parsed = Hrp::parse(Address::HRP_STR).expect("hrp must be valid");
374        assert_eq!(parsed, Address::HRP);
375    }
376
377    #[test]
378    fn serde_uses_the_canonical_string() {
379        let address = Address::from_hash_bytes(RFC8032_TV1_HASH);
380        let json = serde_json::to_string(&address).expect("serialize");
381        assert_eq!(json, format!("\"{RFC8032_TV1_ADDR}\""));
382        let back: Address = serde_json::from_str(&json).expect("deserialize");
383        assert_eq!(back, address);
384    }
385
386    #[test]
387    fn serde_rejects_non_canonical_forms() {
388        for bad in [
389            ZEROS_ADDR.to_uppercase(),
390            // Non-zero padding bits, valid checksum.
391            "off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqra5g99k".to_string(),
392        ] {
393            let json = format!("\"{bad}\"");
394            assert!(serde_json::from_str::<Address>(&json).is_err(), "{bad}");
395        }
396    }
397
398    #[test]
399    fn ord_follows_hash_bytes_not_the_rendered_string() {
400        let low = Address::from_hash_bytes(ZEROS_HASH);
401        let high = Address::from_hash_bytes(FF_HASH);
402        assert!(low < high);
403        assert_eq!(low.hash_bytes() < high.hash_bytes(), low < high);
404
405        // The two orders genuinely disagree, which is why tiebreakers must not
406        // compare rendered strings: value 4 encodes as 'y' (0x79) and value 5
407        // as '9' (0x39), inverting the comparison.
408        let mut a = ZEROS_HASH;
409        a[0] = 0x20; // leading fe = 4 -> 'y'
410        let mut b = ZEROS_HASH;
411        b[0] = 0x28; // leading fe = 5 -> '9'
412        let (a, b) = (Address::from_hash_bytes(a), Address::from_hash_bytes(b));
413        assert!(a < b, "byte order");
414        assert!(a.to_string() > b.to_string(), "string order inverts");
415    }
416
417    #[test]
418    fn rejects_uppercase_and_mixed_case() {
419        // All-uppercase is a valid bech32m string per BIP-173 and the crate
420        // accepts it; the protocol must not.
421        assert_eq!(
422            ZEROS_ADDR.to_uppercase().parse::<Address>(),
423            Err(AddressError::NotLowercase)
424        );
425        let mixed = format!("{}N8antf", &ZEROS_ADDR[..ZEROS_ADDR.len() - 6]);
426        assert_eq!(mixed.parse::<Address>(), Err(AddressError::NotLowercase));
427    }
428
429    #[test]
430    fn rejects_wrong_hrp() {
431        // Same payload, HRP "ofx", freshly checksummed.
432        let other = "ofx1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2e32t6";
433        assert_eq!(
434            other.parse::<Address>(),
435            Err(AddressError::HrpMismatch {
436                found: "ofx".to_string(),
437                expected: Address::HRP_STR,
438            })
439        );
440    }
441
442    #[test]
443    fn rejects_the_original_bech32_checksum() {
444        // Same payload and HRP, checksummed with bech32 instead of bech32m.
445        // `bech32::decode` would accept this; `CheckedHrpstring::<Bech32m>`
446        // must not.
447        let bech32_variant = "off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqxmdlwt";
448        assert!(matches!(
449            bech32_variant.parse::<Address>(),
450            Err(AddressError::InvalidBech32m { .. })
451        ));
452    }
453
454    #[test]
455    fn rejects_corrupted_characters() {
456        let mut corrupted = ZEROS_ADDR.to_string();
457        corrupted.pop();
458        corrupted.push('p'); // valid charset member, wrong checksum
459        assert!(matches!(
460            corrupted.parse::<Address>(),
461            Err(AddressError::InvalidBech32m { .. })
462        ));
463
464        // 'b', 'i', 'o' and '1' are excluded from the bech32 charset.
465        for bad_char in ['b', 'i', 'o'] {
466            let mut off_charset = ZEROS_ADDR.to_string();
467            off_charset.pop();
468            off_charset.push(bad_char);
469            assert!(
470                matches!(
471                    off_charset.parse::<Address>(),
472                    Err(AddressError::InvalidBech32m { .. })
473                ),
474                "{bad_char}"
475            );
476        }
477    }
478
479    #[test]
480    fn rejects_unsupported_version_bytes() {
481        for (encoded, expected_version) in [
482            ("off1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqkynkkv", 0x00u8),
483            ("off1qgqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqquz0u9x", 0x02),
484            ("off1luqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqn347dq", 0xff),
485        ] {
486            assert_eq!(
487                encoded.parse::<Address>(),
488                Err(AddressError::VersionMismatch {
489                    found: expected_version,
490                    expected: Address::VERSION,
491                })
492            );
493        }
494    }
495
496    #[test]
497    fn rejects_wrong_payload_lengths() {
498        // 20-byte payload (19-byte hash) and 22-byte payload (21-byte hash),
499        // each correctly checksummed.
500        for (encoded, len) in [
501            ("off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqxfx3pw", 20usize),
502            ("off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqkev2nx", 22),
503        ] {
504            assert_eq!(
505                encoded.parse::<Address>(),
506                Err(AddressError::PayloadLength {
507                    len,
508                    expected: Address::PAYLOAD_LEN,
509                })
510            );
511        }
512    }
513
514    #[test]
515    fn rejects_non_zero_padding_bits() {
516        // 21 bytes is 168 bits carried in 34 five-bit groups, leaving 2
517        // padding bits. Each mutant sets those bits and carries a freshly
518        // computed, valid bech32m checksum, so it decodes to exactly the
519        // all-zeros payload — the `bech32` crate discards the dirty bits
520        // without complaint. This is the Briar "spare bit" bug; these three
521        // assertions are the regression guard against reintroducing it.
522        for mutant in [
523            "off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpw3fxkm",
524            "off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzqzuscy",
525            "off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqra5g99k",
526        ] {
527            assert_eq!(
528                mutant.parse::<Address>(),
529                Err(AddressError::NonCanonical),
530                "{mutant}"
531            );
532            // The canonical form of that payload parses, proving the mutant is
533            // a second spelling rather than a different address.
534            assert!(ZEROS_ADDR.parse::<Address>().is_ok());
535        }
536    }
537
538    #[test]
539    fn rejects_over_long_data_parts() {
540        // The crate's fes-to-bytes rule is `n * 5 / 8`, so a 35-character data
541        // part also yields 21 bytes: a checksum-valid second spelling that the
542        // length and version checks cannot see.
543        for mutant in [
544            "off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj7v8n5",
545            "off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp0gcjwx",
546            "off1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqlcjhrel",
547        ] {
548            assert_eq!(
549                mutant.parse::<Address>(),
550                Err(AddressError::NonCanonical),
551                "{mutant}"
552            );
553        }
554    }
555
556    #[test]
557    fn rejects_structural_garbage() {
558        for bad in [
559            "",
560            "off",
561            "off1",
562            "off1qqq",
563            "1qyqqqq",
564            ZEROS_ADDR.trim_end_matches('f'),
565        ] {
566            assert!(
567                matches!(
568                    bad.parse::<Address>(),
569                    Err(AddressError::InvalidBech32m { .. })
570                ),
571                "{bad:?}"
572            );
573        }
574    }
575
576    #[test]
577    fn from_payload_rejects_bad_input() {
578        assert_eq!(
579            Address::from_payload(&[]),
580            Err(AddressError::PayloadLength {
581                len: 0,
582                expected: Address::PAYLOAD_LEN,
583            })
584        );
585        let mut payload = [0u8; Address::PAYLOAD_LEN];
586        payload[0] = 0x02;
587        assert_eq!(
588            Address::from_payload(&payload),
589            Err(AddressError::VersionMismatch {
590                found: 0x02,
591                expected: Address::VERSION,
592            })
593        );
594    }
595}