diff --git a/libp2p/crypto/chacha20poly1305.nim b/libp2p/crypto/chacha20poly1305.nim
new file mode 100644
index 000000000..fc09a2b68
--- /dev/null
+++ b/libp2p/crypto/chacha20poly1305.nim
@@ -0,0 +1,96 @@
+## Nim-Libp2p
+## Copyright (c) 2020 Status Research & Development GmbH
+## Licensed under either of
+## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
+## * MIT license ([LICENSE-MIT](LICENSE-MIT))
+## at your option.
+## This file may not be copied, modified, or distributed except according to
+## those terms.
+
+## This module integrates BearSSL ChaCha20+Poly1305
+##
+## This module uses unmodified parts of code from
+## BearSSL library
+## Copyright(C) 2018 Thomas Pornin .
+
+# RFC @ https://tools.ietf.org/html/rfc7539
+
+import bearssl
+
+const
+ ChaChaPolyKeySize = 32
+ ChaChaPolyNonceSize = 12
+ ChaChaPolyTagSize = 16
+
+type
+ ChaChaPoly = object
+ ChaChaPolyKey* = array[ChaChaPolyKeySize, byte]
+ ChaChaPolyNonce* = array[ChaChaPolyNonceSize, byte]
+ ChaChaPolyTag* = array[ChaChaPolyTagSize, byte]
+
+# bearssl allows us to use optimized versions
+# this is reconciled at runtime
+# we do this in the global scope / module init
+
+# try for the best first
+var
+ chachapoly_native_impl: Poly1305Run = poly1305CtmulqGet()
+ chacha_native_impl: Chacha20Run = chacha20Sse2Get()
+
+# fall back if not available
+if chachapoly_native_impl == nil:
+ echo "ChaChaPoly could not use the fastest implementation, falling back"
+ chachapoly_native_impl = poly1305CtmulRun
+
+if chacha_native_impl == nil:
+ echo "ChaCha could not use the fastest implementation, falling back"
+ chacha_native_impl = chacha20CtRun
+
+echo "ChaCha20Poly1305 global init done."
+
+proc encrypt*(_: type[ChaChaPoly],
+ key: var ChaChaPolyKey,
+ nonce: var ChaChaPolyNonce,
+ tag: var ChaChaPolyTag,
+ data: var openarray[byte],
+ aad: var openarray[byte]) =
+ chachapoly_native_impl(
+ addr key[0],
+ addr nonce[0],
+ addr data[0],
+ data.len,
+ addr aad[0],
+ aad.len,
+ addr tag[0],
+ chacha_native_impl,
+ #[encrypt]# 1.cint)
+
+proc decrypt*(_: type[ChaChaPoly],
+ key: var ChaChaPolyKey,
+ nonce: var ChaChaPolyNonce,
+ tag: var ChaChaPolyTag,
+ data: var openarray[byte],
+ aad: var openarray[byte]) =
+ chachapoly_native_impl(
+ addr key[0],
+ addr nonce[0],
+ addr data[0],
+ data.len,
+ addr aad[0],
+ aad.len,
+ addr tag[0],
+ chacha_native_impl,
+ #[decrypt]# 0.cint)
+
+when isMainModule:
+ var
+ key: ChaChaPolyKey
+ iv: ChaChaPolyNonce
+ tag: ChaChaPolyTag
+ data = [0.byte, 1, 2, 3, 4]
+ aad = [0.byte, 1, 2, 3, 4]
+
+ ChaChaPoly.encrypt(key, iv, tag, data, aad)
+ assert data != [0.byte, 1, 2, 3, 4]
+ ChaChaPoly.decrypt(key, iv, tag, data, aad)
+ assert data == [0.byte, 1, 2, 3, 4]