arnaucube
arnaucube/miden-cryptoPublic Self-hosted repository
miden-crypto/src/dsa/rpo_falcon512/keys/public_key.rs
src/dsa/rpo_falcon512/keys/public_key.rsRaw
  1use crate::dsa::rpo_falcon512::FALCON_ENCODING_BITS;
  2
  3use super::{
  4    super::{Rpo256, LOG_N, N, PK_LEN},
  5    ByteReader, ByteWriter, Deserializable, DeserializationError, FalconFelt, Felt, Polynomial,
  6    Serializable, Signature, Word,
  7};
  8use alloc::string::ToString;
  9use core::ops::Deref;
 10use num::Zero;
 11
 12// PUBLIC KEY
 13// ================================================================================================
 14
 15/// A public key for verifying signatures.
 16///
 17/// The public key is a [Word] (i.e., 4 field elements) that is the hash of the coefficients of
 18/// the polynomial representing the raw bytes of the expanded public key. The hash is computed
 19/// using Rpo256.
 20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 21pub struct PublicKey(Word);
 22
 23impl PublicKey {
 24    /// Returns a new [PublicKey] which is a commitment to the provided expanded public key.
 25    pub fn new(pub_key: Word) -> Self {
 26        Self(pub_key)
 27    }
 28
 29    /// Verifies the provided signature against provided message and this public key.
 30    pub fn verify(&self, message: Word, signature: &Signature) -> bool {
 31        signature.verify(message, self.0)
 32    }
 33}
 34
 35impl From<PubKeyPoly> for PublicKey {
 36    fn from(pk_poly: PubKeyPoly) -> Self {
 37        let pk_felts: Polynomial<Felt> = pk_poly.0.into();
 38        let pk_digest = Rpo256::hash_elements(&pk_felts.coefficients).into();
 39        Self(pk_digest)
 40    }
 41}
 42
 43impl From<PublicKey> for Word {
 44    fn from(key: PublicKey) -> Self {
 45        key.0
 46    }
 47}
 48
 49// PUBLIC KEY POLYNOMIAL
 50// ================================================================================================
 51
 52#[derive(Debug, Clone, PartialEq, Eq)]
 53pub struct PubKeyPoly(pub Polynomial<FalconFelt>);
 54
 55impl Deref for PubKeyPoly {
 56    type Target = Polynomial<FalconFelt>;
 57
 58    fn deref(&self) -> &Self::Target {
 59        &self.0
 60    }
 61}
 62
 63impl From<Polynomial<FalconFelt>> for PubKeyPoly {
 64    fn from(pk_poly: Polynomial<FalconFelt>) -> Self {
 65        Self(pk_poly)
 66    }
 67}
 68
 69impl Serializable for &PubKeyPoly {
 70    fn write_into<W: ByteWriter>(&self, target: &mut W) {
 71        let mut buf = [0_u8; PK_LEN];
 72        buf[0] = LOG_N;
 73
 74        let mut acc = 0_u32;
 75        let mut acc_len: u32 = 0;
 76
 77        let mut input_pos = 1;
 78        for c in self.0.coefficients.iter() {
 79            let c = c.value();
 80            acc = (acc << FALCON_ENCODING_BITS) | c as u32;
 81            acc_len += FALCON_ENCODING_BITS;
 82            while acc_len >= 8 {
 83                acc_len -= 8;
 84                buf[input_pos] = (acc >> acc_len) as u8;
 85                input_pos += 1;
 86            }
 87        }
 88        if acc_len > 0 {
 89            buf[input_pos] = (acc >> (8 - acc_len)) as u8;
 90        }
 91
 92        target.write(buf);
 93    }
 94}
 95
 96impl Deserializable for PubKeyPoly {
 97    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
 98        let buf = source.read_array::<PK_LEN>()?;
 99
100        if buf[0] != LOG_N {
101            return Err(DeserializationError::InvalidValue(format!(
102                "Failed to decode public key: expected the first byte to be {LOG_N} but was {}",
103                buf[0]
104            )));
105        }
106
107        let mut acc = 0_u32;
108        let mut acc_len = 0;
109
110        let mut output = [FalconFelt::zero(); N];
111        let mut output_idx = 0;
112
113        for &byte in buf.iter().skip(1) {
114            acc = (acc << 8) | (byte as u32);
115            acc_len += 8;
116
117            if acc_len >= FALCON_ENCODING_BITS {
118                acc_len -= FALCON_ENCODING_BITS;
119                let w = (acc >> acc_len) & 0x3FFF;
120                let element = w.try_into().map_err(|err| {
121                    DeserializationError::InvalidValue(format!(
122                        "Failed to decode public key: {err}"
123                    ))
124                })?;
125                output[output_idx] = element;
126                output_idx += 1;
127            }
128        }
129
130        if (acc & ((1u32 << acc_len) - 1)) == 0 {
131            Ok(Polynomial::new(output.to_vec()).into())
132        } else {
133            Err(DeserializationError::InvalidValue(
134                "Failed to decode public key: input not fully consumed".to_string(),
135            ))
136        }
137    }
138}