Skip to content

Instantly share code, notes, and snippets.

@paulmillr
Created April 23, 2024 16:08
Show Gist options
  • Save paulmillr/f655a39d7144481e1bc0a374fb65689d to your computer and use it in GitHub Desktop.
Save paulmillr/f655a39d7144481e1bc0a374fb65689d to your computer and use it in GitHub Desktop.
noble vs tweetnacl
npm install
npm run build | wc
# => 24    1092   36499 == 36KB
npm run build-nacl | wc
# => 5     225   28459 == 28KB
export { box_keyPair, sign_detached_verify, sign, box, box_open } from 'tweetnacl-ts';
export { xchacha20poly1305 } from '@noble/ciphers/chacha';
export { concatBytes } from '@noble/ciphers/utils';
export { ed25519 } from '@noble/curves/ed25519';
export { hkdf } from '@noble/hashes/hkdf';
export { sha512 } from '@noble/hashes/sha512';
{
"name": "nacl",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "npx esbuild --bundle inp.mjs --minify",
"build-nacl": "npx esbuild --bundle inp-nacl.mjs --minify"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@noble/ciphers": "0.5.2",
"@noble/curves": "1.4.0",
"@noble/hashes": "1.4.0",
"tweetnacl": "1.0.3"
},
"devDependencies": {
"esbuild": "0.20.2"
}
}
@nikitaeverywhere
Copy link

So, overall, noble is smaller than tweetnacl if you use ciphers/_micro and noble-ed25519. As a bonus, it's faster.

Sounds great! Thanks for suggesting.

hkdf is good and I suggest to keep it. Just pointing out that your 26kb tweetnacl bundle does not include it.

I'm a bit confused: tweetnacl doesn't include it - yes, but it does include other algos to achieve

  1. asymmetric encryption / decryption
  2. signing / verifying

=> all I need for my task (plus the minimal possible lib size). To my understanding, I can't do it without hkdf in noble (finding a common secret key for chacha encryption), can I?

I'm unsure what's the most minimal primitives toolkit when using noble for 1 and 2.

@paulmillr
Copy link
Author

nacl uses x25519 for box. Not ed25519. x25519 does not provide signing or verification - it only provides ECDH. See https://nacl.cr.yp.to/box.html

To replicate nacl box:

let shared_key = x25519(public_key_a, private_key_b)
let nonce = randomBytes(24)
xsalsa20poly1305(shared_key, nonce).encrypt(data)

x25519 is available in noble-curves. If you also want to sign and verify something, that would require different set of keys. Tweetnacl AFAICS does not provide a way to convert x25519 key into ed25519 key. So, while tweetnacl has signing and verification separately, you can't really do it, without something like KDF.

@nikitaeverywhere
Copy link

nikitaeverywhere commented Apr 24, 2024

Thanks a ton - your answers really help.

while tweetnacl has signing and verification separately, you can't really do it, without something like KDF.

I'm really thinking high-level here and can't get why you say I can't do it. encryption / decryption and signing / verifying are 2 different tasks in my system, same as exposed in nacl api. I don't need a shared private key between these 2 tasks. I use this approach to give you a bit more of context:

  1. I generate a random keypair for box / open (for x25519 I guess)
  2. I generate a random keypair for sign/verify - used in sign and nacl_detached_verify
  3. "Communication" layer of my system uses (1.) to send end-to-end secure messages over insecure apis (say, browser windows)
  4. I use (2.) to sign the public key (1.) with some other data to verify that this public key is "genuine" (generated by my system) and thus the system by checking it authorizes the communication.

And the question really is: I don't care about what to use, I just need the simplest and the most tiny crypto primitives to do sign+verify and asymmetric encrypt/decrypt as separate tasks. nacl has everything I need: and I'm unsure what minimal set of primitives I need to take from noble to make it happen.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment