opentitanlib/crypto/
spx.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use std::io::{Read, Write};
6use std::str::FromStr;
7
8use anyhow::{Context, Result, anyhow, ensure};
9use serde::Deserialize;
10use serde_annotate::Annotate;
11use sphincsplus::{DecodeKey, SpxPublicKey};
12
13use super::Error;
14
15#[derive(Debug, Deserialize, Annotate)]
16pub struct SpxRawPublicKey {
17    #[serde(with = "serde_bytes")]
18    #[annotate(format = hexstr)]
19    pub key: Vec<u8>,
20}
21
22impl Default for SpxRawPublicKey {
23    fn default() -> Self {
24        Self { key: vec![0; 32] }
25    }
26}
27
28impl TryFrom<&sphincsplus::SpxPublicKey> for SpxRawPublicKey {
29    type Error = Error;
30    fn try_from(v: &SpxPublicKey) -> Result<Self, Self::Error> {
31        Ok(Self {
32            key: v.as_bytes().to_vec(),
33        })
34    }
35}
36
37impl FromStr for SpxRawPublicKey {
38    type Err = Error;
39    fn from_str(s: &str) -> Result<Self, Self::Err> {
40        let key = SpxPublicKey::read_pem_file(s)
41            .with_context(|| format!("Failed to load {s}"))
42            .map_err(Error::Other)?;
43        SpxRawPublicKey::try_from(&key)
44    }
45}
46
47impl SpxRawPublicKey {
48    pub const SIZE: usize = 32;
49    pub fn read(src: &mut impl Read) -> Result<Self> {
50        let mut key = Self::default();
51        key.key.resize(32, 0);
52        src.read_exact(&mut key.key)?;
53        Ok(key)
54    }
55    pub fn write(&self, dest: &mut impl Write) -> Result<()> {
56        ensure!(
57            self.key.len() == Self::SIZE,
58            Error::InvalidPublicKey(anyhow!("bad key length: {}", self.key.len()))
59        );
60        dest.write_all(&self.key)?;
61        Ok(())
62    }
63}