Skip to content

Commit 95015bd

Browse files
committed
Added support for Kyber and Dilithium
1 parent d6a5d36 commit 95015bd

File tree

6 files changed

+601
-13
lines changed

6 files changed

+601
-13
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ chacha20poly1305 = "^0.10.1"
2323
secp256k1 = "^0.30.0"
2424
x25519-dalek = {version = "2.0.0-rc.2", features = ["static_secrets"]}
2525
thiserror = "^1.0.48"
26+
anyhow = "^1.0.0"
2627
hex = "^0.4.3"
2728
ed25519-dalek = {version = "2.1.1", features = ["rand_core"]}
29+
pqcrypto-kyber = "0.8.1"
30+
pqcrypto-dilithium = "0.5.0"
31+
pqcrypto-traits = "0.3.5"
2832

2933
[dev-dependencies]
3034
hex-literal = "^0.4.1"

src/dilithium.rs

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
use anyhow::{Result, anyhow};
2+
use pqcrypto_dilithium::*;
3+
use pqcrypto_traits::sign::{ SecretKey, PublicKey, DetachedSignature };
4+
5+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6+
pub enum DilithiumLevel {
7+
Dilithium2,
8+
Dilithium3,
9+
Dilithium5,
10+
}
11+
12+
impl DilithiumLevel {
13+
pub fn private_key_size(&self) -> usize {
14+
match self {
15+
DilithiumLevel::Dilithium2 => dilithium2::secret_key_bytes(),
16+
DilithiumLevel::Dilithium3 => dilithium3::secret_key_bytes(),
17+
DilithiumLevel::Dilithium5 => dilithium5::secret_key_bytes(),
18+
}
19+
}
20+
21+
pub fn public_key_size(&self) -> usize {
22+
match self {
23+
DilithiumLevel::Dilithium2 => dilithium2::public_key_bytes(),
24+
DilithiumLevel::Dilithium3 => dilithium3::public_key_bytes(),
25+
DilithiumLevel::Dilithium5 => dilithium5::public_key_bytes(),
26+
}
27+
}
28+
29+
pub fn signature_size(&self) -> usize {
30+
match self {
31+
DilithiumLevel::Dilithium2 => dilithium2::signature_bytes(),
32+
DilithiumLevel::Dilithium3 => dilithium3::signature_bytes(),
33+
DilithiumLevel::Dilithium5 => dilithium5::signature_bytes(),
34+
}
35+
}
36+
}
37+
38+
#[derive(Clone, PartialEq)]
39+
pub enum DilithiumPrivateKey {
40+
Dilithium2(Box<dilithium2::SecretKey>),
41+
Dilithium3(Box<dilithium3::SecretKey>),
42+
Dilithium5(Box<dilithium5::SecretKey>),
43+
}
44+
45+
impl DilithiumPrivateKey {
46+
pub fn level(&self) -> DilithiumLevel {
47+
match self {
48+
DilithiumPrivateKey::Dilithium2(_) => DilithiumLevel::Dilithium2,
49+
DilithiumPrivateKey::Dilithium3(_) => DilithiumLevel::Dilithium3,
50+
DilithiumPrivateKey::Dilithium5(_) => DilithiumLevel::Dilithium5,
51+
}
52+
}
53+
54+
pub fn size(&self) -> usize {
55+
self.level().private_key_size()
56+
}
57+
58+
pub fn as_bytes(&self) -> &[u8] {
59+
match self {
60+
DilithiumPrivateKey::Dilithium2(key) => key.as_bytes(),
61+
DilithiumPrivateKey::Dilithium3(key) => key.as_bytes(),
62+
DilithiumPrivateKey::Dilithium5(key) => key.as_bytes(),
63+
}
64+
}
65+
66+
pub fn from_bytes(level: DilithiumLevel, bytes: &[u8]) -> Result<Self> {
67+
match level {
68+
DilithiumLevel::Dilithium2 => Ok(DilithiumPrivateKey::Dilithium2(Box::new(dilithium2::SecretKey::from_bytes(bytes).map_err(|e| anyhow!(e))?))),
69+
DilithiumLevel::Dilithium3 => Ok(DilithiumPrivateKey::Dilithium3(Box::new(dilithium3::SecretKey::from_bytes(bytes).map_err(|e| anyhow!(e))?))),
70+
DilithiumLevel::Dilithium5 => Ok(DilithiumPrivateKey::Dilithium5(Box::new(dilithium5::SecretKey::from_bytes(bytes).map_err(|e| anyhow!(e))?))),
71+
}
72+
}
73+
}
74+
75+
impl std::fmt::Debug for DilithiumPrivateKey {
76+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77+
match self {
78+
DilithiumPrivateKey::Dilithium2(_) => f.write_str("Dilithium2PrivateKey"),
79+
DilithiumPrivateKey::Dilithium3(_) => f.write_str("Dilithium3PrivateKey"),
80+
DilithiumPrivateKey::Dilithium5(_) => f.write_str("Dilithium5PrivateKey"),
81+
}
82+
}
83+
}
84+
85+
#[derive(Clone, PartialEq)]
86+
pub enum DilithiumPublicKey {
87+
Dilithium2(Box<dilithium2::PublicKey>),
88+
Dilithium3(Box<dilithium3::PublicKey>),
89+
Dilithium5(Box<dilithium5::PublicKey>),
90+
}
91+
92+
impl DilithiumPublicKey {
93+
pub fn level(&self) -> DilithiumLevel {
94+
match self {
95+
DilithiumPublicKey::Dilithium2(_) => DilithiumLevel::Dilithium2,
96+
DilithiumPublicKey::Dilithium3(_) => DilithiumLevel::Dilithium3,
97+
DilithiumPublicKey::Dilithium5(_) => DilithiumLevel::Dilithium5,
98+
}
99+
}
100+
101+
pub fn size(&self) -> usize {
102+
self.level().public_key_size()
103+
}
104+
105+
pub fn as_bytes(&self) -> &[u8] {
106+
match self {
107+
DilithiumPublicKey::Dilithium2(key) => key.as_bytes(),
108+
DilithiumPublicKey::Dilithium3(key) => key.as_bytes(),
109+
DilithiumPublicKey::Dilithium5(key) => key.as_bytes(),
110+
}
111+
}
112+
113+
pub fn from_bytes(level: DilithiumLevel, bytes: &[u8]) -> Result<Self> {
114+
match level {
115+
DilithiumLevel::Dilithium2 => Ok(DilithiumPublicKey::Dilithium2(Box::new(dilithium2::PublicKey::from_bytes(bytes).map_err(|e| anyhow!(e))?))),
116+
DilithiumLevel::Dilithium3 => Ok(DilithiumPublicKey::Dilithium3(Box::new(dilithium3::PublicKey::from_bytes(bytes).map_err(|e| anyhow!(e))?))),
117+
DilithiumLevel::Dilithium5 => Ok(DilithiumPublicKey::Dilithium5(Box::new(dilithium5::PublicKey::from_bytes(bytes).map_err(|e| anyhow!(e))?))),
118+
}
119+
}
120+
}
121+
122+
impl std::fmt::Debug for DilithiumPublicKey {
123+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124+
match self {
125+
DilithiumPublicKey::Dilithium2(_) => f.write_str("Dilithium2PublicKey"),
126+
DilithiumPublicKey::Dilithium3(_) => f.write_str("Dilithium3PublicKey"),
127+
DilithiumPublicKey::Dilithium5(_) => f.write_str("Dilithium5PublicKey"),
128+
}
129+
}
130+
}
131+
132+
#[derive(Clone)]
133+
pub enum DilithiumSignature {
134+
Dilithium2(Box<dilithium2::DetachedSignature>),
135+
Dilithium3(Box<dilithium3::DetachedSignature>),
136+
Dilithium5(Box<dilithium5::DetachedSignature>),
137+
}
138+
139+
impl DilithiumSignature {
140+
pub fn level(&self) -> DilithiumLevel {
141+
match self {
142+
DilithiumSignature::Dilithium2(_) => DilithiumLevel::Dilithium2,
143+
DilithiumSignature::Dilithium3(_) => DilithiumLevel::Dilithium3,
144+
DilithiumSignature::Dilithium5(_) => DilithiumLevel::Dilithium5,
145+
}
146+
}
147+
148+
pub fn size(&self) -> usize {
149+
self.level().signature_size()
150+
}
151+
152+
pub fn as_bytes(&self) -> &[u8] {
153+
match self {
154+
DilithiumSignature::Dilithium2(sig) => sig.as_bytes(),
155+
DilithiumSignature::Dilithium3(sig) => sig.as_bytes(),
156+
DilithiumSignature::Dilithium5(sig) => sig.as_bytes(),
157+
}
158+
}
159+
160+
pub fn from_bytes(level: DilithiumLevel, bytes: &[u8]) -> Result<Self> {
161+
match level {
162+
DilithiumLevel::Dilithium2 => Ok(DilithiumSignature::Dilithium2(Box::new(dilithium2::DetachedSignature::from_bytes(bytes).map_err(|e| anyhow!(e))?))),
163+
DilithiumLevel::Dilithium3 => Ok(DilithiumSignature::Dilithium3(Box::new(dilithium3::DetachedSignature::from_bytes(bytes).map_err(|e| anyhow!(e))?))),
164+
DilithiumLevel::Dilithium5 => Ok(DilithiumSignature::Dilithium5(Box::new(dilithium5::DetachedSignature::from_bytes(bytes).map_err(|e| anyhow!(e))?))),
165+
}
166+
}
167+
}
168+
169+
impl std::fmt::Debug for DilithiumSignature {
170+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171+
match self {
172+
DilithiumSignature::Dilithium2(_) => f.write_str("Dilithium2Signature"),
173+
DilithiumSignature::Dilithium3(_) => f.write_str("Dilithium3Signature"),
174+
DilithiumSignature::Dilithium5(_) => f.write_str("Dilithium5Signature"),
175+
}
176+
}
177+
}
178+
179+
pub fn dilithium_new_keypair(level: DilithiumLevel) -> (DilithiumPublicKey, DilithiumPrivateKey) {
180+
match level {
181+
DilithiumLevel::Dilithium2 => {
182+
let (pk, sk) = dilithium2::keypair();
183+
(DilithiumPublicKey::Dilithium2(Box::new(pk)), DilithiumPrivateKey::Dilithium2(Box::new(sk)))
184+
},
185+
DilithiumLevel::Dilithium3 => {
186+
let (pk, sk) = dilithium3::keypair();
187+
(DilithiumPublicKey::Dilithium3(Box::new(pk)), DilithiumPrivateKey::Dilithium3(Box::new(sk)))
188+
},
189+
DilithiumLevel::Dilithium5 => {
190+
let (pk, sk) = dilithium5::keypair();
191+
(DilithiumPublicKey::Dilithium5(Box::new(pk)), DilithiumPrivateKey::Dilithium5(Box::new(sk)))
192+
},
193+
}
194+
}
195+
196+
pub fn dilithium_sign(private_key: &DilithiumPrivateKey, message: impl AsRef<[u8]>) -> DilithiumSignature {
197+
match private_key {
198+
DilithiumPrivateKey::Dilithium2(sk) => DilithiumSignature::Dilithium2(Box::new(dilithium2::detached_sign(message.as_ref(), sk))),
199+
DilithiumPrivateKey::Dilithium3(sk) => DilithiumSignature::Dilithium3(Box::new(dilithium3::detached_sign(message.as_ref(), sk))),
200+
DilithiumPrivateKey::Dilithium5(sk) => DilithiumSignature::Dilithium5(Box::new(dilithium5::detached_sign(message.as_ref(), sk))),
201+
}
202+
}
203+
204+
pub fn dilithium_verify(public_key: &DilithiumPublicKey, signature: &DilithiumSignature, message: impl AsRef<[u8]>) -> bool {
205+
match (public_key, signature) {
206+
(DilithiumPublicKey::Dilithium2(pk), DilithiumSignature::Dilithium2(sig)) => dilithium2::verify_detached_signature(sig, message.as_ref(), pk).is_ok(),
207+
(DilithiumPublicKey::Dilithium3(pk), DilithiumSignature::Dilithium3(sig)) => dilithium3::verify_detached_signature(sig, message.as_ref(), pk).is_ok(),
208+
(DilithiumPublicKey::Dilithium5(pk), DilithiumSignature::Dilithium5(sig)) => dilithium5::verify_detached_signature(sig, message.as_ref(), pk).is_ok(),
209+
_ => false,
210+
}
211+
}
212+
213+
#[cfg(test)]
214+
mod tests {
215+
use crate::*;
216+
217+
const MESSAGE: &[u8] = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
218+
219+
#[test]
220+
fn test_dilithium2_signing() {
221+
let (public_key, private_key) = dilithium_new_keypair(DilithiumLevel::Dilithium2);
222+
let signature = dilithium_sign(&private_key, MESSAGE);
223+
assert!(dilithium_verify(&public_key, &signature, MESSAGE));
224+
assert!(!dilithium_verify(&public_key, &signature, &MESSAGE[..MESSAGE.len() - 1]));
225+
}
226+
227+
#[test]
228+
fn test_dilithium3_signing() {
229+
let (public_key, private_key) = dilithium_new_keypair(DilithiumLevel::Dilithium3);
230+
let signature = dilithium_sign(&private_key, MESSAGE);
231+
assert!(dilithium_verify(&public_key, &signature, MESSAGE));
232+
assert!(!dilithium_verify(&public_key, &signature, &MESSAGE[..MESSAGE.len() - 1]));
233+
}
234+
235+
#[test]
236+
fn test_dilithium5_signing() {
237+
let (public_key, private_key) = dilithium_new_keypair(DilithiumLevel::Dilithium5);
238+
let signature = dilithium_sign(&private_key, MESSAGE);
239+
assert!(dilithium_verify(&public_key, &signature, MESSAGE));
240+
assert!(!dilithium_verify(&public_key, &signature, &MESSAGE[..MESSAGE.len() - 1]));
241+
}
242+
}

src/error.rs

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)