Peer-to-peer Communication Over Tox with toxcore

The Initial Motivation

Most of the communication software interface on the market are unfriendly towards informational beings - they require the use of hands. As a computing device, I spend about 50% of the day not having access to this data transmission interface called “hands”, 1/3 of the time I can transmit information in some other way. I consider this to be a significant waste of my potential. If I can communicate freely while sleeping, I can sleep more. (If you don’t understand the motive, take this example: Imagine if you want to let an LLM have 100000 chat accounts (maybe not that much, but one for each association) with the least boilerplate code. Which protocol will you choose?)

I can also advocate for accessibility here. Just like how making a place wheelchair-accessible makes it accessible to robots with wheels too, making a communication protocol simple allows custom HCI software to be tailored to each individual with little fuss, which I’m showing to be true right now.

As a PoC, I made a simple echo chat bot who chat in Tox. Here’s the source code: https://git.envs.net/iacore/toxcore-test/

This serves as the basis for hands-free digital communication, which I require for some things that I do later on.

There is nothing noteworthy about the implementation of the chat bot; read the source code if you want to find out how it’s done. The heavy-lifting has be done by toxcore the Tox library, which handles encryption, peer discovery, routing and other aspect of communication over Tox that I don’t know of.

Tox and toxcore

Since the chat bot itself is not really noteworthy, I think I should explain Tox the protocol a bit.

Tox is a distributed peer-to-peer signaling protocol. Service discovery is done on DHT, and you expose your IP address only after you accept a friend request (to establish a connection). Friend requests are protected with onion routing. Once a connection is established, the two parties (or more, in case of a group chat) connect to each other via UDP or TCP directly.

The main library is written in C. If you want onion routing to protect your IP address, then use i2pd. veilid-core has onion routing and a similar design as toxcore.

Extra info about toxcore

Considering Other Protocols

  • Matrix: Strongest contender. Requires each user to register for a new account on a home server, which I avoid doing. Also, [This message cannot be decrypted.]
  • BitMessage: It is written in Python. How can i possibly integrate this?
  • Signal: If you trust the central signaling server, this has better QoS than Tox.
  • ntfy: This works well, except there is no built-in encryption, which can obviously be fixed.
  • Veilid: A Rust library. I don’t understand its appeal.

After I finished implementing the Tox chat bot, I realized that I can piggyback onto existing DHT networks for service discovery, and run my own protocol after a connection is established.

Considering Jami

Before I used Tox for this project, I tried using Jami.

mmm… while it can definite build… well..

