Skip to content

Post-Quantum Cryptography NIF based on PQClean for Erlang and Elixir

License

Notifications You must be signed in to change notification settings

potatosalad/erlang-pqclean

Repository files navigation

pqclean NIF

Build Status Hex.pm

Post-Quantum Cryptography NIF based on PQClean for Erlang and Elixir.

See documentation for the pqclean_nif module for the full list of types and functions provided.

Installation

Add pqclean to your project's dependencies in mix.exs

defp deps do
  [
    {:pqclean, "~> 0.0.3"}
  ]
end

Add pqclean to your project's dependencies in your Makefile for erlang.mk or the following to your rebar.config

{deps, [
    {pqclean, "0.0.3"}
]}.

Examples

{PK, SK} = pqclean_nif:kyber768_keypair(),
{CT, SS} = pqclean_nif:kyber768_encapsulate(PK),
     SS  = pqclean_nif:kyber768_decapsulate(CT, SK).

KEM with Encryption Example

% Alice and Bob want to exchange an encrypted messages.
% Alice wants to send Bob the message "a2b".
% Bob wants to send Alice the message "b2a".

% Helper functions (encrypt/decrypt with AES-256-GCM):
Encrypt = fun(K, N, PTxt) ->
    crypto:crypto_one_time_aead(aes_256_gcm, K, <<N:96>>, PTxt, <<>>, true)
end,
Decrypt = fun(K, N, CTxt, CTag) ->
    crypto:crypto_one_time_aead(aes_256_gcm, K, <<N:96>>, CTxt, <<>>, CTag, false)
end.

% Alice generates a new ephemeral keypair using Kyber-768:
{PKa, SKa} = pqclean_nif:kyber768_keypair().

% Alice sends `PKa' to Bob.

% Bob generates a new ephemeral keypair using Kyber-768:
{PKb, SKb} = pqclean_nif:kyber768_keypair(),
% Bob encapsulates a shared-secret `SSb2a' against Alice's `PKa' with
% an ephemeral KEM cipher-text `CTb2a' using Kyber-768:
{CTb2a, SSb2a} = pqclean_nif:kyber768_encapsulate(PKa),
% Bob encrypts plain-text `PKb' with shared-secret `SSb2a' and nonce `0'
% into cipher-text `CTxt_PKb' and cipher-tag `CTag_PKb':
{CTxt_PKb, CTag_PKb} = Encrypt(SSb2a, 0, PKb),
% Bob encrypts plain-text "b2a" with shared-secret `SSb2a' and nonce `1'
% into cipher-text `CTxt_PKb' and cipher-tag `CTag_PKb':
{CTxt_Mb, CTag_Mb} = Encrypt(SSb2a, 1, <<"b2a">>).

% Bob sends `CTb2a', `CTxt_PKb', `CTag_PKb', `CTxt_Mb', and `CTag_Mb' to Alice.

% Alice decapsulates Bob's `CTb2a' using secret-key `SKa' which
% results in shared-secret `SSb2a' using Kyber-768:
SSb2a = pqclean_nif:kyber768_decapsulate(CTb2a, SKa),
% Alice decrypts `PKb' with shared-secret `SSb2a':
PKb = Decrypt(SSb2a, 0, CTxt_PKb, CTag_PKb),
% Alice decrypts Bob's message "b2a" using shared-secret `SSb2a':
<<"b2a">> = Decrypt(SSb2a, 1, CTxt_Mb, CTag_Mb),
% Alice encapsulates a shared-secret `SSa2b' against Bob's `PKb' with
% an ephemeral KEM cipher-text `CTa2b' using Kyber-768:
{CTa2b, SSa2b} = pqclean_nif:kyber768_encapsulate(PKb),
% Alice encrypts plain-text "a2b" with shared-secret `SSa2b' and nonce `0'
% into cipher-text `CTxt_Ma' and cipher-tag `CTag_Ma':
{CTxt_Ma, CTag_Ma} = Encrypt(SSa2b, 0, <<"a2b">>).

% Alice sends `CTa2b', `CTxt_Ma', and `CTag_Ma' to Bob.

% Bob decapsulates Alice's `CTa2b' using secret-key `SKb' which
% results in shared-secret `SSa2b' using Kyber-768:
SSa2b = pqclean_nif:kyber768_decapsulate(CTa2b, SKb),
% Bob decrypts Alice's message "a2b" using shared-secret `SSa2b':
<<"a2b">> = Decrypt(SSa2b, 0, CTxt_Ma, CTag_Ma).

% Alice sends Bob a total of 2,291-bytes.
% Bob sends Alice a total of 2,307-bytes.

See PQNoise for more in-depth examples.

Signature Algorithm Example

{PK, SK} = pqclean_nif:falcon512_keypair(),
Msg = <<"message">>,
Sig = pqclean_nif:falcon512_sign(Msg, SK),
true = pqclean_nif:falcon512_verify(Sig, Msg, PK).

KEM Algorithm Support

