Skip to main content

hekate_core/
errors.rs

1// SPDX-FileCopyrightText: 2026 Andrei Kochergin <andrei@oumuamua.dev>
2// SPDX-FileCopyrightText: 2026 Oumuamua Labs <info@oumuamua.dev>
3// SPDX-License-Identifier: AGPL-3.0-only
4
5use crate::poly::variant;
6use crate::{config, trace};
7use core::fmt;
8use hekate_crypto::{merkle, transcript};
9
10pub type Result<T> = core::result::Result<T, Error>;
11
12#[derive(Clone, Copy, Eq, PartialEq)]
13pub enum Error {
14    Config(config::Error),
15    Trace(trace::Error),
16    Merkle(merkle::Error),
17    Transcript(transcript::Error),
18    VirtualPoly(variant::Error),
19
20    /// Cross-crate protocol failures that
21    /// do not belong to a specific sub-error enum.
22    Protocol {
23        protocol: &'static str,
24        message: &'static str,
25    },
26
27    /// The program the verifier holds is not
28    /// the audited artifact the caller pinned.
29    ProgramIdMismatch {
30        actual: [u8; 32],
31    },
32
33    /// Internal invariant breach; a bug,
34    /// not a verifier-observable soundness failure.
35    InvariantViolation {
36        message: &'static str,
37    },
38}
39
40/// Not `#[derive(Debug)]`: `unwrap` and `{:?}` render a
41/// `[u8; 32]` id as decimal integers nobody can paste back.
42impl fmt::Debug for Error {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        fmt::Display::fmt(self, f)
45    }
46}
47
48impl fmt::Display for Error {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        match self {
51            Self::Config(e) => e.fmt(f),
52            Self::Trace(e) => e.fmt(f),
53            Self::Merkle(e) => e.fmt(f),
54            Self::Transcript(e) => e.fmt(f),
55            Self::VirtualPoly(e) => e.fmt(f),
56            Self::Protocol { protocol, message } => {
57                write!(f, "Protocol error ({protocol}): {message}")
58            }
59            Self::ProgramIdMismatch { actual } => {
60                write!(f, "program_id mismatch: this build computes ")?;
61                write_hex(f, actual)
62            }
63            Self::InvariantViolation { message } => {
64                write!(f, "Invariant violation: {message}")
65            }
66        }
67    }
68}
69
70impl core::error::Error for Error {}
71
72impl From<config::Error> for Error {
73    fn from(value: config::Error) -> Self {
74        Self::Config(value)
75    }
76}
77
78impl From<trace::Error> for Error {
79    fn from(value: trace::Error) -> Self {
80        Self::Trace(value)
81    }
82}
83
84impl From<merkle::Error> for Error {
85    fn from(value: merkle::Error) -> Self {
86        Self::Merkle(value)
87    }
88}
89
90impl From<transcript::Error> for Error {
91    fn from(value: transcript::Error) -> Self {
92        Self::Transcript(value)
93    }
94}
95
96impl From<variant::Error> for Error {
97    fn from(value: variant::Error) -> Self {
98        Self::VirtualPoly(value)
99    }
100}
101
102fn write_hex(f: &mut fmt::Formatter<'_>, bytes: &[u8; 32]) -> fmt::Result {
103    for byte in bytes {
104        write!(f, "{byte:02x}")?;
105    }
106
107    Ok(())
108}