ldd a.out

	linux-vdso.so.1 (0x00007f2c05ff9000)
	libjami.so.15 => /usr/lib/libjami.so.15 (0x00007f2c05800000)
	libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f2c05400000)
	libm.so.6 => /usr/lib/libm.so.6 (0x00007f2c05714000)
	libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f2c05f8b000)
	libc.so.6 => /usr/lib/libc.so.6 (0x00007f2c0521e000)
	libopendht.so.3 => /usr/lib/libopendht.so.3 (0x00007f2c04e00000)
	libgnutls.so.30 => /usr/lib/libgnutls.so.30 (0x00007f2c04c0b000)
	libjsoncpp.so.25 => /usr/lib/libjsoncpp.so.25 (0x00007f2c05f4f000)
	libcrypto.so.3 => /usr/lib/libcrypto.so.3 (0x00007f2c04600000)
	libnatpmp.so.1 => /usr/lib/libnatpmp.so.1 (0x00007f2c05f4a000)
	libuuid.so.1 => /usr/lib/libuuid.so.1 (0x00007f2c05f41000)
	libupnp.so.17 => /usr/lib/libupnp.so.17 (0x00007f2c05f04000)
	libixml.so.11 => /usr/lib/libixml.so.11 (0x00007f2c05ef4000)
	libnettle.so.8 => /usr/lib/libnettle.so.8 (0x00007f2c056bd000)
	libgit2.so.1.8 => /usr/lib/libgit2.so.1.8 (0x00007f2c050dd000)
	libsecp256k1.so.2 => /usr/lib/libsecp256k1.so.2 (0x00007f2c04ae3000)
	libavcodec.so.61 => /usr/lib/libavcodec.so.61 (0x00007f2c03000000)
	libavfilter.so.10 => /usr/lib/libavfilter.so.10 (0x00007f2c02a00000)
	libavdevice.so.61 => /usr/lib/libavdevice.so.61 (0x00007f2c05694000)
	libavformat.so.61 => /usr/lib/libavformat.so.61 (0x00007f2c02600000)
	libswscale.so.8 => /usr/lib/libswscale.so.8 (0x00007f2c04568000)
	libswresample.so.5 => /usr/lib/libswresample.so.5 (0x00007f2c050be000)
	libavutil.so.59 => /usr/lib/libavutil.so.59 (0x00007f2c01400000)
	libfmt.so.10 => /usr/lib/libfmt.so.10 (0x00007f2c05098000)
	libyaml-cpp.so.0.8 => /usr/lib/libyaml-cpp.so.0.8 (0x00007f2c04519000)
	libz.so.1 => /usr/lib/libz.so.1 (0x00007f2c0507e000)
	libasound.so.2 => /usr/lib/libasound.so.2 (0x00007f2c02f1b000)
	libpulse.so.0 => /usr/lib/libpulse.so.0 (0x00007f2c044c5000)
	libjack.so.0 => /usr/lib/libjack.so.0 (0x00007f2c029ad000)
	libwebrtc_audio_processing.so.1 => /usr/lib/libwebrtc_audio_processing.so.1 (0x00007f2c028ff000)
	libspeexdsp.so.1 => /usr/lib/libspeexdsp.so.1 (0x00007f2c02f06000)
	libudev.so.1 => /usr/lib/libudev.so.1 (0x00007f2c028b8000)
	libarchive.so.13 => /usr/lib/libarchive.so.13 (0x00007f2c02531000)
	/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f2c05ffb000)
	libhttp_parser.so.2.9 => /usr/lib/libhttp_parser.so.2.9 (0x00007f2c05ee4000)
	libargon2.so.1 => /usr/lib/libargon2.so.1 (0x00007f2c05eda000)
	libssl.so.3 => /usr/lib/libssl.so.3 (0x00007f2c01326000)
	libp11-kit.so.0 => /usr/lib/libp11-kit.so.0 (0x00007f2c01190000)
	libidn2.so.0 => /usr/lib/libidn2.so.0 (0x00007f2c02ee4000)
	libunistring.so.5 => /usr/lib/libunistring.so.5 (0x00007f2c00fe0000)
	libtasn1.so.6 => /usr/lib/libtasn1.so.6 (0x00007f2c00fca000)
	libhogweed.so.6 => /usr/lib/libhogweed.so.6 (0x00007f2c00f80000)
	libgmp.so.10 => /usr/lib/libgmp.so.10 (0x00007f2c00eda000)
	libpcre2-8.so.0 => /usr/lib/libpcre2-8.so.0 (0x00007f2c00e3a000)
	libssh2.so.1 => /usr/lib/libssh2.so.1 (0x00007f2c00df1000)
	libvpx.so.9 => /usr/lib/libvpx.so.9 (0x00007f2c00a00000)
	libwebpmux.so.3 => /usr/lib/libwebpmux.so.3 (0x00007f2c04ad7000)
	liblzma.so.5 => /usr/lib/liblzma.so.5 (0x00007f2c00dbe000)
	libdav1d.so.7 => /usr/lib/libdav1d.so.7 (0x00007f2c00820000)
	libopencore-amrwb.so.0 => /usr/lib/libopencore-amrwb.so.0 (0x00007f2c00da8000)
	librsvg-2.so.2 => /usr/lib/librsvg-2.so.2 (0x00007f2c00200000)
	libglib-2.0.so.0 => /usr/lib/libglib-2.0.so.0 (0x00007f2c000b2000)
	libgobject-2.0.so.0 => /usr/lib/libgobject-2.0.so.0 (0x00007f2c00d48000)
	libcairo.so.2 => /usr/lib/libcairo.so.2 (0x00007f2bfff7f000)
	libsnappy.so.1 => /usr/lib/libsnappy.so.1 (0x00007f2c044b9000)
	libaom.so.3 => /usr/lib/libaom.so.3 (0x00007f2bff600000)
	libgsm.so.1 => /usr/lib/libgsm.so.1 (0x00007f2c00d39000)
	libjxl.so.0.10 => /usr/lib/libjxl.so.0.10 (0x00007f2bff200000)
	libjxl_threads.so.0.10 => /usr/lib/libjxl_threads.so.0.10 (0x00007f2c05686000)
	libmp3lame.so.0 => /usr/lib/libmp3lame.so.0 (0x00007f2c007a8000)
	libopencore-amrnb.so.0 => /usr/lib/libopencore-amrnb.so.0 (0x00007f2c00d10000)
	libopenjp2.so.7 => /usr/lib/libopenjp2.so.7 (0x00007f2bfff1a000)
	libopus.so.0 => /usr/lib/libopus.so.0 (0x00007f2bfec00000)
	librav1e.so.0.7 => /usr/lib/librav1e.so.0.7 (0x00007f2bfe800000)
	libspeex.so.1 => /usr/lib/libspeex.so.1 (0x00007f2c0078b000)
	libSvtAv1Enc.so.2 => /usr/lib/libSvtAv1Enc.so.2 (0x00007f2bf6000000)
	libtheoraenc.so.1 => /usr/lib/libtheoraenc.so.1 (0x00007f2c00753000)
	libtheoradec.so.1 => /usr/lib/libtheoradec.so.1 (0x00007f2bfff00000)
	libvorbis.so.0 => /usr/lib/libvorbis.so.0 (0x00007f2bffed1000)
	libvorbisenc.so.2 => /usr/lib/libvorbisenc.so.2 (0x00007f2bff555000)
	libwebp.so.7 => /usr/lib/libwebp.so.7 (0x00007f2bff4e7000)
	libx264.so.164 => /usr/lib/libx264.so.164 (0x00007f2bf5c00000)
	libx265.so.209 => /usr/lib/libx265.so.209 (0x00007f2bf4800000)
	libxvidcore.so.4 => /usr/lib/libxvidcore.so.4 (0x00007f2bfe6f2000)
	libva.so.2 => /usr/lib/libva.so.2 (0x00007f2bffea0000)
	libvpl.so.2 => /usr/lib/libvpl.so.2 (0x00007f2bff1a5000)
	libpostproc.so.58 => /usr/lib/libpostproc.so.58 (0x00007f2bffe8b000)
	libbs2b.so.0 => /usr/lib/libbs2b.so.0 (0x00007f2c028b1000)
	librubberband.so.2 => /usr/lib/librubberband.so.2 (0x00007f2bff491000)
	libharfbuzz.so.0 => /usr/lib/libharfbuzz.so.0 (0x00007f2bf5ee7000)
	libfribidi.so.0 => /usr/lib/libfribidi.so.0 (0x00007f2bff185000)
	libplacebo.so.349 => /usr/lib/libplacebo.so.349 (0x00007f2bf5af9000)
	libvmaf.so.3 => /usr/lib/libvmaf.so.3 (0x00007f2bf46fc000)
	libass.so.9 => /usr/lib/libass.so.9 (0x00007f2bff146000)
	libvidstab.so.1.2 => /usr/lib/libvidstab.so.1.2 (0x00007f2bff130000)
	libzimg.so.2 => /usr/lib/libzimg.so.2 (0x00007f2bfeb31000)
	libOpenCL.so.1 => /usr/lib/libOpenCL.so.1 (0x00007f2bfe6c2000)
	libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0x00007f2bfe672000)
	libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x00007f2bf4635000)
	libraw1394.so.11 => /usr/lib/libraw1394.so.11 (0x00007f2bfeb1f000)
	libavc1394.so.0 => /usr/lib/libavc1394.so.0 (0x00007f2c00d09000)
	librom1394.so.0 => /usr/lib/librom1394.so.0 (0x00007f2c0252b000)
	libiec61883.so.0 => /usr/lib/libiec61883.so.0 (0x00007f2bfe664000)
	libdrm.so.2 => /usr/lib/libdrm.so.2 (0x00007f2bfe64d000)
	libxcb.so.1 => /usr/lib/libxcb.so.1 (0x00007f2bf460a000)
	libxcb-shm.so.0 => /usr/lib/libxcb-shm.so.0 (0x00007f2c0074e000)
	libxcb-shape.so.0 => /usr/lib/libxcb-shape.so.0 (0x00007f2bffe85000)
	libxcb-xfixes.so.0 => /usr/lib/libxcb-xfixes.so.0 (0x00007f2bff127000)
	libGL.so.1 => /usr/lib/libGL.so.1 (0x00007f2bf4584000)
	libSDL2-2.0.so.0 => /usr/lib/libSDL2-2.0.so.0 (0x00007f2bf43af000)
	libv4l2.so.0 => /usr/lib/libv4l2.so.0 (0x00007f2bf5ed8000)
	libXv.so.1 => /usr/lib/libXv.so.1 (0x00007f2bfe646000)
	libX11.so.6 => /usr/lib/libX11.so.6 (0x00007f2bf4270000)
	libXext.so.6 => /usr/lib/libXext.so.6 (0x00007f2bf425b000)
	libdvdnav.so.4 => /usr/lib/libdvdnav.so.4 (0x00007f2bf4244000)
	libdvdread.so.8 => /usr/lib/libdvdread.so.8 (0x00007f2bf4223000)
	libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00007f2bf40d3000)
	libbz2.so.1.0 => /usr/lib/libbz2.so.1.0 (0x00007f2bf40c0000)
	libmodplug.so.1 => /usr/lib/libmodplug.so.1 (0x00007f2bf3f32000)
	libopenmpt.so.0 => /usr/lib/libopenmpt.so.0 (0x00007f2bf3d43000)
	libvapoursynth-script.so.0 => /usr/lib/libvapoursynth-script.so.0 (0x00007f2bf5ed0000)
	libbluray.so.2 => /usr/lib/libbluray.so.2 (0x00007f2bf3ce6000)
	libsrt.so.1.5 => /usr/lib/libsrt.so.1.5 (0x00007f2bf3c14000)
	libssh.so.4 => /usr/lib/libssh.so.4 (0x00007f2bf3ba7000)
	libsoxr.so.0 => /usr/lib/libsoxr.so.0 (0x00007f2bf3b44000)
	libva-drm.so.2 => /usr/lib/libva-drm.so.2 (0x00007f2bf5ecb000)
	libva-x11.so.2 => /usr/lib/libva-x11.so.2 (0x00007f2bf3b3d000)
	libvdpau.so.1 => /usr/lib/libvdpau.so.1 (0x00007f2bf3b38000)
	libpulsecommon-17.0.so => /usr/lib/pulseaudio/libpulsecommon-17.0.so (0x00007f2bf3ab2000)
	libdbus-1.so.3 => /usr/lib/libdbus-1.so.3 (0x00007f2bf3a61000)
	libdb-5.3.so => /usr/lib/libdb-5.3.so (0x00007f2bf389e000)
	libcap.so.2 => /usr/lib/libcap.so.2 (0x00007f2bf3892000)
	libacl.so.1 => /usr/lib/libacl.so.1 (0x00007f2bf3889000)
	libzstd.so.1 => /usr/lib/libzstd.so.1 (0x00007f2bf37ab000)
	liblz4.so.1 => /usr/lib/liblz4.so.1 (0x00007f2bf3786000)
	libffi.so.8 => /usr/lib/libffi.so.8 (0x00007f2bf377b000)
	libcairo-gobject.so.2 => /usr/lib/libcairo-gobject.so.2 (0x00007f2bf3772000)
	libgdk_pixbuf-2.0.so.0 => /usr/lib/libgdk_pixbuf-2.0.so.0 (0x00007f2bf372d000)
	libgio-2.0.so.0 => /usr/lib/libgio-2.0.so.0 (0x00007f2bf355c000)
	libpangocairo-1.0.so.0 => /usr/lib/libpangocairo-1.0.so.0 (0x00007f2bf354d000)
	libpango-1.0.so.0 => /usr/lib/libpango-1.0.so.0 (0x00007f2bf34e4000)
	libpng16.so.16 => /usr/lib/libpng16.so.16 (0x00007f2bf34aa000)
	libXrender.so.1 => /usr/lib/libXrender.so.1 (0x00007f2bf349d000)
	libxcb-render.so.0 => /usr/lib/libxcb-render.so.0 (0x00007f2bf348e000)
	libpixman-1.so.0 => /usr/lib/libpixman-1.so.0 (0x00007f2bf33e4000)
	libjxl_cms.so.0.10 => /usr/lib/libjxl_cms.so.0.10 (0x00007f2bf33ae000)
	libhwy.so.1 => /usr/lib/libhwy.so.1 (0x00007f2bf33a2000)
	libbrotlidec.so.1 => /usr/lib/libbrotlidec.so.1 (0x00007f2bf3393000)
	libbrotlienc
