Skip to main content

rustolio_utils/crypto/
signature.rs

1//
2// SPDX-License-Identifier: MPL-2.0
3//
4// Copyright (c) 2026 Tobias Binnewies. All rights reserved.
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at http://mozilla.org/MPL/2.0/.
9//
10
11
12use p256::ecdsa::{
13    self,
14    signature::{Signer, Verifier},
15    SigningKey, VerifyingKey,
16};
17
18use crate::bytes::Bytes;
19use crate::prelude::*;
20
21use super::{hash, rand};
22
23pub type Result<T> = std::result::Result<T, Error>;
24
25#[derive(Debug, Clone, Copy, PartialEq)]
26pub enum Error {
27    Parse,
28    InvalidPublicKey,
29    InvalidPrivateKey,
30    InvalidSignature,
31}
32
33impl std::fmt::Display for Error {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        write!(f, "{self:?}")
36    }
37}
38
39impl std::error::Error for Error {}
40
41#[derive(Debug, Clone)]
42pub struct PrivateKey(SigningKey);
43
44impl PrivateKey {
45    pub fn generate() -> rand::Result<Self> {
46        let key = loop {
47            let key = rand::array()?;
48            // Key cannot have only 0 or 0xFF values
49            if key != [0; 32] && key != [0xFF; 32] {
50                break key;
51            }
52        };
53        let signing_key = SigningKey::from_bytes(&key.into()).unwrap();
54        Ok(Self(signing_key))
55    }
56
57    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self> {
58        let Ok(k) = SigningKey::from_bytes(bytes.as_ref().into()) else {
59            return Err(Error::InvalidPrivateKey);
60        };
61        Ok(Self(k))
62    }
63
64    pub fn to_bytes(&self) -> [u8; 32] {
65        self.0.to_bytes().into()
66    }
67
68    pub fn sign_hash(&self, hash: &hash::Digest) -> Signature {
69        Signature(self.0.sign(hash.as_ref()))
70    }
71
72    pub fn sign<T: std::hash::Hash>(&self, value: T) -> SignedValue<T> {
73        let hash = hash::Hasher::once(&value);
74        let sig = self.sign_hash(&hash);
75        SignedValue {
76            value,
77            sig,
78            signer: self.public_key(),
79        }
80    }
81
82    pub fn public_key(&self) -> PublicKey {
83        PublicKey(VerifyingKey::from(&self.0))
84    }
85}
86
87impl std::ops::Deref for PrivateKey {
88    type Target = SigningKey;
89    fn deref(&self) -> &Self::Target {
90        &self.0
91    }
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub struct PublicKey(VerifyingKey);
96
97impl std::hash::Hash for PublicKey {
98    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
99        self.to_sec1_bytes().hash(state);
100    }
101}
102
103impl Encode for PublicKey {
104    #[async_impl]
105    async fn encode_async(
106        &self,
107        writer: &mut impl __utils_macros::AsyncEncoder,
108    ) -> crate::Result<()> {
109        self.to_bytes().encode_async(writer).await
110    }
111    fn encode_size(&self) -> usize {
112        65
113    }
114}
115
116impl Decode for PublicKey {
117    #[async_impl]
118    async fn decode_async(reader: &mut impl __utils_macros::AsyncDecoder) -> crate::Result<Self> {
119        let bytes = Bytes::decode_async(reader).await?;
120        Self::from_bytes(bytes).context("Invalid data")
121    }
122}
123
124impl PublicKey {
125    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self> {
126        let Ok(k) = VerifyingKey::from_sec1_bytes(bytes.as_ref()) else {
127            return Err(Error::InvalidPublicKey);
128        };
129        Ok(Self(k))
130    }
131
132    pub fn to_bytes(&self) -> Bytes {
133        Bytes::from(self.to_sec1_bytes())
134    }
135
136    pub fn verify_hash(&self, hash: &hash::Digest, sig: &Signature) -> Result<()> {
137        if self.0.verify(hash.as_ref(), &sig.0).is_err() {
138            return Err(Error::InvalidSignature);
139        }
140        Ok(())
141    }
142}
143
144impl std::ops::Deref for PublicKey {
145    type Target = VerifyingKey;
146    fn deref(&self) -> &Self::Target {
147        &self.0
148    }
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152pub struct Signature(ecdsa::Signature);
153
154impl Encode for Signature {
155    #[async_impl]
156    async fn encode_async(
157        &self,
158        writer: &mut impl __utils_macros::AsyncEncoder,
159    ) -> crate::Result<()> {
160        self.to_bytes().encode_async(writer).await
161    }
162    fn encode_size(&self) -> usize {
163        64
164    }
165}
166
167impl Decode for Signature {
168    #[async_impl]
169    async fn decode_async(reader: &mut impl __utils_macros::AsyncDecoder) -> crate::Result<Self> {
170        let bytes = <[u8; 64]>::decode_async(reader).await?;
171        Self::from_bytes(bytes).context("Invalid data")
172    }
173}
174
175impl Signature {
176    pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Signature> {
177        let Ok(sig) = ecdsa::Signature::from_bytes(bytes.as_ref().into()) else {
178            return Err(Error::InvalidSignature);
179        };
180        Ok(Self(sig))
181    }
182
183    pub fn to_bytes(&self) -> [u8; 64] {
184        self.0.to_bytes().into()
185    }
186}
187
188impl std::ops::Deref for Signature {
189    type Target = ecdsa::Signature;
190    fn deref(&self) -> &Self::Target {
191        &self.0
192    }
193}
194
195#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)]
196pub struct SignedValue<T> {
197    value: T,
198    sig: Signature,
199    signer: PublicKey,
200}
201
202impl<T: std::hash::Hash> SignedValue<T> {
203    pub fn verify(&self) -> Result<()> {
204        let hash = hash::Hasher::once(&self.value);
205        self.signer.verify_hash(&hash, &self.sig)
206    }
207
208    pub fn into_value(self) -> T {
209        self.value
210    }
211
212    pub fn signer(&self) -> PublicKey {
213        self.signer
214    }
215}
216
217#[cfg(test)]
218mod tests {
219    use super::*;
220
221    #[test]
222    fn test_signing() {
223        let private = PrivateKey::generate().unwrap();
224        let public = private.public_key();
225
226        let message =
227            b"ECDSA proves knowledge of a secret number in the context of a single message";
228        let hash = hash::Hasher::once(message);
229        let sig = private.sign_hash(&hash);
230
231        assert!(public.verify_hash(&hash, &sig).is_ok());
232    }
233
234    #[test]
235    fn test_signing_encoding_decoding() {
236        let private = PrivateKey::generate().unwrap();
237        let public = private.public_key();
238
239        let encoded_private = private.to_bytes();
240        let encoded_public = public.to_bytes();
241
242        let private = PrivateKey::from_bytes(&encoded_private).unwrap();
243        let public = PublicKey::from_bytes(&encoded_public).unwrap();
244
245        let message =
246            b"ECDSA proves knowledge of a secret number in the context of a single message";
247        let hash = hash::Hasher::once(message);
248        let sig = private.sign_hash(&hash);
249
250        assert!(public.verify_hash(&hash, &sig).is_ok());
251    }
252}