Skip to main content

h33_substrate_verifier/
substrate_layout.rs

1//! The 58-byte H33 signing substrate layout.
2//!
3//! This module is a pure, dependency-free reimplementation of the
4//! substrate wire format from the public specification (see
5//! `gitlab.com/drata5764111/h33/h33-substrate/SPEC.md`). It is NOT a
6//! reference to any internal H33 crate — a verifier that depended on
7//! the signer's private code would defeat the purpose of an open
8//! reference implementation.
9//!
10//! ## Byte layout (v1)
11//!
12//! ```text
13//! Offset  Size  Field              Description
14//! ──────  ────  ─────              ───────────
15//! 0       1     version            Schema version. Always 0x01 for v1.
16//! 1       1     computation_type   Domain separator (see ComputationType).
17//! 2       32    fhe_commitment     SHA3-256(canonical source bytes).
18//! 34      8     timestamp_ms       Millisecond Unix timestamp, big-endian.
19//! 42      16    nonce              16 random bytes, unique per signing event.
20//! ──────  ────
21//! Total:  58 bytes
22//! ```
23//!
24//! The signing message passed to the post-quantum signature algorithms
25//! is always `SHA3-256(substrate_bytes)` — exactly 32 bytes regardless
26//! of what the substrate committed to.
27
28/// Total size of a v1 substrate in bytes.
29pub const SUBSTRATE_SIZE: usize = 58;
30
31/// Schema version byte for v1 substrates.
32pub const SUBSTRATE_VERSION: u8 = 0x01;
33
34/// Size of the `fhe_commitment` field in bytes (SHA3-256 digest).
35pub const COMMITMENT_SIZE: usize = 32;
36
37/// Size of the `timestamp_ms` field in bytes (`u64` big-endian).
38pub const TIMESTAMP_SIZE: usize = 8;
39
40/// Size of the `nonce` field in bytes.
41pub const NONCE_SIZE: usize = 16;
42
43/// Offset at which the `fhe_commitment` starts.
44pub const COMMITMENT_OFFSET: usize = 2;
45
46/// Offset at which the `timestamp_ms` starts.
47pub const TIMESTAMP_OFFSET: usize = COMMITMENT_OFFSET + COMMITMENT_SIZE;
48
49/// Offset at which the `nonce` starts.
50pub const NONCE_OFFSET: usize = TIMESTAMP_OFFSET + TIMESTAMP_SIZE;
51
52/// Domain separator values defined by the substrate specification.
53///
54/// A substrate minted for one computation type can NEVER be confused
55/// with a substrate minted for another, because the type byte is
56/// covered by the SHA3-256 signing message.
57///
58/// Values are an append-only enum — once assigned, a value cannot be
59/// reused or removed without breaking every historical signature that
60/// used the old meaning.
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
62#[non_exhaustive]
63#[repr(u8)]
64pub enum ComputationType {
65    /// FHE biometric authentication match.
66    BiometricAuth = 0x01,
67    /// FHE fraud scoring result.
68    FraudScore = 0x02,
69    /// `FedNow` payment attestation.
70    FedNowPayment = 0x03,
71    /// Solana transaction attestation.
72    SolanaAttestation = 0x04,
73    /// HATS governance proof.
74    HatsGovernance = 0x05,
75    /// Bitcoin UTXO quantum-insurance attestation.
76    BitcoinUtxo = 0x06,
77    /// ZK-KYC identity verification.
78    KycVerification = 0x07,
79    /// H33-Share cross-institution computation.
80    ShareComputation = 0x08,
81    /// `ArchiveSign` document attestation.
82    ArchiveSign = 0x09,
83    /// `MedVault` PHI operation.
84    MedVaultPhi = 0x0A,
85    /// `VaultKey` secret operation.
86    VaultKeyOp = 0x0B,
87    /// HTTP API response attestation (Tier 1 substrate response middleware).
88    ApiResponse = 0x0C,
89    /// Generic FHE computation — catch-all for unrelated uses.
90    GenericFhe = 0xFF,
91}
92
93impl ComputationType {
94    /// Convert from a raw byte. Returns `None` for values the verifier
95    /// does not recognize.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// use h33_substrate_verifier::ComputationType;
101    ///
102    /// assert_eq!(ComputationType::from_byte(0x01), Some(ComputationType::BiometricAuth));
103    /// assert_eq!(ComputationType::from_byte(0x0C), Some(ComputationType::ApiResponse));
104    /// assert_eq!(ComputationType::from_byte(0x42), None);
105    /// ```
106    #[must_use]
107    pub const fn from_byte(byte: u8) -> Option<Self> {
108        match byte {
109            0x01 => Some(Self::BiometricAuth),
110            0x02 => Some(Self::FraudScore),
111            0x03 => Some(Self::FedNowPayment),
112            0x04 => Some(Self::SolanaAttestation),
113            0x05 => Some(Self::HatsGovernance),
114            0x06 => Some(Self::BitcoinUtxo),
115            0x07 => Some(Self::KycVerification),
116            0x08 => Some(Self::ShareComputation),
117            0x09 => Some(Self::ArchiveSign),
118            0x0A => Some(Self::MedVaultPhi),
119            0x0B => Some(Self::VaultKeyOp),
120            0x0C => Some(Self::ApiResponse),
121            0xFF => Some(Self::GenericFhe),
122            _ => None,
123        }
124    }
125
126    /// Convert to the raw byte value.
127    #[must_use]
128    pub const fn to_byte(self) -> u8 {
129        self as u8
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136
137    #[test]
138    fn layout_constants_add_up() {
139        // Every offset + size combination must cleanly tile the 58-byte
140        // substrate with zero overlap and zero gaps.
141        assert_eq!(SUBSTRATE_SIZE, 58);
142        assert_eq!(COMMITMENT_OFFSET, 2);
143        assert_eq!(TIMESTAMP_OFFSET, 34);
144        assert_eq!(NONCE_OFFSET, 42);
145        assert_eq!(NONCE_OFFSET + NONCE_SIZE, SUBSTRATE_SIZE);
146    }
147
148    #[test]
149    fn computation_type_round_trip() {
150        let all = [
151            ComputationType::BiometricAuth,
152            ComputationType::FraudScore,
153            ComputationType::FedNowPayment,
154            ComputationType::SolanaAttestation,
155            ComputationType::HatsGovernance,
156            ComputationType::BitcoinUtxo,
157            ComputationType::KycVerification,
158            ComputationType::ShareComputation,
159            ComputationType::ArchiveSign,
160            ComputationType::MedVaultPhi,
161            ComputationType::VaultKeyOp,
162            ComputationType::ApiResponse,
163            ComputationType::GenericFhe,
164        ];
165        for ct in all {
166            assert_eq!(ComputationType::from_byte(ct.to_byte()), Some(ct));
167        }
168    }
169
170    #[test]
171    fn unrecognized_computation_type_bytes_are_none() {
172        assert_eq!(ComputationType::from_byte(0x00), None);
173        assert_eq!(ComputationType::from_byte(0x0D), None);
174        assert_eq!(ComputationType::from_byte(0x42), None);
175        assert_eq!(ComputationType::from_byte(0xFE), None);
176    }
177}