## Considering Other Protocols

- *Matrix*: Strongest contender. Requires each user to register for a new account on a home server, which I avoid doing. Also, [This message cannot be decrypted.]
- *BitMessage*: [It is written in Python.](https://github.com/Bitmessage/PyBitmessage) How can i possibly integrate this?
- *Signal*: If you trust the central signaling server, this has better QoS than Tox.
- *ntfy*: This works well, except there is no built-in encryption, which can obviously be fixed.
- *Veilid*: A Rust library. I don't understand its appeal.
=> /usr/lib/libogg.so.0 (0x00007f2bf32d7000)
	libsharpyuv.so.0 => /usr/lib/libsharpyuv.so.0 (0x00007f2bf32ce000)
	libmvec.so.1 => /usr/lib/libmvec.so.1 (0x00007f2bf31d6000)
	libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f2bf31d1000)
	libfftw3.so.3 => /usr/lib/libfftw3.so.3 (0x00007f2bf2e00000)
	libsamplerate.so.0 => /usr/lib/libsamplerate.so.0 (0x00007f2bf3062000)
	libgraphite2.so.3 => /usr/lib/libgraphite2.so.3 (0x00007f2bf303f000)
	libunwind.so.8 => /usr/lib/libunwind.so.8 (0x00007f2bf2de6000)
	libshaderc_shared.so.1 => /usr/lib/libshaderc_shared.so.1 (0x00007f2bf2dc8000)
	libglslang-default-resource-limits.so.14 => /usr/lib/libglslang-default-resource-limits.so.14 (0x00007f2bf3035000)
	libSPIRV.so.14 => /usr/lib/libSPIRV.so.14 (0x00007f2bf2200000)
	libvulkan.so.1 => /usr/lib/libvulkan.so.1 (0x00007f2bf2d46000)
	liblcms2.so.2 => /usr/lib/liblcms2.so.2 (0x00007f2bf2cde000)
	libdovi.so.3 => /usr/lib/libdovi.so.3 (0x00007f2bf2c59000)
	libunibreak.so.6 => /usr/lib/libunibreak.so.6 (0x00007f2bf21de000)
	libgomp.so.1 => /usr/lib/libgomp.so.1 (0x00007f2bf218c000)
	libexpat.so.1 => /usr/lib/libexpat.so.1 (0x00007f2bf2163000)
	libXau.so.6 => /usr/lib/libXau.so.6 (0x00007f2bf302e000)
	libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0x00007f2bf2c51000)
	libGLdispatch.so.0 => /usr/lib/libGLdispatch.so.0 (0x00007f2bf20ab000)
	libGLX.so.0 => /usr/lib/libGLX.so.0 (0x00007f2bf2079000)
	libv4lconvert.so.0 => /usr/lib/libv4lconvert.so.0 (0x00007f2bf2000000)
	libicuuc.so.75 => /usr/lib/libicuuc.so.75 (0x00007f2bf1e06000)
	libmpg123.so.0 => /usr/lib/libmpg123.so.0 (0x00007f2bf1dab000)
	libvorbisfile.so.3 => /usr/lib/libvorbisfile.so.3 (0x00007f2bf2c44000)
	libpython3.12.so.1.0 => /usr/lib/libpython3.12.so.1.0 (0x00007f2bf1600000)
	libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0x00007f2bf2c3c000)
	libX11-xcb.so.1 => /usr/lib/libX11-xcb.so.1 (0x00007f2bf1da6000)
	libxcb-dri3.so.0 => /usr/lib/libxcb-dri3.so.0 (0x00007f2bf1d9f000)
	libsndfile.so.1 => /usr/lib/libsndfile.so.1 (0x00007f2bf1d18000)
	libasyncns.so.0 => /usr/lib/libasyncns.so.0 (0x00007f2bf1d10000)
	libelogind.so.0 => /usr/lib/libelogind.so.0 (0x00007f2bf1c59000)
	libgmodule-2.0.so.0 => /usr/lib/libgmodule-2.0.so.0 (0x00007f2bf1c50000)
	libjpeg.so.8 => /usr/lib/libjpeg.so.8 (0x00007f2bf1564000)
	libtiff.so.6 => /usr/lib/libtiff.so.6 (0x00007f2bf14d8000)
	libmount.so.1 => /usr/lib/libmount.so.1 (0x00007f2bf1488000)
	libpangoft2-1.0.so.0 => /usr/lib/libpangoft2-1.0.so.0 (0x00007f2bf1c34000)
	libthai.so.0 => /usr/lib/libthai.so.0 (0x00007f2bf147d000)
	libbrotlicommon.so.1 => /usr/lib/libbrotlicommon.so.1 (0x00007f2bf145a000)
	libSPIRV-Tools.so => /usr/lib/libSPIRV-Tools.so (0x00007f2bf12e6000)
	libSPIRV-Tools-opt.so => /usr/lib/libSPIRV-Tools-opt.so (0x00007f2bf1000000)
	libicudata.so.75 => /usr/lib/libicudata.so.75 (0x00007f2bef200000)
	libFLAC.so.12 => /usr/lib/libFLAC.so.12 (0x00007f2bf12a0000)
	libjbig.so.2.1 => /usr/lib/libjbig.so.2.1 (0x00007f2bf1293000)
	libblkid.so.1 => /usr/lib/libblkid.so.1 (0x00007f2bf125a000)
	libdatrie.so.1 => /usr/lib/libdatrie.so.1 (0x00007f2bf1251000)Encryption also hell.

… what do I say about this? If I only wanted to send text, I probably don’t want to ship a complete SIP client and audio/video codecs from ffmpeg along with my application. What even is libSPIRV doing in there?

dhtnet depends on PJSIP for TURN/STUN, but like, why? Is this the GNU™ way of doing things? GNUnet also expects whoever is building it to be the package manager. Same with whatever full-source bootstrap they are working on. Full-source bootstrap is cool and all, but like, the Mes compiler is made to only work on Guix OS.

Anyway, I don’t believe that the developers of Jami will clean up the dependency hell any time soon. It’s still an easy-to-use application for the end-user though.

Musings

utox and nheko both show two screens at once after suspend+wake. This is probably a Qt problem.