KEM Algorithm NIST Level Public Key Secret Key Cipher Text Shared Secret
HQC-RMRS-128 1 2,249 2,289 4,481 64
HQC-RMRS-192 3 4,522 4,562 9,026 64
HQC-RMRS-256 5 7,245 7,285 14,469 64
Kyber512 1 800 1,632 768 32
Kyber512-90s 1 800 1,632 768 32
Kyber768 3 1,184 2,400 1,088 32
Kyber768-90s 3 1,184 2,400 1,088 32
Kyber1024 5 1,568 3,168 1,568 32
Kyber1024-90s 5 1,568 3,168 1,568 32
Classic McEliece 348864 1 261,120 6,452 128 32
Classic McEliece 348864f 1 261,120 6,452 128 32
Classic McEliece 460896 3 524,160 13,568 188 32
Classic McEliece 460896f 3 524,160 13,568 188 32
Classic McEliece 6688128 5 1,044,992 13,892 240 32
Classic McEliece 6688128 5 1,044,992 13,892 240 32
Classic McEliece 6960119 5 1,047,319 13,908 226 32
Classic McEliece 6960119f 5 1,047,319 13,908 226 32
Classic McEliece 8192128 5 1,357,824 14,080 240 32
Classic McEliece 8192128f 5 1,357,824 14,080 240 32

WARNING: Algorithms marked with a dagger (†) require a large stack for key generation. See below for more information.

Large Stack Support

When generating keys for "large stack" algorithms, an exception will be raised if the detected stack size is below 8MB:

1> try pqclean_nif:mceliece348864_keypair() catch error:{badarg, {_File, _Line}, Reason} -> Reason end.
"Key generation for Classic McEliece 348864 requires a large stack (>= 8MB): "
"please restart the BEAM with `erl +sssdcpu 1024` on 64-bit machines "
"(or `erl +sssdcpu 2048` on 32-bit machines); current setting is `erl +sssdcpu 41`"

Restarting the BEAM with erl +sssdcpu 1024 on 64-bit systems will allow key generation for these algorithms to be supported.

NOTE: If using an escript, rebar3, elixir, etc: it may be simpler to use the environment variable ERL_AFLAGS="+sssdcpu 1024" instead.

$ erl +sssdcpu 1024
1> {PK, SK} = pqclean_nif:mceliece348864_keypair().
{<<38,72,183,62,48,9,8,23,83,149,228,233,255,143,120,71,
   113,143,14,95,28,157,43,73,51,99,6,79,...>>,
 <<116,53,239,220,26,165,236,199,7,246,124,172,167,182,
   154,60,152,213,9,243,206,191,24,129,129,73,132,...>>}

Signature Algorithm Support

Signature Algorithm NIST Level Public Key Secret Key Signature Seed
Dilithium2 2 1,312 2,528 2,420
Dilithium2-AES 2 1,312 2,528 2,420
Dilithium3 3 1,952 4,000 3,293
Dilithium3-AES 3 1,952 4,000 3,293
Dilithium5 5 2,592 4,864 4,595
Dilithium5-AES 5 2,592 4,864 4,595
Falcon-512 1 897 1,281 666
Falcon-1024 5 1,793 2,305 1,280
SPHINCS+-haraka-128f-robust 1 32 64 17,088 48
SPHINCS+-haraka-128f-simple 1 32 64 17,088 48
SPHINCS+-haraka-128s-robust 1 32 64 7,856 48
SPHINCS+-haraka-128s-simple 1 32 64 7,856 48
SPHINCS+-haraka-192f-robust 2 48 96 35,664 72
SPHINCS+-haraka-192f-simple 2 48 96 35,664 72
SPHINCS+-haraka-192s-robust 2 48 96 16,224 72
SPHINCS+-haraka-192s-simple 2 48 96 16,224 72
SPHINCS+-haraka-256f-robust 2 64 128 49,856 96
SPHINCS+-haraka-256f-simple 2 64 128 49,856 96
SPHINCS+-haraka-256s-robust 2 64 128 29,792 96
SPHINCS+-haraka-256s-simple 2 64 128 29,792 96
SPHINCS+-sha2-128f-robust 1 32 64 17,088 48
SPHINCS+-sha2-128f-simple 1 32 64 17,088 48
SPHINCS+-sha2-128s-robust 1 32 64 7,856 48
SPHINCS+-sha2-128s-simple 1 32 64 7,856 48
SPHINCS+-sha2-192f-robust 3 48 96 35,664 72
SPHINCS+-sha2-192f-simple 3 48 96 35,664 72
SPHINCS+-sha2-192s-robust 3 48 96 16,224 72
SPHINCS+-sha2-192s-simple 3 48 96 16,224 72
SPHINCS+-sha2-256f-robust 5 64 128 49,856 96
SPHINCS+-sha2-256f-simple 5 64 128 49,856 96
SPHINCS+-sha2-256s-robust 5 64 128 29,792 96
SPHINCS+-sha2-256s-simple 5 64 128 29,792 96
SPHINCS+-shake-128f-robust 1 32 64 17,088 48
SPHINCS+-shake-128f-simple 1 32 64 17,088 48
SPHINCS+-shake-128s-robust 1 32 64 7,856 48
SPHINCS+-shake-128s-simple 1 32 64 7,856 48
SPHINCS+-shake-192f-robust 3 48 96 35,664 72
SPHINCS+-shake-192f-simple 3 48 96 35,664 72
SPHINCS+-shake-192s-robust 3 48 96 16,224 72
SPHINCS+-shake-192s-simple 3 48 96 16,224 72
SPHINCS+-shake-256f-robust 5 64 128 49,856 96
SPHINCS+-shake-256f-simple 5 64 128 49,856 96
SPHINCS+-shake-256s-robust 5 64 128 29,792 96
SPHINCS+-shake-256s-simple 5 64 128 29,792 96

About

Post-Quantum Cryptography NIF based on PQClean for Erlang and Elixir

Resources

License

Stars

Watchers

Forks

Packages

No packages published