Last active
October 23, 2023 02:54
-
-
Save eaon/fff807d92afad3baf119742a189eab2d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Cargo.toml b/Cargo.toml | |
index 382e8bc..3522e69 100644 | |
--- a/Cargo.toml | |
+++ b/Cargo.toml | |
@@ -18,11 +18,15 @@ wasm-bindgen = { version = "0.2.87", optional = true } | |
[dependencies.rand] | |
version = "0.8.5" | |
+default-features = false | |
features = ["getrandom"] | |
+optional = true | |
[dev-dependencies] | |
+rand = "0.8.5" | |
pqc_core = {version = "0.3.0", features = ["load"]} | |
+ | |
[target.'cfg(bench)'.dev-dependencies.criterion] | |
criterion = "0.4.0" | |
@@ -46,8 +50,10 @@ aes = [] | |
# message that is being signed. | |
random_signing = [] | |
-# For compiling to wasm targets | |
-wasm = ["wasm-bindgen", "getrandom/js"] | |
+# For compiling to wasm targets | |
+wasm = ["wasm-bindgen", "getrandom/js", "rand"] | |
+ | |
+std = [] | |
[lib] | |
crate-type = ["cdylib", "rlib"] | |
\ No newline at end of file | |
diff --git a/README.md b/README.md | |
index fdb0246..80e8507 100644 | |
--- a/README.md | |
+++ b/README.md | |
@@ -13,7 +13,7 @@ A rust implementation of the Dilithium, a KEM standardised by the NIST Post-Quan | |
See the [**features**](#features) section for different options regarding security levels and modes of operation. The default security setting is Dilithium3. | |
-It is recommended to use Dilithium in a hybrid system alongside a traditional signature algorithm such as ed25519. | |
+It is recommended to use Dilithium in a hybrid system alongside a traditional signature algorithm such as ed25519. | |
**Minimum Supported Rust Version: 1.50.0** | |
@@ -23,25 +23,27 @@ It is recommended to use Dilithium in a hybrid system alongside a traditional si | |
```shell | |
cargo add pqc_dilithium | |
-``` | |
+``` | |
-## Usage | |
+## Usage | |
```rust | |
use pqc_dilithium::*; | |
+use rand_core::OsRng; | |
``` | |
### Key Generation | |
```rust | |
-let keys = Keypair::generate(); | |
+use rand_core:: | |
+let keys = Keypair::generate(&mut OsRng); | |
assert!(keys.public.len() == PUBLICKEYBYTES); | |
assert!(keys.expose_secret().len() == SECRETKEYBYTES); | |
``` | |
-### Signing | |
+### Signing | |
```rust | |
let msg = "Hello".as_bytes(); | |
-let sig = keys.sign(&msg); | |
+let sig = keys.sign(&msg, &mut OsRng); | |
assert!(sig.len() == SIGNBYTES); | |
``` | |
@@ -55,7 +57,7 @@ assert!(sig_verify.is_ok()); | |
## AES mode | |
-Dilithium-AES, that uses AES-256 in counter mode instead of SHAKE to | |
+Dilithium-AES, that uses AES-256 in counter mode instead of SHAKE to | |
expand the matrix and the masking vectors, and to sample the secret polynomials. | |
This offers hardware speedups on certain platforms. | |
@@ -87,7 +89,7 @@ By default this library uses Dilithium3 | |
--- | |
-## Testing | |
+## Testing | |
To run the known answer tests, you'll need to enable the `dilithium_kat` in `RUSTFLAGS` eg. | |
@@ -120,16 +122,16 @@ For example, using [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/): | |
wasm-pack build -- --features wasm | |
``` | |
-Which will export the wasm, javascript and typescript files into `./pkg/`. | |
+Which will export the wasm, javascript and typescript files into `./pkg/`. | |
-To compile a different variant into a separate folder: | |
+To compile a different variant into a separate folder: | |
```shell | |
-wasm-pack build --out-dir pkg_mode5/ -- --features "wasm mode5" | |
+wasm-pack build --out-dir pkg_mode5/ -- --features "wasm mode5" | |
``` | |
There is also a basic html demo in the [www](./www/readme.md) folder. | |
- | |
-From the www folder run: | |
+ | |
+From the www folder run: | |
```shell | |
npm install | |
@@ -140,11 +142,11 @@ npm run start | |
## Alternatives | |
-The PQClean project has rust bindings for their C post quantum libraries. | |
+The PQClean project has rust bindings for their C post quantum libraries. | |
https://github.com/rustpq/pqcrypto/tree/main/pqcrypto-dilithium | |
---- | |
+--- | |
## About | |
@@ -152,7 +154,7 @@ Dilithium is a digital signature scheme that is strongly secure under chosen mes | |
The official website: https://pq-crystals.org/dilithium/ | |
-Authors of the Dilithium Algorithm: | |
+Authors of the Dilithium Algorithm: | |
* Roberto Avanzi, ARM Limited (DE) | |
* Joppe Bos, NXP Semiconductors (BE) | |
diff --git a/benches/api.rs b/benches/api.rs | |
index b7ccfbb..599857d 100644 | |
--- a/benches/api.rs | |
+++ b/benches/api.rs | |
@@ -1,20 +1,21 @@ | |
use criterion::{black_box, criterion_group, criterion_main, Criterion}; | |
use pqc_dilithium::*; | |
+use rand_core::OsRng; | |
fn sign_small_msg(c: &mut Criterion) { | |
- let keys = Keypair::generate(); | |
+ let keys = Keypair::generate(&mut OsRng).unwrap(); | |
let msg = "Hello".as_bytes(); | |
c.bench_function("Sign Small Message", |b| { | |
- b.iter(|| keys.sign(black_box(msg))) | |
+ b.iter(|| keys.sign(&black_box(msg), &mut OsRng).unwrap()) | |
}); | |
} | |
fn verify_small_msg(c: &mut Criterion) { | |
- let keys = Keypair::generate(); | |
+ let keys = Keypair::generate(&mut OsRng).unwrap(); | |
let msg = "Hello".as_bytes(); | |
- let sig = keys.sign(msg); | |
+ let sig = keys.sign(msg, &mut OsRng).unwrap(); | |
c.bench_function("Verify Small Message", |b| { | |
- b.iter(|| verify(black_box(sig), black_box(msg), black_box(&keys.public))) | |
+ b.iter(|| verify(black_box(&sig), black_box(msg), black_box(&keys.public))) | |
}); | |
} | |
diff --git a/src/api.rs b/src/api.rs | |
index 3a29494..92bf99f 100644 | |
--- a/src/api.rs | |
+++ b/src/api.rs | |
@@ -1,5 +1,7 @@ | |
+use crate::error::*; | |
use crate::params::{PUBLICKEYBYTES, SECRETKEYBYTES, SIGNBYTES}; | |
use crate::sign::*; | |
+use rand_core::{CryptoRng, RngCore}; | |
#[derive(Copy, Clone, PartialEq, Eq, Hash)] | |
pub struct Keypair { | |
@@ -14,16 +16,12 @@ impl std::fmt::Debug for Keypair { | |
} | |
} | |
-pub enum SignError { | |
- Input, | |
- Verify, | |
-} | |
- | |
impl Keypair { | |
/// Explicitly expose secret key | |
/// ``` | |
/// # use pqc_dilithium::*; | |
- /// let keys = Keypair::generate(); | |
+ /// use rand_core::OsRng; | |
+ /// let keys = Keypair::generate(&mut OsRng).expect("couldn't obtain random bytes"); | |
/// let secret_key = keys.expose_secret(); | |
/// assert!(secret_key.len() == SECRETKEYBYTES); | |
/// ``` | |
@@ -36,15 +34,19 @@ impl Keypair { | |
/// Example: | |
/// ``` | |
/// # use pqc_dilithium::*; | |
- /// let keys = Keypair::generate(); | |
+ /// # use rand_core::OsRng; | |
+ /// let keys = Keypair::generate(&mut OsRng).expect("couldn't obtain random bytes"); | |
/// assert!(keys.public.len() == PUBLICKEYBYTES); | |
/// assert!(keys.expose_secret().len() == SECRETKEYBYTES); | |
/// ``` | |
- pub fn generate() -> Keypair { | |
+ pub fn generate<R>(rng: &mut R) -> Result<Keypair, DilithiumError> | |
+ where | |
+ R: RngCore + CryptoRng, | |
+ { | |
let mut public = [0u8; PUBLICKEYBYTES]; | |
let mut secret = [0u8; SECRETKEYBYTES]; | |
- crypto_sign_keypair(&mut public, &mut secret, None); | |
- Keypair { public, secret } | |
+ crypto_sign_keypair(&mut public, &mut secret, rng, None)?; | |
+ Ok(Keypair { public, secret }) | |
} | |
/// Generates a signature for the given message using a keypair | |
@@ -52,15 +54,23 @@ impl Keypair { | |
/// Example: | |
/// ``` | |
/// # use pqc_dilithium::*; | |
- /// # let keys = Keypair::generate(); | |
+ /// # use rand_core::OsRng; | |
+ /// # let keys = Keypair::generate(&mut OsRng).unwrap(); | |
/// let msg = "Hello".as_bytes(); | |
- /// let sig = keys.sign(&msg); | |
+ /// let sig = keys.sign(&msg, &mut OsRng).expect("couldn't obtain random bytes"); | |
/// assert!(sig.len() == SIGNBYTES); | |
- /// ``` | |
- pub fn sign(&self, msg: &[u8]) -> [u8; SIGNBYTES] { | |
+ /// ``` | |
+ pub fn sign<R>( | |
+ &self, | |
+ msg: &[u8], | |
+ rng: &mut R, | |
+ ) -> Result<[u8; SIGNBYTES], DilithiumError> | |
+ where | |
+ R: RngCore + CryptoRng, | |
+ { | |
let mut sig = [0u8; SIGNBYTES]; | |
- crypto_sign_signature(&mut sig, msg, &self.secret); | |
- sig | |
+ crypto_sign_signature(&mut sig, msg, &self.secret, rng)?; | |
+ Ok(sig) | |
} | |
} | |
@@ -69,18 +79,19 @@ impl Keypair { | |
/// Example: | |
/// ``` | |
/// # use pqc_dilithium::*; | |
-/// # let keys = Keypair::generate(); | |
+/// # use rand_core::OsRng; | |
+/// # let keys = Keypair::generate(&mut OsRng).unwrap(); | |
/// # let msg = [0u8; 32]; | |
-/// # let sig = keys.sign(&msg); | |
+/// # let sig = keys.sign(&msg, &mut OsRng).unwrap(); | |
/// let sig_verify = verify(&sig, &msg, &keys.public); | |
/// assert!(sig_verify.is_ok()); | |
pub fn verify( | |
sig: &[u8], | |
msg: &[u8], | |
public_key: &[u8], | |
-) -> Result<(), SignError> { | |
+) -> Result<(), DilithiumError> { | |
if sig.len() != SIGNBYTES { | |
- return Err(SignError::Input); | |
+ return Err(DilithiumError::Input); | |
} | |
crypto_sign_verify(&sig, &msg, public_key) | |
} | |
diff --git a/src/error.rs b/src/error.rs | |
new file mode 100644 | |
index 0000000..b334172 | |
--- /dev/null | |
+++ b/src/error.rs | |
@@ -0,0 +1,9 @@ | |
+#[derive(Debug, PartialEq)] | |
+pub enum DilithiumError { | |
+ Input, | |
+ Verify, | |
+ RandomBytesGeneration, | |
+} | |
+ | |
+#[cfg(feature = "std")] | |
+impl std::error::Error for DilithiumError {} | |
diff --git a/src/lib.rs b/src/lib.rs | |
index 33a1226..4ea0e69 100644 | |
--- a/src/lib.rs | |
+++ b/src/lib.rs | |
@@ -1,14 +1,15 @@ | |
#[cfg(feature = "aes")] | |
mod aes256ctr; | |
mod api; | |
+mod error; | |
mod fips202; | |
mod ntt; | |
mod packing; | |
mod params; | |
mod poly; | |
mod polyvec; | |
-mod randombytes; | |
mod reduce; | |
+mod rng; | |
mod rounding; | |
mod sign; | |
mod symmetric; | |
diff --git a/src/packing.rs b/src/packing.rs | |
index 561ffbf..77d2c4e 100644 | |
--- a/src/packing.rs | |
+++ b/src/packing.rs | |
@@ -1,4 +1,4 @@ | |
-use crate::{params::*, poly::*, polyvec::*, SignError}; | |
+use crate::{error::DilithiumError, params::*, poly::*, polyvec::*}; | |
/// Bit-pack public key pk = (rho, t1). | |
pub fn pack_pk(pk: &mut [u8], rho: &[u8], t1: &Polyveck) { | |
@@ -123,7 +123,7 @@ pub fn unpack_sig( | |
z: &mut Polyvecl, | |
h: &mut Polyveck, | |
sig: &[u8], | |
-) -> Result<(), SignError> { | |
+) -> Result<(), DilithiumError> { | |
let mut idx = 0usize; | |
c[..SEEDBYTES].copy_from_slice(&sig[..SEEDBYTES]); | |
@@ -138,12 +138,12 @@ pub fn unpack_sig( | |
let mut k = 0usize; | |
for i in 0..K { | |
if sig[idx + OMEGA + i] < k as u8 || sig[idx + OMEGA + i] > OMEGA_U8 { | |
- return Err(SignError::Input); | |
+ return Err(DilithiumError::Input); | |
} | |
for j in k..sig[idx + OMEGA + i] as usize { | |
// Coefficients are ordered for strong unforgeability | |
if j > k && sig[idx + j as usize] <= sig[idx + j as usize - 1] { | |
- return Err(SignError::Input); | |
+ return Err(DilithiumError::Input); | |
} | |
h.vec[i].coeffs[sig[idx + j] as usize] = 1; | |
} | |
@@ -153,7 +153,7 @@ pub fn unpack_sig( | |
// Extra indices are zero for strong unforgeability | |
for j in k..OMEGA { | |
if sig[idx + j as usize] > 0 { | |
- return Err(SignError::Input); | |
+ return Err(DilithiumError::Input); | |
} | |
} | |
diff --git a/src/randombytes.rs b/src/randombytes.rs | |
deleted file mode 100644 | |
index b67a2fc..0000000 | |
--- a/src/randombytes.rs | |
+++ /dev/null | |
@@ -1,5 +0,0 @@ | |
-use rand::prelude::*; | |
- | |
-pub fn randombytes(x: &mut [u8], len: usize) { | |
- thread_rng().fill_bytes(&mut x[..len]) | |
-} | |
diff --git a/src/rng.rs b/src/rng.rs | |
new file mode 100644 | |
index 0000000..249fee6 | |
--- /dev/null | |
+++ b/src/rng.rs | |
@@ -0,0 +1,16 @@ | |
+use crate::error::DilithiumError; | |
+use rand_core::*; | |
+ | |
+pub fn randombytes<R>( | |
+ x: &mut [u8], | |
+ len: usize, | |
+ rng: &mut R, | |
+) -> Result<(), DilithiumError> | |
+where | |
+ R: RngCore + CryptoRng, | |
+{ | |
+ match rng.try_fill_bytes(&mut x[..len]) { | |
+ Ok(_) => Ok(()), | |
+ Err(_) => Err(DilithiumError::RandomBytesGeneration), | |
+ } | |
+} | |
diff --git a/src/sign.rs b/src/sign.rs | |
index 6067211..0a54ace 100644 | |
--- a/src/sign.rs | |
+++ b/src/sign.rs | |
@@ -1,17 +1,22 @@ | |
use crate::{ | |
- fips202::*, packing::*, params::*, poly::*, polyvec::*, randombytes::*, | |
- SignError, | |
+ error::DilithiumError, fips202::*, packing::*, params::*, poly::*, | |
+ polyvec::*, rng::*, | |
}; | |
+use rand_core::{CryptoRng, RngCore}; | |
-pub fn crypto_sign_keypair( | |
+pub fn crypto_sign_keypair<R>( | |
pk: &mut [u8], | |
sk: &mut [u8], | |
+ rng: &mut R, | |
seed: Option<&[u8]>, | |
-) -> u8 { | |
+) -> Result<(), DilithiumError> | |
+where | |
+ R: RngCore + CryptoRng, | |
+{ | |
let mut init_seed = [0u8; SEEDBYTES]; | |
match seed { | |
Some(x) => init_seed.copy_from_slice(x), | |
- None => randombytes(&mut init_seed, SEEDBYTES), | |
+ None => randombytes(&mut init_seed, SEEDBYTES, rng)?, | |
}; | |
let mut seedbuf = [0u8; 2 * SEEDBYTES + CRHBYTES]; | |
let mut tr = [0u8; SEEDBYTES]; | |
@@ -61,10 +66,18 @@ pub fn crypto_sign_keypair( | |
shake256(&mut tr, SEEDBYTES, pk, PUBLICKEYBYTES); | |
pack_sk(sk, &rho, &tr, &key, &t0, &s1, &s2); | |
- return 0; | |
+ Ok(()) | |
} | |
-pub fn crypto_sign_signature(sig: &mut [u8], m: &[u8], sk: &[u8]) { | |
+pub fn crypto_sign_signature<R>( | |
+ sig: &mut [u8], | |
+ m: &[u8], | |
+ sk: &[u8], | |
+ rng: &mut R, | |
+) -> Result<(), DilithiumError> | |
+where | |
+ R: RngCore + CryptoRng, | |
+{ | |
// `key` and `mu` are concatenated | |
let mut keymu = [0u8; SEEDBYTES + CRHBYTES]; | |
@@ -97,7 +110,7 @@ pub fn crypto_sign_signature(sig: &mut [u8], m: &[u8], sk: &[u8]) { | |
shake256_squeeze(&mut keymu[SEEDBYTES..], CRHBYTES, &mut state); | |
if RANDOMIZED_SIGNING { | |
- randombytes(&mut rhoprime, CRHBYTES); | |
+ randombytes(&mut rhoprime, CRHBYTES, rng)?; | |
} else { | |
shake256(&mut rhoprime, CRHBYTES, &keymu, SEEDBYTES + CRHBYTES); | |
} | |
@@ -168,7 +181,7 @@ pub fn crypto_sign_signature(sig: &mut [u8], m: &[u8], sk: &[u8]) { | |
// Write signature | |
pack_sig(sig, None, &z, &h); | |
- return; | |
+ return Ok(()); | |
} | |
} | |
@@ -176,7 +189,7 @@ pub fn crypto_sign_verify( | |
sig: &[u8], | |
m: &[u8], | |
pk: &[u8], | |
-) -> Result<(), SignError> { | |
+) -> Result<(), DilithiumError> { | |
let mut buf = [0u8; K * POLYW1_PACKEDBYTES]; | |
let mut rho = [0u8; SEEDBYTES]; | |
let mut mu = [0u8; CRHBYTES]; | |
@@ -192,7 +205,7 @@ pub fn crypto_sign_verify( | |
let mut state = KeccakState::default(); // shake256_init() | |
if sig.len() != SIGNBYTES { | |
- return Err(SignError::Input); | |
+ return Err(DilithiumError::Input); | |
} | |
unpack_pk(&mut rho, &mut t1, pk); | |
@@ -200,7 +213,7 @@ pub fn crypto_sign_verify( | |
return Err(e); | |
} | |
if polyvecl_chknorm(&z, (GAMMA1 - BETA) as i32) > 0 { | |
- return Err(SignError::Input); | |
+ return Err(DilithiumError::Input); | |
} | |
// Compute CRH(CRH(rho, t1), msg) | |
@@ -240,7 +253,7 @@ pub fn crypto_sign_verify( | |
shake256_squeeze(&mut c2, SEEDBYTES, &mut state); | |
// Doesn't require constant time equality check | |
if c != c2 { | |
- Err(SignError::Verify) | |
+ Err(DilithiumError::Verify) | |
} else { | |
Ok(()) | |
} | |
diff --git a/src/wasm.rs b/src/wasm.rs | |
index 123e49b..3cc5c04 100644 | |
--- a/src/wasm.rs | |
+++ b/src/wasm.rs | |
@@ -12,16 +12,21 @@ pub struct Keys { | |
} | |
#[wasm_bindgen] | |
-pub fn keypair() -> Keys { | |
- Keys { | |
- keypair: api::Keypair::generate(), | |
+pub fn keypair() -> Result<Keys, JsError> { | |
+ let mut rng = rand::rngs::OsRng {}; | |
+ match api::Keypair::generate(&mut rng) { | |
+ Ok(keypair) => Ok(Keys { keypair }), | |
+ Err(error::DilithiumError::RandomBytesGeneration) => { | |
+ Err(JsError::new("Error trying to fill random bytes")) | |
+ } | |
+ _ => Err(JsError::new("The keypair could not be generated")), | |
} | |
} | |
#[wasm_bindgen] | |
impl Keys { | |
#[wasm_bindgen(constructor)] | |
- pub fn new() -> Keys { | |
+ pub fn new() -> Result<Keys, JsError> { | |
keypair() | |
} | |
@@ -36,8 +41,12 @@ impl Keys { | |
} | |
#[wasm_bindgen] | |
- pub fn sign(&self, msg: Box<[u8]>) -> Box<[u8]> { | |
- Box::new(self.keypair.sign(&msg)) | |
+ pub fn sign(&self, msg: Box<[u8]>) -> Result<Box<[u8]>, JsValue> { | |
+ let mut rng = rand::rngs::OsRng {}; | |
+ match self.keypair.sign(&msg, &mut rng) { | |
+ Ok(signature) => Ok(Box::new(signature)), | |
+ Err(_) => Err(JsValue::null()), | |
+ } | |
} | |
} | |
diff --git a/tests/integration.rs b/tests/integration.rs | |
index cd0dfd9..d9958be 100644 | |
--- a/tests/integration.rs | |
+++ b/tests/integration.rs | |
@@ -2,17 +2,19 @@ use pqc_dilithium::*; | |
#[test] | |
fn sign_then_verify_valid() { | |
+ let mut rng = rand::thread_rng(); | |
let msg = b"Hello"; | |
- let keys = Keypair::generate(); | |
- let signature = keys.sign(msg); | |
+ let keys = Keypair::generate(&mut rng).unwrap(); | |
+ let signature = keys.sign(msg, &mut rng).unwrap(); | |
assert!(verify(&signature, msg, &keys.public).is_ok()) | |
} | |
#[test] | |
fn sign_then_verify_invalid() { | |
+ let mut rng = rand::thread_rng(); | |
let msg = b"Hello"; | |
- let keys = Keypair::generate(); | |
- let mut signature = keys.sign(msg); | |
+ let keys = Keypair::generate(&mut rng).unwrap(); | |
+ let mut signature = keys.sign(msg, &mut rng).unwrap(); | |
signature[..4].copy_from_slice(&[255u8; 4]); | |
assert!(verify(&signature, msg, &keys.public).is_err()) | |
} | |
diff --git a/tests/kat.rs b/tests/kat.rs | |
index 5300946..897193c 100644 | |
--- a/tests/kat.rs | |
+++ b/tests/kat.rs | |
@@ -2,6 +2,7 @@ | |
use pqc_core::load::*; | |
use pqc_dilithium::*; | |
+use rand_core::OsRng; | |
use std::path::PathBuf; | |
const MODE: u8 = if cfg!(feature = "mode2") { | |
@@ -25,7 +26,8 @@ fn keypair() { | |
let sk = kat.sk.clone(); | |
let mut pk2 = [0u8; PUBLICKEYBYTES]; | |
let mut sk2 = [0u8; SECRETKEYBYTES]; | |
- crypto_sign_keypair(&mut pk2, &mut sk2, Some(&bufvec[i])); | |
+ crypto_sign_keypair(&mut pk2, &mut sk2, &mut OsRng, Some(&bufvec[i])) | |
+ .unwrap(); | |
assert_eq!(pk, pk2); | |
assert_eq!(sk, sk2); | |
} | |
@@ -41,7 +43,7 @@ pub fn sign() { | |
let msg = kat.msg.clone(); | |
let sk = kat.sk.clone(); | |
let mut sig = vec![0u8; SIGNBYTES]; | |
- crypto_sign_signature(&mut sig, &msg, &sk); | |
+ crypto_sign_signature(&mut sig, &msg, &sk, &mut OsRng).unwrap(); | |
assert_eq!(sm[..SIGNBYTES], sig); | |
} | |
} | |
diff --git a/tests/wasm.js b/tests/wasm.js | |
index 34ba6c1..a1e4544 100644 | |
--- a/tests/wasm.js | |
+++ b/tests/wasm.js | |
@@ -2,7 +2,7 @@ | |
// Uses CommonJS modules | |
// Package needs to be built for node: | |
-// wasm-pack build --target nodejs -- features wasm | |
+// wasm-pack build --target nodejs -- --features wasm | |
const dilithium = require("../pkg/pqc_dilithium"); | |
const assert = require("assert"); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment