kyberlib/
wasm.rs

1// Copyright © 2024 kyberlib. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4#![allow(non_snake_case)]
5extern crate alloc;
6
7use super::*;
8use crate::params::*;
9use alloc::boxed::Box;
10use rand::rngs::OsRng;
11use wasm_bindgen::prelude::*;
12
13/// Generate a key pair for Kyber encryption.
14///
15/// # Errors
16///
17/// Returns a `JsError` if an error occurs during key pair generation.
18#[wasm_bindgen]
19pub fn keypair() -> Result<Keys, JsError> {
20    let mut rng = OsRng {};
21    match api::keypair(&mut rng) {
22        Ok(keys) => Ok(Keys {
23            pubkey: Box::new(keys.public),
24            secret: Box::new(keys.secret),
25        }),
26        Err(KyberLibError::RandomBytesGeneration) => {
27            Err(JsError::new("Error trying to fill random bytes"))
28        }
29        _ => Err(JsError::new("The keypair could not be generated")),
30    }
31}
32
33/// Encapsulate a shared secret using the provided public key.
34///
35/// # Arguments
36///
37/// * `pk` - The public key as a boxed slice of bytes.
38///
39/// # Errors
40///
41/// Returns a `JsValue` that is `null()` if the public key size is incorrect or if an error occurs during encapsulation.
42#[wasm_bindgen]
43pub fn encapsulate(pk: Box<[u8]>) -> Result<Kex, JsValue> {
44    if pk.len() != KYBER_PUBLIC_KEY_BYTES {
45        return Err(JsValue::null());
46    }
47
48    let mut rng = OsRng {};
49    match api::encapsulate(&pk, &mut rng) {
50        Ok(kex) => Ok(Kex {
51            ciphertext: Box::new(kex.0),
52            sharedSecret: Box::new(kex.1),
53        }),
54        Err(_) => Err(JsValue::null()),
55    }
56}
57
58/// Decapsulate a ciphertext using the provided secret key.
59///
60/// # Arguments
61///
62/// * `ct` - The ciphertext as a boxed slice of bytes.
63/// * `sk` - The secret key as a boxed slice of bytes.
64///
65/// # Errors
66///
67/// Returns a `JsValue` that is `null()` if the input sizes are incorrect or if an error occurs during decapsulation.
68#[wasm_bindgen]
69pub fn decapsulate(
70    ct: Box<[u8]>,
71    sk: Box<[u8]>,
72) -> Result<Box<[u8]>, JsValue> {
73    if ct.len() != KYBER_CIPHERTEXT_BYTES
74        || sk.len() != KYBER_SECRET_KEY_BYTES
75    {
76        return Err(JsValue::null());
77    }
78
79    match api::decapsulate(&ct, &sk) {
80        Ok(ss) => Ok(Box::new(ss)),
81        Err(_) => Err(JsValue::null()),
82    }
83}
84
85/// Represents Kyber key pair.
86#[wasm_bindgen]
87#[derive(Debug)]
88pub struct Keys {
89    pubkey: Box<[u8]>,
90    secret: Box<[u8]>,
91}
92
93/// Represents Kyber encapsulated shared secret.
94#[wasm_bindgen]
95#[derive(Debug)]
96pub struct Kex {
97    ciphertext: Box<[u8]>,
98    sharedSecret: Box<[u8]>,
99}
100
101#[wasm_bindgen]
102impl Keys {
103    /// Create a new key pair.
104    ///
105    /// This function generates a new Kyber key pair and returns it as a `Keys` struct.
106    ///
107    /// # Errors
108    ///
109    /// Returns a `JsError` if an error occurs during key pair generation.
110    #[wasm_bindgen(constructor)]
111    pub fn new() -> Result<Keys, JsError> {
112        keypair()
113    }
114
115    /// Get the public key.
116    ///
117    /// Returns the public key as a boxed slice of bytes.
118    #[wasm_bindgen(getter)]
119    pub fn pubkey(&self) -> Box<[u8]> {
120        self.pubkey.clone()
121    }
122
123    /// Get the secret key.
124    ///
125    /// Returns the secret key as a boxed slice of bytes.
126    #[wasm_bindgen(getter)]
127    pub fn secret(&self) -> Box<[u8]> {
128        self.secret.clone()
129    }
130}
131
132#[wasm_bindgen]
133impl Kex {
134    /// Create a new Kex instance by encapsulating with a given public key.
135    ///
136    /// # Arguments
137    ///
138    /// * `public_key` - The public key as a boxed slice of bytes.
139    ///
140    /// # Panics
141    ///
142    /// Panics if the public key size is incorrect.
143    #[wasm_bindgen(constructor)]
144    pub fn new(public_key: Box<[u8]>) -> Self {
145        encapsulate(public_key).expect("Invalid Public Key Size")
146    }
147
148    /// Get the ciphertext.
149    ///
150    /// Returns the ciphertext as a boxed slice of bytes.
151    #[wasm_bindgen(getter)]
152    pub fn ciphertext(&self) -> Box<[u8]> {
153        self.ciphertext.clone()
154    }
155
156    /// Get the shared secret.
157    ///
158    /// Returns the shared secret as a boxed slice of bytes.
159    #[wasm_bindgen(getter)]
160    pub fn sharedSecret(&self) -> Box<[u8]> {
161        self.sharedSecret.clone()
162    }
163
164    /// Set the ciphertext.
165    ///
166    /// # Arguments
167    ///
168    /// * `ciphertext` - The ciphertext as a boxed slice of bytes.
169    #[wasm_bindgen(setter)]
170    pub fn set_ciphertext(&mut self, ciphertext: Box<[u8]>) {
171        self.ciphertext = ciphertext;
172    }
173
174    /// Set the shared secret.
175    ///
176    /// # Arguments
177    ///
178    /// * `sharedSecret` - The shared secret as a boxed slice of bytes.
179    #[wasm_bindgen(setter)]
180    pub fn set_sharedSecret(&mut self, sharedSecret: Box<[u8]>) {
181        self.sharedSecret = sharedSecret;
182    }
183}
184
185/// Represents Kyber parameters.
186#[wasm_bindgen]
187#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
188pub struct Params {
189    /// The size of public key bytes.
190    #[wasm_bindgen(readonly)]
191    pub publicKeyBytes: usize,
192    /// The size of secret key bytes.
193    #[wasm_bindgen(readonly)]
194    pub secretKeyBytes: usize,
195    /// The size of ciphertext bytes.
196    #[wasm_bindgen(readonly)]
197    pub ciphertextBytes: usize,
198    /// The size of shared secret bytes.
199    #[wasm_bindgen(readonly)]
200    pub sharedSecretBytes: usize,
201}
202
203#[wasm_bindgen]
204impl Params {
205    /// Get the size of public key bytes.
206    #[wasm_bindgen(getter)]
207    pub fn publicKeyBytes() -> usize {
208        KYBER_PUBLIC_KEY_BYTES
209    }
210
211    /// Get the size of secret key bytes.
212    #[wasm_bindgen(getter)]
213    pub fn secretKeyBytes() -> usize {
214        KYBER_SECRET_KEY_BYTES
215    }
216
217    /// Get the size of ciphertext bytes.
218    #[wasm_bindgen(getter)]
219    pub fn ciphertextBytes() -> usize {
220        KYBER_CIPHERTEXT_BYTES
221    }
222
223    /// Get the size of shared secret bytes.
224    #[wasm_bindgen(getter)]
225    pub fn sharedSecretBytes() -> usize {
226        KYBER_SHARED_SECRET_BYTES
227    }
228}