Merge pull request #1075 from jagerman/dht-blinding

Dht blinding
pull/1081/head
Jeff 5 years ago committed by GitHub
commit c122b460e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -95,7 +95,7 @@ CROSS ?= OFF
SHARED_LIB ?= OFF
# enable generating coverage
COVERAGE ?= OFF
# allow downloading libsodium if >= 1.0.17 not installed
# allow downloading libsodium if >= 1.0.18 not installed
DOWNLOAD_SODIUM ?= OFF
COVERAGE_OUTDIR ?= "$(TMPDIR)/lokinet-coverage"

@ -1,7 +1,7 @@
set(LIBSODIUM_PREFIX ${CMAKE_BINARY_DIR}/libsodium)
set(LIBSODIUM_SRC ${LIBSODIUM_PREFIX}/libsodium-1.0.17)
set(LIBSODIUM_TARBALL ${LIBSODIUM_PREFIX}/libsodium-1.0.17.tar.gz)
set(LIBSODIUM_URL https://github.com/jedisct1/libsodium/releases/download/1.0.17/libsodium-1.0.17.tar.gz)
set(LIBSODIUM_SRC ${LIBSODIUM_PREFIX}/libsodium-1.0.18)
set(LIBSODIUM_TARBALL ${LIBSODIUM_PREFIX}/libsodium-1.0.18.tar.gz)
set(LIBSODIUM_URL https://github.com/jedisct1/libsodium/releases/download/1.0.18-RELEASE/libsodium-1.0.18.tar.gz)
if(SODIUM_TARBALL_URL)
# make a build time override of the tarball url so we can fetch it if the original link goes away
set(LIBSODIUM_URL ${SODIUM_TARBALL_URL})
@ -10,254 +10,19 @@ set(SODIUM_PRETEND_TO_BE_CONFIGURED ON)
file(DOWNLOAD
${LIBSODIUM_URL}
${LIBSODIUM_TARBALL}
EXPECTED_HASH SHA512=7cc9e4f11e656008ce9dff735acea95acbcb91ae4936de4d26f7798093766a77c373e9bd4a7b45b60ef8a11de6c55bc8dcac13bebf8c23c671d0536430501da1
EXPECTED_HASH SHA512=17e8638e46d8f6f7d024fe5559eccf2b8baf23e143fadd472a7d29d228b186d86686a5e6920385fe2020729119a5f12f989c3a782afbd05a8db4819bb18666ef
SHOW_PROGRESS)
execute_process(COMMAND tar -xzf ${LIBSODIUM_TARBALL} -C ${LIBSODIUM_PREFIX})
if(WIN32)
message("patch -p0 -d ${LIBSODIUM_SRC} < ${CMAKE_SOURCE_DIR}/llarp/win32/libsodium-1.0.17-win32.patch")
execute_process(COMMAND "patch -p0 -d ${LIBSODIUM_SRC} < ${CMAKE_SOURCE_DIR}/llarp/win32/libsodium-1.0.17-win32.patch")
message("patch -p0 -d ${LIBSODIUM_SRC} < ${CMAKE_SOURCE_DIR}/llarp/win32/libsodium-1.0.18-win32.patch")
execute_process(COMMAND "patch -p0 -d ${LIBSODIUM_SRC} < ${CMAKE_SOURCE_DIR}/llarp/win32/libsodium-1.0.18-win32.patch")
endif()
add_library(sodium_vendor
${LIBSODIUM_SRC}/src/libsodium/crypto_aead/aes256gcm/aesni/aead_aes256gcm_aesni.c
${LIBSODIUM_SRC}/src/libsodium/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c
${LIBSODIUM_SRC}/src/libsodium/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c
${LIBSODIUM_SRC}/src/libsodium/crypto_auth/crypto_auth.c
${LIBSODIUM_SRC}/src/libsodium/crypto_auth/hmacsha256/auth_hmacsha256.c
${LIBSODIUM_SRC}/src/libsodium/crypto_auth/hmacsha512/auth_hmacsha512.c
${LIBSODIUM_SRC}/src/libsodium/crypto_auth/hmacsha512256/auth_hmacsha512256.c
${LIBSODIUM_SRC}/src/libsodium/crypto_box/crypto_box.c
${LIBSODIUM_SRC}/src/libsodium/crypto_box/crypto_box_easy.c
${LIBSODIUM_SRC}/src/libsodium/crypto_box/crypto_box_seal.c
${LIBSODIUM_SRC}/src/libsodium/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/ref10/ed25519_ref10.c
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/ref10/fe_25_5/base.h
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/ref10/fe_25_5/base2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/ref10/fe_25_5/constants.h
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/ref10/fe_25_5/fe.h
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/ref10/fe_51/base.h
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/ref10/fe_51/base2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/ref10/fe_51/constants.h
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/ref10/fe_51/fe.h
${LIBSODIUM_SRC}/src/libsodium/crypto_core/hchacha20/core_hchacha20.c
${LIBSODIUM_SRC}/src/libsodium/crypto_core/hsalsa20/core_hsalsa20.c
${LIBSODIUM_SRC}/src/libsodium/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c
${LIBSODIUM_SRC}/src/libsodium/crypto_core/salsa/ref/core_salsa_ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/generichash_blake2.c
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-avx2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-sse41.c
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-sse41.h
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.h
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-load-avx2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-load-sse2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-load-sse41.h
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/blake2b-ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/blake2b/ref/generichash_blake2b.c
${LIBSODIUM_SRC}/src/libsodium/crypto_generichash/crypto_generichash.c
${LIBSODIUM_SRC}/src/libsodium/crypto_hash/crypto_hash.c
${LIBSODIUM_SRC}/src/libsodium/crypto_hash/sha256/cp/hash_sha256_cp.c
${LIBSODIUM_SRC}/src/libsodium/crypto_hash/sha256/hash_sha256.c
${LIBSODIUM_SRC}/src/libsodium/crypto_hash/sha512/cp/hash_sha512_cp.c
${LIBSODIUM_SRC}/src/libsodium/crypto_hash/sha512/hash_sha512.c
${LIBSODIUM_SRC}/src/libsodium/crypto_kdf/blake2b/kdf_blake2b.c
${LIBSODIUM_SRC}/src/libsodium/crypto_kdf/crypto_kdf.c
${LIBSODIUM_SRC}/src/libsodium/crypto_kx/crypto_kx.c
${LIBSODIUM_SRC}/src/libsodium/crypto_onetimeauth/crypto_onetimeauth.c
${LIBSODIUM_SRC}/src/libsodium/crypto_onetimeauth/poly1305/donna/poly1305_donna.c
${LIBSODIUM_SRC}/src/libsodium/crypto_onetimeauth/poly1305/donna/poly1305_donna.h
${LIBSODIUM_SRC}/src/libsodium/crypto_onetimeauth/poly1305/donna/poly1305_donna32.h
${LIBSODIUM_SRC}/src/libsodium/crypto_onetimeauth/poly1305/donna/poly1305_donna64.h
${LIBSODIUM_SRC}/src/libsodium/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c
${LIBSODIUM_SRC}/src/libsodium/crypto_onetimeauth/poly1305/onetimeauth_poly1305.h
${LIBSODIUM_SRC}/src/libsodium/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.c
${LIBSODIUM_SRC}/src/libsodium/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2-core.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2-core.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2-encoding.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2-encoding.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2-fill-block-avx2.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2-fill-block-avx512f.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2-fill-block-ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2-fill-block-ssse3.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/argon2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/blake2b-long.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/blake2b-long.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/blamka-round-avx2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/blamka-round-avx512f.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/blamka-round-ref.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/blamka-round-ssse3.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/pwhash_argon2i.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/argon2/pwhash_argon2id.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/crypto_pwhash.c
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/crypto_scalarmult.c
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/consts_namespace.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/fe.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/fe51.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/fe51_namespace.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/ladder.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/ladder_base.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/ladder_base_namespace.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/sandy2x/ladder_namespace.h
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/scalarmult_curve25519.c
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/curve25519/scalarmult_curve25519.h
${LIBSODIUM_SRC}/src/libsodium/crypto_secretbox/crypto_secretbox.c
${LIBSODIUM_SRC}/src/libsodium/crypto_secretbox/crypto_secretbox_easy.c
${LIBSODIUM_SRC}/src/libsodium/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c
${LIBSODIUM_SRC}/src/libsodium/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c
${LIBSODIUM_SRC}/src/libsodium/crypto_shorthash/crypto_shorthash.c
${LIBSODIUM_SRC}/src/libsodium/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_shorthash/siphash24/ref/shorthash_siphash_ref.h
${LIBSODIUM_SRC}/src/libsodium/crypto_shorthash/siphash24/shorthash_siphash24.c
${LIBSODIUM_SRC}/src/libsodium/crypto_sign/crypto_sign.c
${LIBSODIUM_SRC}/src/libsodium/crypto_sign/ed25519/ref10/keypair.c
${LIBSODIUM_SRC}/src/libsodium/crypto_sign/ed25519/ref10/open.c
${LIBSODIUM_SRC}/src/libsodium/crypto_sign/ed25519/ref10/sign.c
${LIBSODIUM_SRC}/src/libsodium/crypto_sign/ed25519/ref10/sign_ed25519_ref10.h
${LIBSODIUM_SRC}/src/libsodium/crypto_sign/ed25519/sign_ed25519.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/dolbeau/u0.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/dolbeau/u1.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/dolbeau/u4.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/dolbeau/u8.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/ref/chacha20_ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/ref/chacha20_ref.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/stream_chacha20.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/chacha20/stream_chacha20.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/crypto_stream.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/ref/salsa20_ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/ref/salsa20_ref.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/stream_salsa20.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/stream_salsa20.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6/salsa20_xmm6.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6/salsa20_xmm6.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6int/u0.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6int/u1.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6int/u4.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa20/xmm6int/u8.h
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/xsalsa20/stream_xsalsa20.c
${LIBSODIUM_SRC}/src/libsodium/crypto_verify/sodium/verify.c
${LIBSODIUM_SRC}/src/libsodium/include/sodium.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/core.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_aead_aes256gcm.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_aead_chacha20poly1305.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_aead_xchacha20poly1305.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_auth.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_auth_hmacsha256.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_auth_hmacsha512.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_auth_hmacsha512256.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_box.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_box_curve25519xchacha20poly1305.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_box_curve25519xsalsa20poly1305.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_core_ed25519.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_core_hchacha20.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_core_hsalsa20.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_core_salsa20.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_core_salsa2012.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_core_salsa208.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_generichash.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_generichash_blake2b.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_hash.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_hash_sha256.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_hash_sha512.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_kdf.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_kdf_blake2b.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_kx.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_onetimeauth.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_onetimeauth_poly1305.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_pwhash.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_pwhash_argon2i.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_pwhash_argon2id.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_pwhash_scryptsalsa208sha256.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_scalarmult.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_scalarmult_curve25519.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_scalarmult_ed25519.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_secretbox.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_secretbox_xchacha20poly1305.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_secretbox_xsalsa20poly1305.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_secretstream_xchacha20poly1305.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_shorthash.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_shorthash_siphash24.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_sign.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_sign_ed25519.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_sign_edwards25519sha512batch.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_stream.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_stream_chacha20.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_stream_salsa20.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_stream_salsa2012.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_stream_salsa208.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_stream_xchacha20.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_stream_xsalsa20.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_verify_16.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_verify_32.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/crypto_verify_64.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/export.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/private/chacha20_ietf_ext.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/private/common.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/private/ed25519_ref10.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/private/ed25519_ref10_fe_25_5.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/private/ed25519_ref10_fe_51.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/private/implementations.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/private/mutex.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/private/sse2_64_32.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/randombytes.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/randombytes_nativeclient.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/randombytes_salsa20_random.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/randombytes_sysrandom.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/runtime.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/utils.h
${LIBSODIUM_SRC}/src/libsodium/include/sodium/version.h
${LIBSODIUM_SRC}/src/libsodium/randombytes/nativeclient/randombytes_nativeclient.c
${LIBSODIUM_SRC}/src/libsodium/randombytes/randombytes.c
${LIBSODIUM_SRC}/src/libsodium/randombytes/salsa20/randombytes_salsa20_random.c
${LIBSODIUM_SRC}/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c
${LIBSODIUM_SRC}/src/libsodium/sodium/codecs.c
${LIBSODIUM_SRC}/src/libsodium/sodium/core.c
${LIBSODIUM_SRC}/src/libsodium/sodium/runtime.c
${LIBSODIUM_SRC}/src/libsodium/sodium/utils.c
${LIBSODIUM_SRC}/src/libsodium/sodium/version.c
)
target_sources(sodium_vendor
PRIVATE
${LIBSODIUM_SRC}/src/libsodium/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c
${LIBSODIUM_SRC}/src/libsodium/crypto_box/curve25519xchacha20poly1305/box_seal_curve25519xchacha20poly1305.c
${LIBSODIUM_SRC}/src/libsodium/crypto_core/ed25519/core_ed25519.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.h
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c
${LIBSODIUM_SRC}/src/libsodium/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c
${LIBSODIUM_SRC}/src/libsodium/crypto_scalarmult/ed25519/ref10/scalarmult_ed25519_ref10.c
${LIBSODIUM_SRC}/src/libsodium/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c
${LIBSODIUM_SRC}/src/libsodium/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_shorthash/siphash24/shorthash_siphashx24.c
${LIBSODIUM_SRC}/src/libsodium/crypto_sign/ed25519/ref10/obsolete.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa2012/stream_salsa2012.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa208/ref/stream_salsa208_ref.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/salsa208/stream_salsa208.c
${LIBSODIUM_SRC}/src/libsodium/crypto_stream/xchacha20/stream_xchacha20.c
)
file(GLOB_RECURSE sodium_sources
${LIBSODIUM_SRC}/src/libsodium/*.c
${LIBSODIUM_SRC}/src/libsodium/*.h
)
add_library(sodium_vendor ${sodium_sources})
set_target_properties(sodium_vendor
PROPERTIES
@ -284,13 +49,15 @@ target_compile_definitions(sodium_vendor
# Variables that need to be exported to version.h.in
set(VERSION_ORIG "${VERSION}") # an included module sets things in the calling scope :(
set(VERSION 1.0.17)
set(VERSION 1.0.18)
set(SODIUM_LIBRARY_VERSION_MAJOR 10)
set(SODIUM_LIBRARY_VERSION_MINOR 2)
set(SODIUM_LIBRARY_VERSION_MINOR 3)
configure_file(
${LIBSODIUM_SRC}/src/libsodium/include/sodium/version.h.in
${LIBSODIUM_SRC}/src/libsodium/include/sodium/version.h
)
target_sources(sodium_vendor PRIVATE ${LIBSODIUM_SRC}/src/libsodium/include/sodium/version.h)
set(VERSION "${VERSION_ORIG}")

@ -66,19 +66,19 @@ target_link_libraries(${CRYPTOGRAPHY_LIB} PRIVATE cryptography_avx_lib)
option(DOWNLOAD_SODIUM "Allow libsodium to be downloaded and built locally if not found on the system" OFF)
find_package(Sodium 1.0.17)
find_package(Sodium 1.0.18)
if(sodium_FOUND)
target_include_directories(${CRYPTOGRAPHY_LIB} PUBLIC ${sodium_INCLUDE_DIR})
target_include_directories(cryptography_avx_lib PUBLIC ${sodium_INCLUDE_DIR})
target_link_libraries(${CRYPTOGRAPHY_LIB} PUBLIC ${sodium_LIBRARY_RELEASE})
elseif(DOWNLOAD_SODIUM)
message(STATUS "Sodium >= 1.0.17 not found, but DOWNLOAD_SODIUM specified, so downloading it")
message(STATUS "Sodium >= 1.0.18 not found, but DOWNLOAD_SODIUM specified, so downloading it")
include(DownloadLibSodium)
target_link_libraries(${CRYPTOGRAPHY_LIB} PUBLIC sodium_vendor)
target_link_libraries(cryptography_avx_lib PUBLIC sodium_vendor)
else()
message(FATAL_ERROR "Could not find libsodium >= 1.0.17; either install it on your system or use -DDOWNLOAD_SODIUM=ON to download and build an internal copy")
message(FATAL_ERROR "Could not find libsodium >= 1.0.18; either install it on your system or use -DDOWNLOAD_SODIUM=ON to download and build an internal copy")
endif()
target_include_directories(${CRYPTOGRAPHY_LIB} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/libntrup/include")

@ -42,8 +42,8 @@ else()
target_link_directories(${EXE} PRIVATE /usr/local/lib)
target_link_directories(${CTL} PRIVATE /usr/local/lib)
endif()
target_link_libraries(${EXE} PUBLIC ${EXE_LIBS} ${LIBS})
target_link_libraries(${CTL} PUBLIC ${EXE_LIBS} ${LIBS})
target_link_libraries(${EXE} PUBLIC ${EXE_LIBS} ${LIBS} ${CRYPTOGRAPHY_LIB})
target_link_libraries(${CTL} PUBLIC ${EXE_LIBS} ${LIBS} ${CRYPTOGRAPHY_LIB})
if(CURL_FOUND)
target_include_directories(${CTL} PRIVATE ${CURL_INCLUDE_DIRS})

@ -0,0 +1,94 @@
llarp's dht is a recusrive kademlia dht with optional request proxying via paths for requester anonymization.
dht is separated into 2 different networks, one for router contacts, one for introsets.
format for consesus propagation messages:
keys: A, H, K, N, O, T, U, V
concensus request messages
requester requests current table hash, H,N,O is set to zeros if not known
C -> S
{
A: "C",
H: "<32 byte last hash of consensus table>",
N: uint64_number_of_entries_to_request,
O: uint64_offset_in_table,
T: uint64_txid,
V: []
}
when H or N is set to zero from the requester, they are requesting the current consensus table's hash
consensus response message is as follows for a zero H or N value
S -> C
{
A: "C",
H: "<32 byte hash of current consensus table>",
N: uint64_number_of_entries_in_table,
T: uint64_txid,
U: uint64_ms_next_update_required,
V: [proto, major, minor, patch]
}
requester requests a part of the current table for hash H
N must be less than or equal to 512
C -> S
{
A: "C",
H: "<32 bytes current consensus table hash>",
N: 256,
O: 512,
T: uint64_txid,
V: []
}
consensus response message for routers 512 to 512 + 256
S -> C
{
A: "C",
H: "<32 bytes current concensus table hash>",
K: [list, of, N, pubkeys, from, request, starting, at, position, O],
T: uint64_txid,
V: [proto, major, minor, patch]
}
consensus table is a concatination of all public keys in lexigraphical order.
the hash function in use is 256 bit blake2
gossip RC message
broadcast style RC publish message. sent to all peers infrequently.
it is really an unwarrented GRCM, propagate to all peers.
{
A: "S",
R: [RC],
T: 0,
V: proto
}
replays are dropped using a decaying hashset or decaying bloom filter.
the introset dht has 3 message: GetIntroSet Message (GIM), PutIntroSet Message (PIM), FoundIntroSet Message (FIM)

@ -132,7 +132,12 @@ set(DNSLIB_SRC
dns/string.cpp
)
set(CONSENSUS_SRC
consensus/table.cpp
)
set(LIB_SRC
${CONSENSUS_SRC}
${DNSLIB_SRC}
bootstrap.cpp
context.cpp
@ -214,6 +219,7 @@ set(LIB_SRC
router/router.cpp
router_contact.cpp
router_id.cpp
router_version.cpp
routing/dht_message.cpp
routing/handler.cpp
routing/message_parser.cpp

@ -0,0 +1,17 @@
#include <consensus/table.hpp>
#include <crypto/crypto.hpp>
namespace llarp
{
namespace consensus
{
ShortHash
Table::CalculateHash() const
{
ShortHash h;
const llarp_buffer_t buf(begin()->data(), size());
CryptoManager::instance()->shorthash(h, buf);
return h;
}
} // namespace consensus
} // namespace llarp

@ -0,0 +1,20 @@
#ifndef LLARP_CONSENSUS_TABLE_HPP
#define LLARP_CONSENSUS_TABLE_HPP
#include <crypto/types.hpp>
#include <vector>
namespace llarp
{
namespace consensus
{
/// consensus table
struct Table : public std::vector< RouterID >
{
ShortHash
CalculateHash() const;
};
} // namespace consensus
} // namespace llarp
#endif

@ -1,6 +1,8 @@
#include <constants/version.hpp>
#include <constants/version.h>
#include <constants/proto.hpp>
// clang-format off
#define LLARP_STRINGIFY2(val) #val
#define LLARP_STRINGIFY(val) LLARP_STRINGIFY2(val)
@ -10,6 +12,7 @@
namespace llarp
{
const std::array<uint16_t, 3> VERSION{{LLARP_VERSION_MAJ, LLARP_VERSION_MIN, LLARP_VERSION_PATCH}};
const std::array<uint64_t, 4> ROUTER_VERSION{{LLARP_PROTO_VERSION, LLARP_VERSION_MAJ, LLARP_VERSION_MIN, LLARP_VERSION_PATCH}};
const char* const VERSION_STR = LLARP_VERSION_STR;
const char* const VERSION_TAG = "@VERSIONTAG@";
const char* const VERSION_FULL = LLARP_NAME "-" LLARP_VERSION_STR "-@VERSIONTAG@";

@ -7,8 +7,8 @@
#define LLARP_NAME "lokinet"
#define LLARP_VERSION_MAJ 0
#define LLARP_VERSION_MIN 6
#define LLARP_VERSION_PATCH 4
#define LLARP_VERSION_MIN 7
#define LLARP_VERSION_PATCH 0
#define LLARP_DEFAULT_NETID "lokinet"

@ -6,10 +6,11 @@
namespace llarp
{
// Given a full lokinet version of: lokinet-1.2.3-abc these are:
extern const std::array< uint16_t, 3 > VERSION; // [1, 2, 3]
extern const char* const VERSION_STR; // "1.2.3"
extern const char* const VERSION_TAG; // "abc"
extern const char* const VERSION_FULL; // "lokinet-1.2.3-abc"
extern const std::array< uint16_t, 3 > VERSION; // [1, 2, 3]
extern const std::array< uint64_t, 4 > ROUTER_VERSION; // [proto, 1, 2, 3]
extern const char* const VERSION_STR; // "1.2.3"
extern const char* const VERSION_TAG; // "abc"
extern const char* const VERSION_FULL; // "lokinet-1.2.3-abc"
extern const char* const RELEASE_MOTTO;
extern const char* const DEFAULT_NETID;

@ -54,15 +54,29 @@ namespace llarp
/// blake2b 256 bit
virtual bool
shorthash(ShortHash &, const llarp_buffer_t &) = 0;
/// blake2s 256 bit hmac
/// blake2s 256 bit "hmac" (keyed hash)
virtual bool
hmac(byte_t *, const llarp_buffer_t &, const SharedSecret &) = 0;
/// ed25519 sign
virtual bool
sign(Signature &, const SecretKey &, const llarp_buffer_t &) = 0;
/// ed25519 sign (custom with derived keys)
virtual bool
sign(Signature &, const PrivateKey &, const llarp_buffer_t &) = 0;
/// ed25519 verify
virtual bool
verify(const PubKey &, const llarp_buffer_t &, const Signature &) = 0;
/// derive sub keys for public keys
virtual bool
derive_subkey(PubKey &, const PubKey &, uint64_t,
const AlignedBuffer< 32 > * = nullptr) = 0;
/// derive sub keys for private keys
virtual bool
derive_subkey_private(PrivateKey &, const SecretKey &, uint64_t,
const AlignedBuffer< 32 > * = nullptr) = 0;
/// seed to secretkey
virtual bool
seed_to_secretkey(llarp::SecretKey &, const llarp::IdentitySecret &) = 0;

@ -2,10 +2,15 @@
#include <sodium/crypto_generichash.h>
#include <sodium/crypto_sign.h>
#include <sodium/crypto_scalarmult.h>
#include <sodium/crypto_scalarmult_ed25519.h>
#include <sodium/crypto_stream_xchacha20.h>
#include <sodium/crypto_core_ed25519.h>
#include <sodium/randombytes.h>
#include <sodium/utils.h>
#include <util/mem.hpp>
#include <util/endian.hpp>
#include <cassert>
#include <cstring>
extern "C"
{
@ -171,6 +176,51 @@ namespace llarp
!= -1;
}
bool
CryptoLibSodium::sign(Signature &sig, const PrivateKey &privkey,
const llarp_buffer_t &buf)
{
PubKey pubkey;
privkey.toPublic(pubkey);
crypto_hash_sha512_state hs;
unsigned char nonce[64];
unsigned char hram[64];
unsigned char mulres[32];
// r = H(s || M) where here s is pseudorandom bytes typically generated as
// part of hashing the seed (i.e. [a,s] = H(k)), but for derived
// PrivateKeys will come from a hash of the root key's s concatenated with
// the derivation hash.
crypto_hash_sha512_init(&hs);
crypto_hash_sha512_update(&hs, privkey.signingHash(), 32);
crypto_hash_sha512_update(&hs, buf.base, buf.sz);
crypto_hash_sha512_final(&hs, nonce);
crypto_core_ed25519_scalar_reduce(nonce, nonce);
// copy pubkey into sig to make (for now) sig = (R || A)
memmove(sig.data() + 32, pubkey.data(), 32);
// R = r * B
crypto_scalarmult_ed25519_base_noclamp(sig.data(), nonce);
// hram = H(R || A || M)
crypto_hash_sha512_init(&hs);
crypto_hash_sha512_update(&hs, sig.data(), 64);
crypto_hash_sha512_update(&hs, buf.base, buf.sz);
crypto_hash_sha512_final(&hs, hram);
// S = r + H(R || A || M) * s, so sig = (R || S)
crypto_core_ed25519_scalar_reduce(hram, hram);
crypto_core_ed25519_scalar_mul(mulres, hram, privkey.data());
crypto_core_ed25519_scalar_add(sig.data() + 32, mulres, nonce);
sodium_memzero(nonce, sizeof nonce);
return true;
}
bool
CryptoLibSodium::verify(const PubKey &pub, const llarp_buffer_t &buf,
const Signature &sig)
@ -180,16 +230,154 @@ namespace llarp
!= -1;
}
/// clamp a 32 byte ec point
static void
clamp_ed25519(byte_t *out)
{
out[0] &= 248;
out[31] &= 127;
out[31] |= 64;
}
template < typename K >
static K
clamp(const K &p)
{
K out = p;
clamp_ed25519(out);
return out;
}
template < typename K >
static bool
is_clamped(const K &key)
{
K other(key);
clamp_ed25519(other.data());
return other == key;
}
constexpr static char derived_key_hash_str[161] =
"just imagine what would happen if we all decided to understand. you "
"can't in the and by be or then before so just face it this text hurts "
"to read? lokinet yolo!";
template < typename K >
static bool make_scalar(AlignedBuffer< 32 > &out, const K &k, uint64_t i)
{
// b = BLIND-STRING || k || i
std::array< byte_t, 160 + K::SIZE + sizeof(uint64_t) > buf;
std::copy(derived_key_hash_str, derived_key_hash_str + 160, buf.begin());
std::copy(k.begin(), k.end(), buf.begin() + 160);
htole64buf(buf.data() + 160 + K::SIZE, i);
// n = H(b)
// h = make_point(n)
ShortHash n;
return -1
!= crypto_generichash_blake2b(n.data(), ShortHash::SIZE, buf.data(),
buf.size(), nullptr, 0)
&& -1 != crypto_core_ed25519_from_uniform(out.data(), n.data());
}
static AlignedBuffer< 32 > zero;
bool
CryptoLibSodium::derive_subkey(PubKey &out_pubkey,
const PubKey &root_pubkey, uint64_t key_n,
const AlignedBuffer< 32 > *hash)
{
// scalar h = H( BLIND-STRING || root_pubkey || key_n )
AlignedBuffer< 32 > h;
if(hash)
h = *hash;
else if(not make_scalar(h, root_pubkey, key_n))
{
LogError("cannot make scalar");
return false;
}
return 0
== crypto_scalarmult_ed25519(out_pubkey.data(), h.data(),
root_pubkey.data());
}
bool
CryptoLibSodium::derive_subkey_private(PrivateKey &out_key,
const SecretKey &root_key,
uint64_t key_n,
const AlignedBuffer< 32 > *hash)
{
// Derives a private subkey from a root key.
//
// The basic idea is:
//
// h = H( BLIND-STRING || A || key_n )
// a - private key
// A = aB - public key
// s - signing hash
// a' = ah - derived private key
// A' = a'B = (ah)B - derived public key
// s' = H(h || s) - derived signing hash
//
// libsodium throws some wrenches in the mechanics which are a nuisance,
// the biggest of which is that sodium's secret key is *not* `a`; rather
// it is the seed. If you want to get the private key (i.e. "a"), you
// need to SHA-512 hash it and then clamp that.
//
// This also makes signature verification harder: we can't just use
// sodium's sign function because it wants to be given the seed rather
// than the private key, and moreover we can't actually *get* the seed to
// make libsodium happy because we only have `ah` above; thus we
// reimplemented most of sodium's detached signing function but without
// the hash step.
//
// Lastly, for the signing hash s', we need some value that is both
// different from the root s but also unknowable from the public key
// (since otherwise `r` in the signing function would be known), so we
// generate it from a hash of `h` and the root key's (psuedorandom)
// signing hash, `s`.
//
const auto root_pubkey = root_key.toPublic();
AlignedBuffer< 32 > h;
if(hash)
h = *hash;
else if(not make_scalar(h, root_pubkey, key_n))
{
LogError("cannot make scalar");
return false;
}
h[0] &= 248;
h[31] &= 63;
h[31] |= 64;
PrivateKey a;
if(!root_key.toPrivate(a))
return false;
// a' = ha
crypto_core_ed25519_scalar_mul(out_key.data(), h.data(), a.data());
// s' = H(h || s)
std::array< byte_t, 64 > buf;
std::copy(h.begin(), h.end(), buf.begin());
std::copy(a.signingHash(), a.signingHash() + 32, buf.begin() + 32);
return -1
!= crypto_generichash_blake2b(out_key.signingHash(), 32, buf.data(),
buf.size(), nullptr, 0);
return true;
}
bool
CryptoLibSodium::seed_to_secretkey(llarp::SecretKey &secret,
const llarp::IdentitySecret &seed)
{
PubKey pk;
return crypto_sign_ed25519_seed_keypair(pk.data(), secret.data(),
return crypto_sign_ed25519_seed_keypair(secret.data() + 32, secret.data(),
seed.data())
!= -1;
}
void
CryptoLibSodium::randomize(const llarp_buffer_t &buff)
{
@ -212,6 +400,8 @@ namespace llarp
assert(pk == sk_pk);
(void)result;
(void)sk_pk;
// encryption_keygen(keys);
}
bool

@ -48,11 +48,27 @@ namespace llarp
/// ed25519 sign
bool
sign(Signature &, const SecretKey &, const llarp_buffer_t &) override;
/// ed25519 sign (custom with derived keys)
bool
sign(Signature &, const PrivateKey &, const llarp_buffer_t &) override;
/// ed25519 verify
bool
verify(const PubKey &, const llarp_buffer_t &,
const Signature &) override;
/// derive sub keys for public keys. hash is really only intended for
/// testing and overrides key_n if given.
bool
derive_subkey(PubKey &derived, const PubKey &root, uint64_t key_n,
const AlignedBuffer< 32 > *hash = nullptr) override;
/// derive sub keys for private keys. hash is really only intended for
/// testing and overrides key_n if given.
bool
derive_subkey_private(PrivateKey &derived, const SecretKey &root,
uint64_t key_n,
const AlignedBuffer< 32 > *hash = nullptr) override;
/// seed to secretkey
bool
seed_to_secretkey(llarp::SecretKey &,

@ -106,10 +106,16 @@ namespace llarp
}
bool
sign(Signature &sig, const SecretKey &key, const llarp_buffer_t &) override
sign(Signature &sig, const SecretKey &, const llarp_buffer_t &) override
{
static_assert(Signature::SIZE == SecretKey::SIZE, "");
std::copy(key.begin(), key.end(), sig.begin());
std::fill(sig.begin(), sig.end(), 0);
return true;
}
bool
sign(Signature &sig, const PrivateKey &, const llarp_buffer_t &) override
{
std::fill(sig.begin(), sig.end(), 0);
return true;
}

@ -7,6 +7,10 @@
#include <iterator>
#include <sodium/crypto_sign.h>
#include <sodium/crypto_sign_ed25519.h>
#include <sodium/crypto_scalarmult_ed25519.h>
namespace llarp
{
bool
@ -51,6 +55,39 @@ namespace llarp
return BDecode(&buf);
}
bool
SecretKey::Recalculate()
{
PrivateKey key;
PubKey pubkey;
if(!toPrivate(key) || !key.toPublic(pubkey))
return false;
std::memcpy(data() + 32, pubkey.data(), 32);
return true;
}
bool
SecretKey::toPrivate(PrivateKey& key) const
{
// Ed25519 calculates a 512-bit hash from the seed; the first half (clamped)
// is the private key; the second half is the hash that gets used in
// signing.
unsigned char h[crypto_hash_sha512_BYTES];
if(crypto_hash_sha512(h, data(), 32) < 0)
return false;
h[0] &= 248;
h[31] &= 63;
h[31] |= 64;
std::memcpy(key.data(), h, 64);
return true;
}
bool
PrivateKey::toPublic(PubKey& pubkey) const
{
return crypto_scalarmult_ed25519_base_noclamp(pubkey.data(), data()) != -1;
}
bool
SecretKey::SaveToFile(const char* fname) const
{
@ -94,25 +131,25 @@ namespace llarp
}
byte_t*
Signature::R()
Signature::Lo()
{
return data();
}
const byte_t*
Signature::R() const
Signature::Lo() const
{
return data();
}
byte_t*
Signature::C()
Signature::Hi()
{
return data() + 32;
}
const byte_t*
Signature::C() const
Signature::Hi() const
{
return data() + 32;
}

@ -16,9 +16,7 @@ namespace llarp
struct PubKey final : public AlignedBuffer< PUBKEYSIZE >
{
PubKey() : AlignedBuffer< SIZE >()
{
}
PubKey() = default;
explicit PubKey(const byte_t *ptr) : AlignedBuffer< SIZE >(ptr)
{
@ -76,16 +74,36 @@ namespace llarp
return lhs.as_array() == rhs.as_array();
}
struct PrivateKey;
/// Stores a sodium "secret key" value, which is actually the seed
/// concatenated with the public key. Note that the seed is *not* the private
/// key value itself, but rather the seed from which it can be calculated.
struct SecretKey final : public AlignedBuffer< SECKEYSIZE >
{
SecretKey() : AlignedBuffer< SECKEYSIZE >()
SecretKey() = default;
explicit SecretKey(const byte_t *ptr) : AlignedBuffer< SECKEYSIZE >(ptr)
{
}
explicit SecretKey(const byte_t *ptr) : AlignedBuffer< SECKEYSIZE >(ptr)
// The full data
explicit SecretKey(const AlignedBuffer< SECKEYSIZE > &seed)
: AlignedBuffer< SECKEYSIZE >(seed)
{
}
// Just the seed, we recalculate the pubkey
explicit SecretKey(const AlignedBuffer< 32 > &seed)
{
std::copy(seed.begin(), seed.end(), begin());
Recalculate();
}
/// recalculate public component
bool
Recalculate();
std::ostream &
print(std::ostream &stream, int level, int spaces) const
{
@ -100,6 +118,11 @@ namespace llarp
return PubKey(data() + 32);
}
/// Computes the private key from the secret key (which is actually the
/// seed)
bool
toPrivate(PrivateKey &key) const;
bool
LoadFromFile(const char *fname);
@ -115,6 +138,61 @@ namespace llarp
return out << "[secretkey]";
}
/// PrivateKey is similar to SecretKey except that it only stores the private
/// key value and a hash, unlike SecretKey which stores the seed from which
/// the private key and hash value are generated. This is primarily intended
/// for use with derived keys, where we can derive the private key but not the
/// seed.
struct PrivateKey final : public AlignedBuffer< 64 >
{
PrivateKey() = default;
explicit PrivateKey(const byte_t *ptr) : AlignedBuffer< 64 >(ptr)
{
}
explicit PrivateKey(const AlignedBuffer< 64 > &key_and_hash)
: AlignedBuffer< 64 >(key_and_hash)
{
}
/// Returns a pointer to the beginning of the 32-byte hash which is used for
/// pseudorandomness when signing with this private key.
const byte_t *
signingHash() const
{
return data() + 32;
}
/// Returns a pointer to the beginning of the 32-byte hash which is used for
/// pseudorandomness when signing with this private key.
byte_t *
signingHash()
{
return data() + 32;
}
std::ostream &
print(std::ostream &stream, int level, int spaces) const
{
Printer printer(stream, level, spaces);
printer.printValue("privatekey");
return stream;
}
/// Computes the public key
bool
toPublic(PubKey &pubkey) const;
};
inline std::ostream &
operator<<(std::ostream &out, const PrivateKey &)
{
// return out << k.ToHex();
// make sure we never print out private keys
return out << "[privatekey]";
}
/// IdentitySecret is a secret key from a service node secret seed
struct IdentitySecret final : public AlignedBuffer< 32 >
{
@ -145,16 +223,16 @@ namespace llarp
struct Signature final : public AlignedBuffer< SIGSIZE >
{
byte_t *
R();
Hi();
const byte_t *
R() const;
Hi() const;
byte_t *
C();
Lo();
const byte_t *
C() const;
Lo() const;
};
using TunnelNonce = AlignedBuffer< TUNNONCESIZE >;

@ -208,6 +208,16 @@ namespace llarp
}
}
template < typename Visit_t >
void
ForEachNode(Visit_t visit)
{
for(const auto& item : nodes)
{
visit(item.second);
}
}
void
Clear()
{

@ -21,6 +21,7 @@
#include <nodedb.hpp>
#include <profiling.hpp>
#include <router/i_rc_lookup_handler.hpp>
#include <util/decaying_hashset.hpp>
#include <vector>
namespace llarp
@ -48,15 +49,15 @@ namespace llarp
/// key askpeer
void
LookupIntroSetRecursive(
const service::Address& target, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer, uint64_t R,
service::IntroSetLookupHandler result = nullptr) override;
const Key_t& target, const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer, uint64_t R,
service::EncryptedIntroSetLookupHandler result = nullptr) override;
void
LookupIntroSetIterative(
const service::Address& target, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
service::IntroSetLookupHandler result = nullptr) override;
const Key_t& target, const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer,
service::EncryptedIntroSetLookupHandler result = nullptr) override;
/// on behalf of whoasked request router with public key target from dht
/// router with key askpeer
@ -83,19 +84,6 @@ namespace llarp
return pendingRouterLookups().HasLookupFor(target);
}
/// on behalf of whoasked request introsets with tag from dht router with
/// key askpeer with Recursion depth R
void
LookupTagRecursive(const service::Tag& tag, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
uint64_t R) override;
/// issue dht lookup for tag via askpeer and send reply to local path
void
LookupTagForPath(const service::Tag& tag, uint64_t txid,
const llarp::PathID_t& path,
const Key_t& askpeer) override;
/// issue dht lookup for router via askpeer and send reply to local path
void
LookupRouterForPath(const RouterID& target, uint64_t txid,
@ -104,7 +92,7 @@ namespace llarp
/// issue dht lookup for introset for addr via askpeer and send reply to
/// local path
void
LookupIntroSetForPath(const service::Address& addr, uint64_t txid,
LookupIntroSetForPath(const Key_t& addr, uint64_t txid,
const llarp::PathID_t& path, const Key_t& askpeer,
uint64_t R) override;
@ -120,11 +108,6 @@ namespace llarp
const Key_t& requester, uint64_t txid, const RouterID& target,
std::vector< std::unique_ptr< IMessage > >& reply) override;
std::set< service::IntroSet >
FindRandomIntroSetsWithTagExcluding(
const service::Tag& tag, size_t max = 2,
const std::set< service::IntroSet >& excludes = {}) override;
/// handle rc lookup from requester for target
void
LookupRouterRelayed(
@ -140,8 +123,8 @@ namespace llarp
/// send introset to peer from source with S counter and excluding peers
void
PropagateIntroSetTo(const Key_t& source, uint64_t sourceTX,
const service::IntroSet& introset, const Key_t& peer,
uint64_t S,
const service::EncryptedIntroSet& introset,
const Key_t& peer, uint64_t S,
const std::set< Key_t >& exclude) override;
/// initialize dht context and explore every exploreInterval milliseconds
@ -150,9 +133,8 @@ namespace llarp
llarp_time_t exploreInterval) override;
/// get localally stored introset by service address
const llarp::service::IntroSet*
GetIntroSetByServiceAddress(
const llarp::service::Address& addr) const override;
absl::optional< llarp::service::EncryptedIntroSet >
GetIntroSetByLocation(const Key_t& location) const override;
void
handle_cleaner_timer(uint64_t interval);
@ -228,11 +210,23 @@ namespace llarp
return router->nodedb()->Get(k.as_array(), rc);
}
void
FloodRCLater(const dht::Key_t from, const RouterContact rc) override;
PendingIntrosetLookups _pendingIntrosetLookups;
PendingTagLookups _pendingTagLookups;
PendingRouterLookups _pendingRouterLookups;
PendingExploreLookups _pendingExploreLookups;
using RCGossipReplayFilter_t = util::DecayingHashSet< RouterContact >;
RCGossipReplayFilter_t m_GossipReplayFilter;
using RCGossipList_t = std::unordered_multimap< RouterContact, RouterID,
RouterContact::Hash >;
/// list of RCs that we want to publish with who gave us the publish
RCGossipList_t m_GossipList;
PendingIntrosetLookups&
pendingIntrosetLookups() override
{
@ -245,18 +239,6 @@ namespace llarp
return _pendingIntrosetLookups;
}
PendingTagLookups&
pendingTagLookups() override
{
return _pendingTagLookups;
}
const PendingTagLookups&
pendingTagLookups() const override
{
return _pendingTagLookups;
}
PendingRouterLookups&
pendingRouterLookups() override
{
@ -305,7 +287,9 @@ namespace llarp
Key_t ourKey;
};
Context::Context()
static constexpr auto GossipFilterDecayInterval = std::chrono::minutes(30);
Context::Context() : m_GossipReplayFilter(GossipFilterDecayInterval)
{
randombytes((byte_t*)&ids, sizeof(uint64_t));
}
@ -355,18 +339,51 @@ namespace llarp
{
// clean up transactions
CleanupTX();
const llarp_time_t now = Now();
// flush pending floods
if(router->IsServiceNode())
{
std::unordered_set< RouterContact, RouterContact::Hash > keys;
for(const auto& item : m_GossipList)
{
// filter hit don't publish it at all
if(not m_GossipReplayFilter.Insert(item.first))
continue;
// skip if duplicate RC
if(not keys.emplace(item.first).second)
continue;
const auto& rc = item.first;
// build set of routers to not send to for this RC
std::set< RouterID > exclude = {rc.pubkey};
const auto range = m_GossipList.equal_range(rc);
auto itr = range.first;
while(itr != range.second)
{
exclude.emplace(itr->second);
++itr;
}
Nodes()->ForEachNode([self = this, rc, &exclude](const auto& node) {
const RouterID K(node.rc.pubkey);
if(exclude.find(K) == exclude.end())
self->DHTSendTo(K, new GotRouterMessage(rc));
});
}
}
// clear gossip list
m_GossipList.clear();
// decay gossip filter
m_GossipReplayFilter.Decay(now);
if(_services)
{
// expire intro sets
auto now = Now();
auto& nodes = _services->nodes;
auto itr = nodes.begin();
while(itr != nodes.end())
{
if(itr->second.introset.IsExpired(now))
{
llarp::LogDebug("introset expired ", itr->second.introset.A.Addr());
itr = nodes.erase(itr);
}
else
@ -376,53 +393,6 @@ namespace llarp
ScheduleCleanupTimer();
}
std::set< service::IntroSet >
Context::FindRandomIntroSetsWithTagExcluding(
const service::Tag& tag, size_t max,
const std::set< service::IntroSet >& exclude)
{
std::set< service::IntroSet > found;
auto& nodes = _services->nodes;
if(nodes.size() == 0)
{
return found;
}
auto itr = nodes.begin();
// start at random middle point
auto start = llarp::randint() % nodes.size();
std::advance(itr, start);
auto end = itr;
std::string tagname = tag.ToString();
while(itr != nodes.end())
{
if(itr->second.introset.topic.ToString() == tagname)
{
if(exclude.count(itr->second.introset) == 0)
{
found.insert(itr->second.introset);
if(found.size() == max)
return found;
}
}
++itr;
}
itr = nodes.begin();
while(itr != end)
{
if(itr->second.introset.topic.ToString() == tagname)
{
if(exclude.count(itr->second.introset) == 0)
{
found.insert(itr->second.introset);
if(found.size() == max)
return found;
}
}
++itr;
}
return found;
}
void
Context::LookupRouterRelayed(
const Key_t& requester, uint64_t txid, const Key_t& target,
@ -484,15 +454,13 @@ namespace llarp
}
}
const llarp::service::IntroSet*
Context::GetIntroSetByServiceAddress(
const llarp::service::Address& addr) const
absl::optional< llarp::service::EncryptedIntroSet >
Context::GetIntroSetByLocation(const Key_t& key) const
{
auto key = addr.ToKey();
auto itr = _services->nodes.find(key);
if(itr == _services->nodes.end())
return nullptr;
return &itr->second.introset;
return {};
return itr->second.introset;
}
void
@ -503,7 +471,6 @@ namespace llarp
pendingRouterLookups().Expire(now);
_pendingIntrosetLookups.Expire(now);
pendingTagLookups().Expire(now);
pendingExploreLookups().Expire(now);
}
@ -513,7 +480,6 @@ namespace llarp
util::StatusObject obj{
{"pendingRouterLookups", pendingRouterLookups().ExtractStatus()},
{"pendingIntrosetLookups", _pendingIntrosetLookups.ExtractStatus()},
{"pendingTagLookups", pendingTagLookups().ExtractStatus()},
{"pendingExploreLookups", pendingExploreLookups().ExtractStatus()},
{"nodes", _nodes->ExtractStatus()},
{"services", _services->ExtractStatus()},
@ -564,7 +530,7 @@ namespace llarp
llarp::routing::DHTMessage reply;
if(!msg.HandleMessage(router->dht(), reply.M))
return false;
if(!reply.M.empty())
if(not reply.M.empty())
{
auto path = router->pathContext().GetByUpstream(router->pubkey(), id);
return path && path->SendRoutingMessage(reply, router);
@ -573,7 +539,7 @@ namespace llarp
}
void
Context::LookupIntroSetForPath(const service::Address& addr, uint64_t txid,
Context::LookupIntroSetForPath(const Key_t& addr, uint64_t txid,
const llarp::PathID_t& path,
const Key_t& askpeer, uint64_t R)
{
@ -587,23 +553,23 @@ namespace llarp
void
Context::PropagateIntroSetTo(const Key_t& from, uint64_t txid,
const service::IntroSet& introset,
const service::EncryptedIntroSet& introset,
const Key_t& tellpeer, uint64_t S,
const std::set< Key_t >& exclude)
{
TXOwner asker(from, txid);
TXOwner peer(tellpeer, ++ids);
service::Address addr = introset.A.Addr();
const Key_t addr(introset.derivedSigningKey);
_pendingIntrosetLookups.NewTX(
peer, asker, addr,
new PublishServiceJob(asker, introset, this, S, exclude));
}
void
Context::LookupIntroSetRecursive(const service::Address& addr,
const Key_t& whoasked, uint64_t txid,
const Key_t& askpeer, uint64_t R,
service::IntroSetLookupHandler handler)
Context::LookupIntroSetRecursive(
const Key_t& addr, const Key_t& whoasked, uint64_t txid,
const Key_t& askpeer, uint64_t R,
service::EncryptedIntroSetLookupHandler handler)
{
TXOwner asker(whoasked, txid);
TXOwner peer(askpeer, ++ids);
@ -614,39 +580,25 @@ namespace llarp
}
void
Context::LookupIntroSetIterative(const service::Address& addr,
const Key_t& whoasked, uint64_t txid,
const Key_t& askpeer,
service::IntroSetLookupHandler handler)
Context::FloodRCLater(const dht::Key_t from, const RouterContact rc)
{
TXOwner asker(whoasked, txid);
TXOwner peer(askpeer, ++ids);
_pendingIntrosetLookups.NewTX(
peer, asker, addr,
new ServiceAddressLookup(asker, addr, this, 0, handler), 1000);
}
void
Context::LookupTagRecursive(const service::Tag& tag, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
uint64_t R)
{
TXOwner asker(whoasked, whoaskedTX);
TXOwner peer(askpeer, ++ids);
_pendingTagLookups.NewTX(peer, asker, tag,
new TagLookup(asker, tag, this, R));
llarp::LogDebug("ask ", askpeer.SNode(), " for ", tag, " on behalf of ",
whoasked.SNode(), " R=", R);
// check valid rc
if(not router->rcLookupHandler().CheckRC(rc))
return;
m_GossipList.emplace(rc, from.as_array());
// TODO: don't publish our rc in next interval (based of whitelist size)
}
void
Context::LookupTagForPath(const service::Tag& tag, uint64_t txid,
const llarp::PathID_t& path, const Key_t& askpeer)
Context::LookupIntroSetIterative(
const Key_t& addr, const Key_t& whoasked, uint64_t txid,
const Key_t& askpeer, service::EncryptedIntroSetLookupHandler handler)
{
TXOwner asker(whoasked, txid);
TXOwner peer(askpeer, ++ids);
TXOwner whoasked(OurKey(), txid);
_pendingTagLookups.NewTX(peer, whoasked, tag,
new LocalTagLookup(path, txid, tag, this));
_pendingIntrosetLookups.NewTX(
peer, asker, addr,
new ServiceAddressLookup(asker, addr, this, 0, handler), 1000);
}
bool

@ -26,10 +26,7 @@ namespace llarp
struct AbstractContext
{
using PendingIntrosetLookups =
TXHolder< service::Address, service::IntroSet,
service::Address::Hash >;
using PendingTagLookups =
TXHolder< service::Tag, service::IntroSet, service::Tag::Hash >;
TXHolder< Key_t, service::EncryptedIntroSet, Key_t::Hash >;
using PendingRouterLookups =
TXHolder< RouterID, RouterContact, RouterID::Hash >;
using PendingExploreLookups =
@ -48,46 +45,29 @@ namespace llarp
/// on behalf of whoasked request introset for target from dht router with
/// key askpeer
virtual void
LookupIntroSetRecursive(const service::Address& target,
const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer, uint64_t R,
service::IntroSetLookupHandler result =
service::IntroSetLookupHandler()) = 0;
LookupIntroSetRecursive(
const Key_t& target, const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer, uint64_t R,
service::EncryptedIntroSetLookupHandler result =
service::EncryptedIntroSetLookupHandler()) = 0;
virtual void
LookupIntroSetIterative(const service::Address& target,
const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer,
service::IntroSetLookupHandler result =
service::IntroSetLookupHandler()) = 0;
virtual std::set< service::IntroSet >
FindRandomIntroSetsWithTagExcluding(
const service::Tag& tag, size_t max = 2,
const std::set< service::IntroSet >& excludes = {}) = 0;
LookupIntroSetIterative(
const Key_t& target, const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer,
service::EncryptedIntroSetLookupHandler result =
service::EncryptedIntroSetLookupHandler()) = 0;
virtual bool
HasRouterLookup(const RouterID& target) const = 0;
/// on behalf of whoasked request introsets with tag from dht router with
/// key askpeer with Recursion depth R
virtual void
LookupTagRecursive(const service::Tag& tag, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
uint64_t R) = 0;
/// issue dht lookup for tag via askpeer and send reply to local path
virtual void
LookupTagForPath(const service::Tag& tag, uint64_t txid,
const PathID_t& path, const Key_t& askpeer) = 0;
/// issue dht lookup for router via askpeer and send reply to local path
virtual void
LookupRouterForPath(const RouterID& target, uint64_t txid,
const PathID_t& path, const Key_t& askpeer) = 0;
virtual void
LookupIntroSetForPath(const service::Address& addr, uint64_t txid,
LookupIntroSetForPath(const Key_t& addr, uint64_t txid,
const PathID_t& path, const Key_t& askpeer,
uint64_t R) = 0;
@ -113,16 +93,16 @@ namespace llarp
/// send introset to peer from source with S counter and excluding peers
virtual void
PropagateIntroSetTo(const Key_t& source, uint64_t sourceTX,
const service::IntroSet& introset, const Key_t& peer,
uint64_t S, const std::set< Key_t >& exclude) = 0;
const service::EncryptedIntroSet& introset,
const Key_t& peer, uint64_t S,
const std::set< Key_t >& exclude) = 0;
virtual void
Init(const Key_t& us, AbstractRouter* router,
llarp_time_t exploreInterval) = 0;
virtual const llarp::service::IntroSet*
GetIntroSetByServiceAddress(
const llarp::service::Address& addr) const = 0;
virtual absl::optional< llarp::service::EncryptedIntroSet >
GetIntroSetByLocation(const Key_t& location) const = 0;
virtual llarp_time_t
Now() const = 0;
@ -145,12 +125,6 @@ namespace llarp
virtual const PendingIntrosetLookups&
pendingIntrosetLookups() const = 0;
virtual PendingTagLookups&
pendingTagLookups() = 0;
virtual const PendingTagLookups&
pendingTagLookups() const = 0;
virtual PendingRouterLookups&
pendingRouterLookups() = 0;
@ -185,6 +159,10 @@ namespace llarp
virtual void
StoreRC(const RouterContact rc) const = 0;
/// flood rc to all peers later in a batch
virtual void
FloodRCLater(const dht::Key_t from, const RouterContact rc) = 0;
};
std::unique_ptr< AbstractContext >

@ -12,7 +12,7 @@ namespace llarp
namespace dht
{
LocalServiceAddressLookup::LocalServiceAddressLookup(
const PathID_t &pathid, uint64_t txid, const service::Address &addr,
const PathID_t &pathid, uint64_t txid, const Key_t &addr,
AbstractContext *ctx, __attribute__((unused)) const Key_t &askpeer)
: ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, 5,
nullptr)
@ -36,7 +36,7 @@ namespace llarp
// pick newest if we have more than 1 result
if(valuesFound.size())
{
service::IntroSet found;
service::EncryptedIntroSet found;
for(const auto &introset : valuesFound)
{
if(found.OtherIsNewer(introset))

@ -14,8 +14,7 @@ namespace llarp
PathID_t localPath;
LocalServiceAddressLookup(const PathID_t &pathid, uint64_t txid,
const service::Address &addr,
AbstractContext *ctx,
const Key_t &addr, AbstractContext *ctx,
__attribute__((unused)) const Key_t &askpeer);
void

@ -0,0 +1,28 @@
#ifndef LLARP_DHT_MESSAGES_CONSENSUS_HPP
#define LLARP_DHT_MESSAGES_CONSENSUS_HPP
#include <dht/message.hpp>
#include <router_version.hpp>
namespace llarp
{
namespace dht
{
struct ConsensusMessage
{
/// H
ShortHash m_Hash;
/// K
std::vector< RouterID > m_Keys;
/// N
uint64_t m_NumberOfEntries;
/// O
uint64_t m_EntryOffset;
/// T
uint64_t m_TxID;
/// U
llarp_time_t m_NextUpdateRequired;
/// V
RouterVersion m_RotuerVersion;
};
} // namespace dht
} // namespace llarp

@ -24,7 +24,7 @@ namespace llarp
if(!BEncodeMaybeReadDictInt("R", recursionDepth, read, k, val))
return false;
if(!BEncodeMaybeReadDictEntry("S", serviceAddress, read, k, val))
if(!BEncodeMaybeReadDictEntry("S", location, read, k, val))
return false;
if(!BEncodeMaybeReadDictInt("T", txID, read, k, val))
@ -52,7 +52,7 @@ namespace llarp
if(!BEncodeWriteDictInt("R", recursionDepth, buf))
return false;
// service address
if(!BEncodeWriteDictEntry("S", serviceAddress, buf))
if(!BEncodeWriteDictEntry("S", location, buf))
return false;
}
else
@ -91,111 +91,58 @@ namespace llarp
}
Key_t peer;
std::set< Key_t > exclude = {dht.OurKey(), From};
if(tagName.Empty())
if(not tagName.Empty())
return false;
if(location.IsZero())
{
if(serviceAddress.IsZero())
{
// we dont got it
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
llarp::LogInfo("lookup ", serviceAddress.ToString());
const auto introset = dht.GetIntroSetByServiceAddress(serviceAddress);
if(introset)
{
replies.emplace_back(new GotIntroMessage({*introset}, txID));
return true;
}
const Key_t target = serviceAddress.ToKey();
const Key_t us = dht.OurKey();
if(recursionDepth == 0)
{
// we don't have it
Key_t closer;
// find closer peer
if(!dht.Nodes()->FindClosest(target, closer))
return false;
replies.emplace_back(new GotIntroMessage(From, closer, txID));
return true;
}
// we are recursive
const auto rc = dht.GetRouter()->nodedb()->FindClosestTo(target);
peer = Key_t(rc.pubkey);
if((us ^ target) < (peer ^ target) || peer == us)
{
// we are not closer than our peer to the target so don't
// recurse farther
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
if(relayed)
{
dht.LookupIntroSetForPath(serviceAddress, txID, pathID, peer,
recursionDepth - 1);
}
else
{
dht.LookupIntroSetRecursive(serviceAddress, From, txID, peer,
recursionDepth - 1);
}
// we dont got it
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
const auto maybe = dht.GetIntroSetByLocation(location);
if(maybe.has_value())
{
replies.emplace_back(new GotIntroMessage({maybe.value()}, txID));
return true;
}
const Key_t us = dht.OurKey();
if(recursionDepth == 0)
{
// we don't have it
Key_t closer;
// find closer peer
if(!dht.Nodes()->FindClosest(location, closer))
return false;
replies.emplace_back(new GotIntroMessage(From, closer, txID));
return true;
}
// we are recursive
const auto rc = dht.GetRouter()->nodedb()->FindClosestTo(location);
peer = Key_t(rc.pubkey);
if((us ^ location) < (peer ^ location) || peer == us)
{
// we are not closer than our peer to the target so don't
// recurse farther
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
if(relayed)
{
// tag lookup
if(dht.Nodes()->GetRandomNodeExcluding(peer, exclude))
{
dht.LookupTagForPath(tagName, txID, pathID, peer);
}
else
{
// no more closer peers
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
dht.LookupIntroSetForPath(location, txID, pathID, peer,
recursionDepth - 1);
}
else
{
if(recursionDepth == 0)
{
// base case
auto introsets =
dht.FindRandomIntroSetsWithTagExcluding(tagName, 2, {});
std::vector< service::IntroSet > reply;
for(const auto& introset : introsets)
{
reply.emplace_back(introset);
}
replies.emplace_back(new GotIntroMessage(reply, txID));
return true;
}
if(recursionDepth < MaxRecursionDepth)
{
// tag lookup
if(dht.Nodes()->GetRandomNodeExcluding(peer, exclude))
{
dht.LookupTagRecursive(tagName, From, txID, peer,
recursionDepth - 1);
}
else
{
replies.emplace_back(new GotIntroMessage({}, txID));
}
}
else
{
// too big recursion depth
replies.emplace_back(new GotIntroMessage({}, txID));
}
dht.LookupIntroSetRecursive(location, From, txID, peer,
recursionDepth - 1);
}
return true;
}
} // namespace dht

@ -14,7 +14,7 @@ namespace llarp
{
static const uint64_t MaxRecursionDepth;
uint64_t recursionDepth = 0;
llarp::service::Address serviceAddress;
Key_t location;
llarp::service::Tag tagName;
uint64_t txID = 0;
bool relayed = false;
@ -28,19 +28,17 @@ namespace llarp
bool iterate = true)
: IMessage({}), tagName(tag), txID(txid)
{
serviceAddress.Zero();
if(iterate)
recursionDepth = 0;
else
recursionDepth = 1;
}
explicit FindIntroMessage(uint64_t txid,
const llarp::service::Address& addr,
explicit FindIntroMessage(uint64_t txid, const Key_t& addr,
uint64_t maxRecursionDepth)
: IMessage({})
, recursionDepth(maxRecursionDepth)
, serviceAddress(addr)
, location(addr)
, txID(txid)
{
tagName.Zero();

@ -11,8 +11,8 @@ namespace llarp
{
namespace dht
{
GotIntroMessage::GotIntroMessage(std::vector< service::IntroSet > results,
uint64_t tx)
GotIntroMessage::GotIntroMessage(
std::vector< service::EncryptedIntroSet > results, uint64_t tx)
: IMessage({}), found(std::move(results)), txid(tx)
{
}
@ -37,12 +37,7 @@ namespace llarp
}
}
TXOwner owner(From, txid);
auto tagLookup = dht.pendingTagLookups().GetPendingLookupFrom(owner);
if(tagLookup)
{
dht.pendingTagLookups().Found(owner, tagLookup->target, found);
return true;
}
auto serviceLookup =
dht.pendingIntrosetLookups().GetPendingLookupFrom(owner);
if(serviceLookup)

@ -16,7 +16,7 @@ namespace llarp
struct GotIntroMessage : public IMessage
{
/// the found introsets
std::vector< service::IntroSet > found;
std::vector< service::EncryptedIntroSet > found;
/// txid
uint64_t txid = 0;
/// the key of a router closer in keyspace if iterative lookup
@ -42,7 +42,8 @@ namespace llarp
}
/// for recursive reply
GotIntroMessage(std::vector< service::IntroSet > results, uint64_t txid);
GotIntroMessage(std::vector< service::EncryptedIntroSet > results,
uint64_t txid);
~GotIntroMessage() override = default;

@ -124,6 +124,11 @@ namespace llarp
{
if(not dht.GetRouter()->rcLookupHandler().CheckRC(rc))
return false;
if(txid == 0 and foundRCs.size() == 1)
{
// flood as needed
dht.FloodRCLater(From, rc);
}
}
return true;
}

@ -1,6 +1,6 @@
#ifndef LLARP_DHT_MESSAGES_GOT_ROUTER_HPP
#define LLARP_DHT_MESSAGES_GOT_ROUTER_HPP
#include <constants/proto.hpp>
#include <dht/message.hpp>
#include <router_contact.hpp>
#include <util/copy_or_nullptr.hpp>
@ -42,6 +42,13 @@ namespace llarp
{
}
/// gossip message
GotRouterMessage(const RouterContact rc)
: IMessage({}), foundRCs({rc}), txid(0)
{
version = LLARP_PROTO_VERSION;
}
GotRouterMessage(const GotRouterMessage& other)
: IMessage(other.From)
, foundRCs(other.foundRCs)

@ -55,20 +55,7 @@ namespace llarp
return true;
}
if(introset.W && !introset.W->IsValid(now))
{
llarp::LogWarn("proof of work not good enough for IntroSet");
// don't propogate or store
replies.emplace_back(new GotIntroMessage({}, txID));
return true;
}
llarp::dht::Key_t addr;
if(not introset.A.CalculateAddress(addr.as_array()))
{
llarp::LogWarn(
"failed to calculate hidden service address for PubIntro message");
return false;
}
const llarp::dht::Key_t addr(introset.derivedSigningKey);
now += llarp::service::MAX_INTROSET_TIME_DELTA;
if(introset.IsExpired(now))

@ -13,7 +13,7 @@ namespace llarp
struct PublishIntroMessage final : public IMessage
{
static const uint64_t MaxPropagationDepth;
llarp::service::IntroSet introset;
llarp::service::EncryptedIntroSet introset;
std::vector< Key_t > exclude;
uint64_t depth = 0;
uint64_t txID = 0;
@ -21,8 +21,9 @@ namespace llarp
{
}
PublishIntroMessage(const llarp::service::IntroSet& i, uint64_t tx,
uint64_t s, std::vector< Key_t > _exclude = {})
PublishIntroMessage(const llarp::service::EncryptedIntroSet& i,
uint64_t tx, uint64_t s,
std::vector< Key_t > _exclude = {})
: IMessage({})
, introset(i)
, exclude(std::move(_exclude))

@ -39,7 +39,7 @@ namespace llarp
struct ISNode
{
service::IntroSet introset;
service::EncryptedIntroSet introset;
Key_t ID;
@ -48,9 +48,9 @@ namespace llarp
ID.Zero();
}
ISNode(service::IntroSet other) : introset(std::move(other))
ISNode(service::EncryptedIntroSet other) : introset(std::move(other))
{
introset.A.CalculateAddress(ID.as_array());
ID = Key_t(introset.derivedSigningKey.as_array());
}
util::StatusObject
@ -62,7 +62,7 @@ namespace llarp
bool
operator<(const ISNode& other) const
{
return introset.T < other.introset.T;
return introset.signedAt < other.introset.signedAt;
}
};
} // namespace dht

@ -9,27 +9,28 @@ namespace llarp
namespace dht
{
PublishServiceJob::PublishServiceJob(const TXOwner &asker,
const service::IntroSet &introset,
const service::EncryptedIntroSet &I,
AbstractContext *ctx, uint64_t s,
std::set< Key_t > exclude)
: TX< service::Address, service::IntroSet >(asker, introset.A.Addr(),
ctx)
: TX< Key_t, service::EncryptedIntroSet >(
asker, Key_t{I.derivedSigningKey}, ctx)
, S(s)
, dontTell(std::move(exclude))
, I(introset)
, introset(I)
{
}
bool
PublishServiceJob::Validate(const service::IntroSet &introset) const
PublishServiceJob::Validate(const service::EncryptedIntroSet &value) const
{
if(I.A != introset.A)
if(value.derivedSigningKey != introset.derivedSigningKey)
{
llarp::LogWarn(
"publish introset acknowledgement acked a different service");
return false;
}
return true;
const llarp_time_t now = llarp::time_now_ms();
return value.Verify(now);
}
void
@ -40,8 +41,9 @@ namespace llarp
{
exclude.push_back(router);
}
parent->DHTSendTo(peer.node.as_array(),
new PublishIntroMessage(I, peer.txid, S, exclude));
parent->DHTSendTo(
peer.node.as_array(),
new PublishIntroMessage(introset, peer.txid, S, exclude));
}
} // namespace dht
} // namespace llarp

@ -12,18 +12,19 @@ namespace llarp
{
namespace dht
{
struct PublishServiceJob : public TX< service::Address, service::IntroSet >
struct PublishServiceJob : public TX< Key_t, service::EncryptedIntroSet >
{
uint64_t S;
std::set< Key_t > dontTell;
service::IntroSet I;
service::EncryptedIntroSet introset;
PublishServiceJob(const TXOwner &asker, const service::IntroSet &introset,
PublishServiceJob(const TXOwner &asker,
const service::EncryptedIntroSet &introset,
AbstractContext *ctx, uint64_t s,
std::set< Key_t > exclude);
bool
Validate(const service::IntroSet &introset) const override;
Validate(const service::EncryptedIntroSet &introset) const override;
void
Start(const TXOwner &peer) override;

@ -10,10 +10,9 @@ namespace llarp
namespace dht
{
ServiceAddressLookup::ServiceAddressLookup(
const TXOwner &asker, const service::Address &addr,
AbstractContext *ctx, uint64_t r,
service::IntroSetLookupHandler handler)
: TX< service::Address, service::IntroSet >(asker, addr, ctx)
const TXOwner &asker, const Key_t &addr, AbstractContext *ctx,
uint64_t r, service::EncryptedIntroSetLookupHandler handler)
: TX< Key_t, service::EncryptedIntroSet >(asker, addr, ctx)
, handleResult(std::move(handler))
, R(r)
{
@ -21,14 +20,15 @@ namespace llarp
}
bool
ServiceAddressLookup::Validate(const service::IntroSet &value) const
ServiceAddressLookup::Validate(
const service::EncryptedIntroSet &value) const
{
if(!value.Verify(parent->Now()))
{
llarp::LogWarn("Got invalid introset from service lookup");
return false;
}
if(value.A.Addr() != target)
if(value.derivedSigningKey != target)
{
llarp::LogWarn("got introset with wrong target from service lookup");
return false;
@ -40,11 +40,10 @@ namespace llarp
ServiceAddressLookup::GetNextPeer(Key_t &next,
const std::set< Key_t > &exclude)
{
Key_t k = target.ToKey();
const auto &nodes = parent->Nodes();
if(nodes)
{
return nodes->FindCloseExcluding(k, next, exclude);
return nodes->FindCloseExcluding(target, next, exclude);
}
return false;
@ -78,7 +77,7 @@ namespace llarp
// get newest introset
if(valuesFound.size())
{
llarp::service::IntroSet found;
llarp::service::EncryptedIntroSet found;
for(const auto &introset : valuesFound)
{
if(found.OtherIsNewer(introset))

@ -12,18 +12,17 @@ namespace llarp
{
struct TXOwner;
struct ServiceAddressLookup
: public TX< service::Address, service::IntroSet >
struct ServiceAddressLookup : public TX< Key_t, service::EncryptedIntroSet >
{
service::IntroSetLookupHandler handleResult;
service::EncryptedIntroSetLookupHandler handleResult;
uint64_t R;
ServiceAddressLookup(const TXOwner &asker, const service::Address &addr,
ServiceAddressLookup(const TXOwner &asker, const Key_t &addr,
AbstractContext *ctx, uint64_t r,
service::IntroSetLookupHandler handler);
service::EncryptedIntroSetLookupHandler handler);
bool
Validate(const service::IntroSet &value) const override;
Validate(const service::EncryptedIntroSet &value) const override;
bool
GetNextPeer(Key_t &next, const std::set< Key_t > &exclude) override;

@ -8,14 +8,16 @@ namespace llarp
namespace dht
{
bool
TagLookup::Validate(const service::IntroSet &introset) const
TagLookup::Validate(const service::EncryptedIntroSet &introset) const
{
if(!introset.Verify(parent->Now()))
{
llarp::LogWarn("got invalid introset from tag lookup");
return false;
}
if(introset.topic != target)
if(not introset.topic.has_value())
return false;
if(introset.topic.value() != target)
{
llarp::LogWarn("got introset with missmatched topic in tag lookup");
return false;
@ -33,20 +35,8 @@ namespace llarp
void
TagLookup::SendReply()
{
std::set< service::IntroSet > found(valuesFound.begin(),
valuesFound.end());
// collect our local values if we haven't hit a limit
if(found.size() < 2)
{
auto tags =
parent->FindRandomIntroSetsWithTagExcluding(target, 1, found);
std::copy(tags.begin(), tags.end(), std::inserter(found, found.end()));
}
std::vector< service::IntroSet > values(found.begin(), found.end());
parent->DHTSendTo(whoasked.node.as_array(),
new GotIntroMessage(values, whoasked.txid));
new GotIntroMessage({}, whoasked.txid));
}
} // namespace dht
} // namespace llarp

@ -9,17 +9,18 @@ namespace llarp
{
namespace dht
{
struct TagLookup : public TX< service::Tag, service::IntroSet >
struct TagLookup : public TX< service::Tag, service::EncryptedIntroSet >
{
uint64_t R;
TagLookup(const TXOwner &asker, const service::Tag &tag,
AbstractContext *ctx, uint64_t r)
: TX< service::Tag, service::IntroSet >(asker, tag, ctx), R(r)
: TX< service::Tag, service::EncryptedIntroSet >(asker, tag, ctx)
, R(r)
{
}
bool
Validate(const service::IntroSet &introset) const override;
Validate(const service::EncryptedIntroSet &introset) const override;
void
Start(const TXOwner &peer) override;

@ -131,7 +131,7 @@ namespace llarp
template < typename K, typename V, typename K_Hash >
void
TXHolder< K, V, K_Hash >::NotFound(const TXOwner& from,
const std::unique_ptr< Key_t >& next)
const std::unique_ptr< Key_t >&)
{
auto txitr = tx.find(from);
if(txitr == tx.end())

@ -123,6 +123,12 @@ namespace llarp
util::StatusObject
ExtractStatus() const override;
bool
IsInbound() const override
{
return m_Inbound;
}
private:
enum class State
{

@ -187,6 +187,8 @@ namespace llarp
}
for(const auto& pending : closedPending)
{
if(pending->IsInbound())
continue;
HandleTimeout(pending.get());
}
}

@ -82,6 +82,10 @@ namespace llarp
virtual PubKey
GetPubKey() const = 0;
/// is an inbound session or not
virtual bool
IsInbound() const = 0;
/// get remote address
virtual Addr
GetRemoteEndpoint() const = 0;

@ -24,6 +24,8 @@ namespace llarp
{
if(key == "c")
{
/// so we dont put it into the shitty queue
pathid.Fill('c');
return BEncodeReadArray(frames, buf);
}
bool read = false;
@ -248,9 +250,10 @@ namespace llarp
if(self->context->HasTransitHop(self->hop->info))
{
llarp::LogError("duplicate transit hop ", self->hop->info);
OnForwardLRCMResult(self->context->Router(), self->hop->info.rxID,
self->hop->info.downstream, self->hop->pathKey,
SendStatus::Congestion);
LR_StatusMessage::CreateAndSend(
self->context->Router(), self->hop->info.rxID,
self->hop->info.downstream, self->hop->pathKey,
LR_StatusRecord::FAIL_DUPLICATE_HOP);
self->hop = nullptr;
return;
}

@ -91,6 +91,7 @@ namespace llarp
{
std::for_each(frames.begin(), frames.end(), [](auto& f) { f.Clear(); });
version = 0;
status = 0;
}
bool
@ -134,7 +135,8 @@ namespace llarp
if(!path)
{
llarp::LogWarn(
"unhandled LR_Status message: no associated IHopHandler found");
"unhandled LR_Status message: no associated path found pathid=",
pathid);
return false;
}
@ -161,7 +163,7 @@ namespace llarp
{
auto message = std::make_shared< LR_StatusMessage >();
message->status = status & LR_StatusRecord::SUCCESS;
message->status = status;
message->pathid = pathid;
message->SetDummyFrames();
@ -230,13 +232,6 @@ namespace llarp
std::shared_ptr< LR_StatusMessage > msg)
{
llarp::LogDebug("Attempting to send LR_Status message to (", nextHop, ")");
if(not router->HasSessionTo(nextHop))
{
llarp::LogError(
"Sending LR_Status message, but no connection to previous hop (",
nextHop, ")");
return;
}
if(not router->SendToOrQueue(nextHop, msg.get()))
{
llarp::LogError("Sending LR_Status message, SendToOrQueue to ", nextHop,

@ -247,7 +247,7 @@ namespace llarp
GetCurrentIntroductions(std::set< service::Introduction >& intros) const;
virtual bool
PublishIntroSet(__attribute__((unused)) AbstractRouter* r)
PublishIntroSet(const service::EncryptedIntroSet&, AbstractRouter*)
{
return false;
}

@ -71,11 +71,12 @@ namespace llarp
LR_StatusMessage::QueueSendMessage(r, info.downstream, msg);
if((status & LR_StatusRecord::SUCCESS) == 0)
if((status & LR_StatusRecord::SUCCESS) != LR_StatusRecord::SUCCESS)
{
LogDebug(
LogWarn(
"TransitHop received non-successful LR_StatusMessage, queueing "
"self-destruct");
"self-destruct status=",
status);
QueueDestroySelf(r);
}

@ -221,7 +221,10 @@ namespace llarp
if(status == ILinkSession::DeliveryStatus::eDeliverySuccess)
DoCallback(callback, SendStatus::Success);
else
{
LogWarn("Send outbound message handler dropped message");
DoCallback(callback, SendStatus::Congestion);
}
});
}
@ -252,6 +255,10 @@ namespace llarp
!= llarp::thread::QueueReturn::Success)
{
m_queueStats.dropped++;
LogWarn(
"QueueOutboundMessage outbound message handler dropped message on "
"pathid=",
pathid);
DoCallback(callback_copy, SendStatus::Congestion);
}
else
@ -290,6 +297,10 @@ namespace llarp
}
else
{
LogWarn(
"ProcessOutboundQueue outbound message handler dropped message on "
"pathid=",
entry.pathid);
DoCallback(entry.message.second, SendStatus::Congestion);
m_queueStats.dropped++;
}

@ -57,9 +57,8 @@ namespace llarp
OutboundSessionMaker::OnConnectTimeout(ILinkSession *session)
{
// TODO: retry/num attempts
LogWarn("Session establish attempt to ", RouterID(session->GetPubKey()),
" timed out.");
" timed out.", session->GetRemoteEndpoint());
FinalizeRequest(session->GetPubKey(), SessionResult::Timeout);
}

@ -339,14 +339,18 @@ namespace llarp
if(!nextRC.Verify(time_now_ms(), false))
return false;
_rc = std::move(nextRC);
// propagate RC by renegotiating sessions
ForEachPeer([](ILinkSession *s) {
if(s->RenegotiateSession())
LogInfo("renegotiated session");
else
LogWarn("failed to renegotiate session");
});
if(rotateKeys)
{
// propagate RC by renegotiating sessions
ForEachPeer([](ILinkSession *s) {
if(s->RenegotiateSession())
LogInfo("renegotiated session");
else
LogWarn("failed to renegotiate session");
});
}
/// flood our rc
_dht->impl->FloodRCLater(dht::Key_t(pubkey()), _rc);
return SaveRC();
}
@ -919,6 +923,11 @@ namespace llarp
// set public signing key
_rc.pubkey = seckey_topublic(identity());
// set router version if service node
if(IsServiceNode())
{
_rc.routerVersion = RouterVersion(llarp::VERSION, LLARP_PROTO_VERSION);
}
AddressInfo ai;
_linkManager.ForEachInboundLink([&](LinkLayer_ptr link) {

@ -126,7 +126,12 @@ namespace llarp
return false;
if(!enckey.BEncode(buf))
return false;
// write router version if present
if(routerVersion.has_value())
{
if(not BEncodeWriteDictEntry("r", routerVersion.value(), buf))
return false;
}
/* write last updated */
if(!bencode_write_bytestring(buf, "u", 1))
return false;
@ -160,7 +165,8 @@ namespace llarp
nickname.Zero();
enckey.Zero();
pubkey.Zero();
last_updated = 0;
routerVersion = absl::optional< RouterVersion >{};
last_updated = 0;
}
util::StatusObject
@ -176,7 +182,10 @@ namespace llarp
{
obj["nickname"] = Nick();
}
if(routerVersion.has_value())
{
obj["routerVersion"] = routerVersion->ToString();
}
return obj;
}
@ -193,6 +202,15 @@ namespace llarp
if(!BEncodeMaybeReadDictEntry("k", pubkey, read, key, buf))
return false;
if(key == "r")
{
RouterVersion r;
if(not r.BDecode(buf))
return false;
routerVersion = r;
return true;
}
if(key == "n")
{
llarp_buffer_t strbuf;

@ -8,6 +8,7 @@
#include <util/aligned.hpp>
#include <util/bencode.hpp>
#include <util/status.hpp>
#include <router_version.hpp>
#include <functional>
#include <nlohmann/json.hpp>
@ -104,6 +105,7 @@ namespace llarp
uint64_t last_updated = 0;
uint64_t version = LLARP_PROTO_VERSION;
absl::optional< RouterVersion > routerVersion;
util::StatusObject
ExtractStatus() const;

@ -0,0 +1,96 @@
#include <router_version.hpp>
#include <constants/version.hpp>
#include <constants/proto.hpp>
#include <algorithm>
#include <cassert>
namespace llarp
{
RouterVersion::RouterVersion(const Version_t& router, uint64_t proto)
: m_Version(router), m_ProtoVersion(proto)
{
}
bool
RouterVersion::IsCompatableWith(const RouterVersion& other) const
{
return m_ProtoVersion == other.m_ProtoVersion;
}
bool
RouterVersion::BEncode(llarp_buffer_t* buf) const
{
if(not bencode_start_list(buf))
return false;
if(not IsEmpty())
{
if(not bencode_write_uint64(buf, m_ProtoVersion))
return false;
for(const auto& i : m_Version)
{
if(not bencode_write_uint64(buf, i))
return false;
}
}
return bencode_end(buf);
}
void
RouterVersion::Clear()
{
m_Version.fill(0);
m_ProtoVersion = LLARP_PROTO_VERSION;
assert(IsEmpty());
}
static const RouterVersion emptyRouterVersion({0, 0, 0}, LLARP_PROTO_VERSION);
bool
RouterVersion::IsEmpty() const
{
return *this == emptyRouterVersion;
}
bool
RouterVersion::BDecode(llarp_buffer_t* buf)
{
// clear before hand
Clear();
size_t idx = 0;
if(not bencode_read_list(
[self = this, &idx](llarp_buffer_t* buffer, bool has) {
if(has)
{
uint64_t i;
if(idx == 0)
{
if(not bencode_read_integer(buffer, &self->m_ProtoVersion))
return false;
}
else if(bencode_read_integer(buffer, &i))
{
self->m_Version[idx - 1] = i;
}
else
return false;
++idx;
}
return true;
},
buf))
return false;
// either full list or empty list is valid
return idx == 4 || idx == 0;
}
std::string
RouterVersion::ToString() const
{
return std::to_string(m_Version.at(0)) + "."
+ std::to_string(m_Version.at(1)) + "."
+ std::to_string(m_Version.at(2)) + " protocol version "
+ std::to_string(m_ProtoVersion);
}
} // namespace llarp

@ -0,0 +1,74 @@
#ifndef LLARP_ROUTER_VERSION_HPP
#define LLARP_ROUTER_VERSION_HPP
#include <array>
#include <util/bencode.hpp>
#include <constants/version.hpp>
#include <constants/proto.hpp>
namespace llarp
{
struct RouterVersion
{
using Version_t = std::array< uint16_t, 3 >;
RouterVersion() = default;
explicit RouterVersion(const Version_t& routerVersion,
uint64_t protoVersion);
bool
BEncode(llarp_buffer_t* buf) const;
bool
BDecode(llarp_buffer_t* buf);
/// return true if this router version is all zeros
bool
IsEmpty() const;
/// set to be empty
void
Clear();
std::string
ToString() const;
/// return true if the other router version is compatible with ours
bool
IsCompatableWith(const RouterVersion& other) const;
/// compare router versions
bool
operator<(const RouterVersion& other) const
{
return m_ProtoVersion < other.m_ProtoVersion
|| m_Version < other.m_Version;
}
bool
operator!=(const RouterVersion& other) const
{
return !(*this == other);
}
bool
operator==(const RouterVersion& other) const
{
return m_ProtoVersion == other.m_ProtoVersion
&& m_Version == other.m_Version;
}
private:
Version_t m_Version = {{0, 0, 0}};
uint64_t m_ProtoVersion = LLARP_PROTO_VERSION;
};
inline std::ostream&
operator<<(std::ostream& out, const RouterVersion& rv)
{
return out << rv.ToString();
}
} // namespace llarp
#endif

@ -10,10 +10,10 @@ namespace llarp
bool
DHTMessage::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
{
llarp::dht::Key_t fromKey;
fromKey.Zero();
if(key == "M")
{
llarp::dht::Key_t fromKey;
fromKey.Zero();
return llarp::dht::DecodeMesssageList(fromKey, val, M, true);
}
if(key == "S")
@ -49,7 +49,7 @@ namespace llarp
DHTMessage::HandleMessage(IMessageHandler* h, AbstractRouter* r) const
{
// set source as us
llarp::dht::Key_t us{r->pubkey()};
const llarp::dht::Key_t us(r->pubkey());
for(const auto& msg : M)
{
msg->From = us;

@ -1,5 +1,5 @@
#include <service/address.hpp>
#include <crypto/crypto.hpp>
#include <algorithm>
namespace llarp
@ -60,5 +60,14 @@ namespace llarp
// make sure it's lowercase
return Base32Decode(lowercase(sub, true), *this);
}
dht::Key_t
Address::ToKey() const
{
PubKey k;
CryptoManager::instance()->derive_subkey(k, PubKey(data()), 1);
return dht::Key_t{k.as_array()};
}
} // namespace service
} // namespace llarp

@ -14,7 +14,7 @@ namespace llarp
{
namespace service
{
/// Snapp/Snode Address
/// Snapp Address
struct Address : public AlignedBuffer< 32 >
{
/// if parsed using FromString this contains the subdomain
@ -35,21 +35,21 @@ namespace llarp
bool
FromString(const std::string& str, const char* tld = ".loki");
Address() : AlignedBuffer< SIZE >()
Address() : AlignedBuffer< 32 >()
{
}
explicit Address(const Data& buf) : AlignedBuffer< SIZE >(buf)
explicit Address(const Data& buf) : AlignedBuffer< 32 >(buf)
{
}
Address(const Address& other)
: AlignedBuffer< SIZE >(other.as_array()), subdomain(other.subdomain)
: AlignedBuffer< 32 >(other.as_array()), subdomain(other.subdomain)
{
}
explicit Address(const AlignedBuffer< SIZE >& other)
: AlignedBuffer< SIZE >(other)
explicit Address(const AlignedBuffer< 32 >& other)
: AlignedBuffer< 32 >(other)
{
}
@ -81,10 +81,7 @@ namespace llarp
operator=(const Address& other) = default;
dht::Key_t
ToKey() const
{
return dht::Key_t(as_array());
}
ToKey() const;
RouterID
ToRouter() const

@ -99,12 +99,13 @@ namespace llarp
return;
}
introSet().topic = m_state->m_Tag;
if(!m_Identity.SignIntroSet(introSet(), now))
auto maybe = m_Identity.EncryptAndSignIntroSet(introSet(), now);
if(not maybe.has_value())
{
LogWarn("failed to sign introset for endpoint ", Name());
LogWarn("failed to generate introset for endpoint ", Name());
return;
}
if(PublishIntroSet(Router()))
if(PublishIntroSet(maybe.value(), Router()))
{
LogInfo("(re)publishing introset for endpoint ", Name());
}
@ -204,48 +205,6 @@ namespace llarp
}
}
}
#ifdef TESTNET
// prefetch tags
for(const auto& tag : m_state->m_PrefetchTags)
{
auto itr = m_state->m_PrefetchedTags.find(tag);
if(itr == m_state->m_PrefetchedTags.end())
{
itr =
m_state->m_PrefetchedTags.emplace(tag, CachedTagResult(tag, this))
.first;
}
for(const auto& introset : itr->second.result)
{
if(HasPendingPathToService(introset.A.Addr()))
continue;
std::array< byte_t, 128 > tmp = {0};
llarp_buffer_t buf(tmp);
if(SendToServiceOrQueue(introset.A.Addr(), buf, eProtocolControl))
LogInfo(Name(), " send message to ", introset.A.Addr(), " for tag ",
tag.ToString());
else
LogWarn(Name(), " failed to send/queue data to ", introset.A.Addr(),
" for tag ", tag.ToString());
}
itr->second.Expire(now);
if(itr->second.ShouldRefresh(now))
{
auto path = PickRandomEstablishedPath();
if(path)
{
auto job = new TagLookupJob(this, &itr->second);
if(!job->SendRequestViaPath(path, Router()))
LogError(Name(), " failed to send tag lookup");
}
else
{
LogError(Name(), " has no paths for tag lookup");
}
}
}
#endif
// deregister dead sessions
EndpointUtil::DeregisterDeadSessions(now, m_state->m_DeadSessions);
@ -294,17 +253,16 @@ namespace llarp
bool
Endpoint::HandleGotIntroMessage(dht::GotIntroMessage_constptr msg)
{
std::set< IntroSet > remote;
std::set< EncryptedIntroSet > remote;
auto currentPub = m_state->m_CurrentPublishTX;
for(const auto& introset : msg->found)
{
if(!introset.Verify(Now()))
if(not introset.Verify(Now()))
{
if(m_Identity.pub == introset.A && currentPub == msg->txid)
IntroSetPublishFail();
return true;
LogError(Name(), " got invalid introset");
return false;
}
if(m_Identity.pub == introset.A && currentPub == msg->txid)
if(currentPub == msg->txid)
{
LogInfo(
"got introset publish confirmation for hidden service endpoint ",
@ -312,7 +270,6 @@ namespace llarp
IntroSetPublished();
return true;
}
remote.insert(introset);
}
auto& lookups = m_state->m_PendingLookups;
@ -501,19 +458,19 @@ namespace llarp
}
bool
Endpoint::PublishIntroSet(AbstractRouter* r)
Endpoint::PublishIntroSet(const EncryptedIntroSet& i, AbstractRouter* r)
{
// publish via near router
RouterID location = m_Identity.pub.Addr().as_array();
auto path = GetEstablishedPathClosestTo(location);
return path && PublishIntroSetVia(r, path);
const auto path = GetEstablishedPathClosestTo(i.derivedSigningKey);
return path && PublishIntroSetVia(i, r, path);
}
struct PublishIntroSetJob : public IServiceLookup
{
IntroSet m_IntroSet;
EncryptedIntroSet m_IntroSet;
Endpoint* m_Endpoint;
PublishIntroSetJob(Endpoint* parent, uint64_t id, IntroSet introset)
PublishIntroSetJob(Endpoint* parent, uint64_t id,
EncryptedIntroSet introset)
: IServiceLookup(parent, id, "PublishIntroSet")
, m_IntroSet(std::move(introset))
, m_Endpoint(parent)
@ -530,9 +487,9 @@ namespace llarp
}
bool
HandleResponse(const std::set< IntroSet >& response) override
HandleResponse(const std::set< EncryptedIntroSet >& response) override
{
if(response.size())
if(not response.empty())
m_Endpoint->IntroSetPublished();
else
m_Endpoint->IntroSetPublishFail();
@ -557,9 +514,10 @@ namespace llarp
}
bool
Endpoint::PublishIntroSetVia(AbstractRouter* r, path::Path_ptr path)
Endpoint::PublishIntroSetVia(const EncryptedIntroSet& i, AbstractRouter* r,
path::Path_ptr path)
{
auto job = new PublishIntroSetJob(this, GenTXID(), introSet());
auto job = new PublishIntroSetJob(this, GenTXID(), i);
if(job->SendRequestViaPath(path, r))
{
m_state->m_LastPublishAttempt = Now();
@ -952,13 +910,14 @@ namespace llarp
}
bool
Endpoint::OnLookup(const Address& addr, const IntroSet* introset,
Endpoint::OnLookup(const Address& addr,
absl::optional< const IntroSet > introset,
const RouterID& endpoint)
{
const auto now = Router()->Now();
auto& fails = m_state->m_ServiceLookupFails;
auto& lookups = m_state->m_PendingServiceLookups;
if(introset == nullptr || introset->IsExpired(now))
if(not introset.has_value() || introset->IsExpired(now))
{
LogError(Name(), " failed to lookup ", addr.ToString(), " from ",
endpoint);
@ -973,8 +932,7 @@ namespace llarp
}
return false;
}
PutNewOutboundContext(*introset);
PutNewOutboundContext(introset.value());
return true;
}
@ -983,11 +941,12 @@ namespace llarp
ABSL_ATTRIBUTE_UNUSED llarp_time_t timeoutMS,
bool randomPath)
{
path::Path_ptr path = nullptr;
const dht::Key_t location = remote.ToKey();
path::Path_ptr path = nullptr;
if(randomPath)
path = PickRandomEstablishedPath();
else
path = GetEstablishedPathClosestTo(remote.ToRouter());
path = GetEstablishedPathClosestTo(location.as_array());
if(!path)
{
LogWarn("No outbound path for lookup yet");
@ -1017,7 +976,8 @@ namespace llarp
using namespace std::placeholders;
HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup(
this, util::memFn(&Endpoint::OnLookup, this), remote, GenTXID());
this, util::memFn(&Endpoint::OnLookup, this), location,
PubKey{remote.as_array()}, GenTXID());
LogInfo("doing lookup for ", remote, " via ", path->Endpoint());
if(job->SendRequestViaPath(path, Router()))
{

@ -168,10 +168,11 @@ namespace llarp
HandlePathDied(path::Path_ptr p) override;
bool
PublishIntroSet(AbstractRouter* r) override;
PublishIntroSet(const EncryptedIntroSet& i, AbstractRouter* r) override;
bool
PublishIntroSetVia(AbstractRouter* r, path::Path_ptr p);
PublishIntroSetVia(const EncryptedIntroSet& i, AbstractRouter* r,
path::Path_ptr p);
bool
HandleGotIntroMessage(
@ -410,7 +411,7 @@ namespace llarp
llarp_async_verify_rc* j);
bool
OnLookup(const service::Address& addr, const IntroSet* i,
OnLookup(const service::Address& addr, absl::optional< const IntroSet > i,
const RouterID& endpoint); /* */
bool

@ -10,28 +10,36 @@ namespace llarp
{
HiddenServiceAddressLookup::HiddenServiceAddressLookup(Endpoint* p,
HandlerFunc h,
const Address& addr,
const dht::Key_t& l,
const PubKey& k,
uint64_t tx)
: IServiceLookup(p, tx, "HSLookup"), remote(addr), handle(std::move(h))
: IServiceLookup(p, tx, "HSLookup")
, rootkey(k)
, location(l)
, handle(std::move(h))
{
}
bool
HiddenServiceAddressLookup::HandleResponse(
const std::set< IntroSet >& results)
const std::set< EncryptedIntroSet >& results)
{
absl::optional< IntroSet > found;
const Address remote(rootkey);
LogInfo("found ", results.size(), " for ", remote.ToString());
if(results.size() > 0)
{
IntroSet selected;
EncryptedIntroSet selected;
for(const auto& introset : results)
{
if(selected.OtherIsNewer(introset) && introset.A.Addr() == remote)
if(selected.OtherIsNewer(introset))
selected = introset;
}
return handle(remote, &selected, endpoint);
const auto maybe = selected.MaybeDecrypt(rootkey);
if(maybe.has_value())
found = maybe.value();
}
return handle(remote, nullptr, endpoint);
return handle(remote, found, endpoint);
}
std::shared_ptr< routing::IMessage >
@ -39,7 +47,7 @@ namespace llarp
{
auto msg = std::make_shared< routing::DHTMessage >();
msg->M.emplace_back(std::make_unique< dht::FindIntroMessage >(
txid, remote, dht::FindIntroMessage::MaxRecursionDepth));
txid, location, dht::FindIntroMessage::MaxRecursionDepth));
return msg;
}

@ -12,18 +12,20 @@ namespace llarp
struct Endpoint;
struct HiddenServiceAddressLookup : public IServiceLookup
{
Address remote;
using HandlerFunc = std::function< bool(const Address&, const IntroSet*,
const RouterID&) >;
const PubKey rootkey;
const dht::Key_t location;
using HandlerFunc = std::function< bool(
const Address&, absl::optional< const IntroSet >, const RouterID&) >;
HandlerFunc handle;
HiddenServiceAddressLookup(Endpoint* p, HandlerFunc h,
const Address& addr, uint64_t tx);
const dht::Key_t& location,
const PubKey& rootkey, uint64_t tx);
~HiddenServiceAddressLookup() override = default;
bool
HandleResponse(const std::set< IntroSet >& results) override;
HandleResponse(const std::set< EncryptedIntroSet >& results) override;
std::shared_ptr< routing::IMessage >
BuildRequestMessage() override;

@ -2,6 +2,7 @@
#include <crypto/crypto.hpp>
#include <util/fs.hpp>
#include <sodium/crypto_sign_ed25519.h>
namespace llarp
{
@ -57,10 +58,14 @@ namespace llarp
Identity::RegenerateKeys()
{
auto crypto = CryptoManager::instance();
crypto->encryption_keygen(enckey);
crypto->identity_keygen(signkey);
pub.Update(seckey_topublic(enckey), seckey_topublic(signkey));
crypto_sign_ed25519_sk_to_curve25519(enckey.data(), signkey.data());
pub.Update(seckey_topublic(signkey));
crypto->pqe_keygen(pq);
if(not crypto->derive_subkey_private(derivedSignKey, signkey, 1))
{
LogError("failed to generate derived key");
}
}
bool
@ -141,32 +146,44 @@ namespace llarp
if(!vanity.IsZero())
van = vanity;
// update pubkeys
pub.Update(seckey_topublic(enckey), seckey_topublic(signkey), van);
return true;
pub.Update(seckey_topublic(signkey), van);
crypto_sign_ed25519_sk_to_curve25519(enckey.data(), signkey.data());
auto crypto = CryptoManager::instance();
return crypto->derive_subkey_private(derivedSignKey, signkey, 1);
}
bool
Identity::SignIntroSet(IntroSet& i, llarp_time_t now) const
absl::optional< EncryptedIntroSet >
Identity::EncryptAndSignIntroSet(const IntroSet& other_i,
llarp_time_t now) const
{
if(i.I.size() == 0)
return false;
EncryptedIntroSet encrypted;
if(other_i.I.size() == 0)
return {};
IntroSet i(other_i);
encrypted.nounce.Randomize();
// set timestamp
// TODO: round to nearest 1000 ms
i.T = now;
i.T = now;
encrypted.signedAt = now;
// set service info
i.A = pub;
// set public encryption key
i.K = pq_keypair_to_public(pq);
// zero out signature for signing process
i.Z.Zero();
std::array< byte_t, MAX_INTROSET_SIZE > tmp;
llarp_buffer_t buf(tmp);
if(!i.BEncode(&buf))
return false;
if(not i.BEncode(&buf))
return {};
// rewind and resize buffer
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return Sign(i.Z, buf);
const SharedSecret k(i.A.Addr());
CryptoManager::instance()->xchacha20(buf, k, encrypted.nounce);
encrypted.introsetPayload.resize(buf.sz);
std::copy_n(buf.base, buf.sz, encrypted.introsetPayload.data());
if(not encrypted.Sign(derivedSignKey))
return {};
return encrypted;
}
} // namespace service
} // namespace llarp

@ -21,6 +21,7 @@ namespace llarp
{
SecretKey enckey;
SecretKey signkey;
PrivateKey derivedSignKey;
PQKeyPair pq;
uint64_t version = LLARP_PROTO_VERSION;
VanityNonce vanity;
@ -46,8 +47,8 @@ namespace llarp
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf);
bool
SignIntroSet(IntroSet& i, llarp_time_t now) const;
absl::optional< EncryptedIntroSet >
EncryptAndSignIntroSet(const IntroSet& i, llarp_time_t now) const;
bool
Sign(Signature& sig, const llarp_buffer_t& buf) const;

@ -7,6 +7,7 @@
#include <cassert>
#include <sodium/crypto_generichash.h>
#include <sodium/crypto_sign_ed25519.h>
namespace llarp
{
@ -19,6 +20,19 @@ namespace llarp
return CryptoManager::instance()->verify(signkey, payload, sig);
}
bool
ServiceInfo::Update(const byte_t* pubkey, const OptNonce& nonce)
{
signkey = pubkey;
if(crypto_sign_ed25519_pk_to_curve25519(enckey.data(), pubkey) == -1)
return false;
if(nonce)
{
vanity = nonce.value();
}
return UpdateAddr();
}
bool
ServiceInfo::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* val)
{
@ -67,13 +81,8 @@ namespace llarp
bool ServiceInfo::CalculateAddress(std::array< byte_t, 32 >& data) const
{
std::array< byte_t, 256 > tmp;
llarp_buffer_t buf(tmp);
if(!BEncode(&buf))
return false;
return crypto_generichash_blake2b(data.data(), data.size(), buf.base,
buf.cur - buf.base, nullptr, 0)
!= -1;
data = signkey.as_array();
return true;
}
bool

@ -45,17 +45,7 @@ namespace llarp
}
bool
Update(const byte_t* enc, const byte_t* sign,
const OptNonce& nonce = OptNonce())
{
enckey = enc;
signkey = sign;
if(nonce)
{
vanity = nonce.value();
}
return UpdateAddr();
}
Update(const byte_t* pubkey, const OptNonce& nonce = OptNonce());
bool
operator==(const ServiceInfo& other) const

@ -1,11 +1,144 @@
#include <service/intro_set.hpp>
#include <crypto/crypto.hpp>
#include <path/path.hpp>
namespace llarp
{
namespace service
{
util::StatusObject
EncryptedIntroSet::ExtractStatus() const
{
const auto sz = introsetPayload.size();
return {{"location", derivedSigningKey.ToString()},
{"signedAt", signedAt},
{"size", sz}};
}
bool
EncryptedIntroSet::BEncode(llarp_buffer_t* buf) const
{
if(not bencode_start_dict(buf))
return false;
if(not BEncodeWriteDictEntry("d", derivedSigningKey, buf))
return false;
if(not BEncodeWriteDictEntry("n", nounce, buf))
return false;
if(not BEncodeWriteDictInt("s", signedAt, buf))
return false;
if(not bencode_write_bytestring(buf, "x", 1))
return false;
if(not bencode_write_bytestring(buf, introsetPayload.data(),
introsetPayload.size()))
return false;
if(not BEncodeWriteDictEntry("z", sig, buf))
return false;
return bencode_end(buf);
}
bool
EncryptedIntroSet::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
bool read = false;
if(key == "x")
{
llarp_buffer_t strbuf;
if(not bencode_read_string(buf, &strbuf))
return false;
if(strbuf.sz > MAX_INTROSET_SIZE)
return false;
introsetPayload.resize(strbuf.sz);
std::copy_n(strbuf.base, strbuf.sz, introsetPayload.data());
return true;
}
if(not BEncodeMaybeReadDictEntry("d", derivedSigningKey, read, key, buf))
return false;
if(not BEncodeMaybeReadDictEntry("n", nounce, read, key, buf))
return false;
if(not BEncodeMaybeReadDictInt("s", signedAt, read, key, buf))
return false;
if(not BEncodeMaybeReadDictEntry("z", sig, read, key, buf))
return false;
return read;
}
bool
EncryptedIntroSet::OtherIsNewer(const EncryptedIntroSet& other) const
{
return signedAt < other.signedAt;
}
std::ostream&
EncryptedIntroSet::print(std::ostream& out, int levels, int spaces) const
{
Printer printer(out, levels, spaces);
printer.printAttribute("d", derivedSigningKey);
printer.printAttribute("n", nounce);
printer.printAttribute("s", signedAt);
printer.printAttribute(
"x", "[" + std::to_string(introsetPayload.size()) + " bytes]");
printer.printAttribute("z", sig);
return out;
}
absl::optional< IntroSet >
EncryptedIntroSet::MaybeDecrypt(const PubKey& root) const
{
SharedSecret k(root);
IntroSet i;
std::vector< byte_t > payload = introsetPayload;
llarp_buffer_t buf(payload);
CryptoManager::instance()->xchacha20(buf, k, nounce);
if(not i.BDecode(&buf))
return {};
return i;
}
bool
EncryptedIntroSet::IsExpired(llarp_time_t now) const
{
return now >= signedAt + path::default_lifetime;
}
bool
EncryptedIntroSet::Sign(const PrivateKey& k)
{
signedAt = llarp::time_now_ms();
if(not k.toPublic(derivedSigningKey))
return false;
sig.Zero();
std::array< byte_t, MAX_INTROSET_SIZE + 128 > tmp;
llarp_buffer_t buf(tmp);
if(not BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
if(not CryptoManager::instance()->sign(sig, k, buf))
return false;
LogInfo("signed encrypted introset: ", *this);
return true;
}
bool
EncryptedIntroSet::Verify(llarp_time_t now) const
{
if(IsExpired(now))
return false;
std::array< byte_t, MAX_INTROSET_SIZE + 128 > tmp;
llarp_buffer_t buf(tmp);
EncryptedIntroSet copy(*this);
copy.sig.Zero();
if(not copy.BEncode(&buf))
return false;
LogInfo("verify encrypted introset: ", copy, " sig = ", sig);
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return CryptoManager::instance()->verify(derivedSigningKey, buf, sig);
}
util::StatusObject
IntroSet::ExtractStatus() const
{

@ -23,6 +23,7 @@ namespace llarp
constexpr std::size_t MAX_INTROSET_SIZE = 4096;
// 10 seconds clock skew permitted for introset expiration
constexpr llarp_time_t MAX_INTROSET_TIME_DELTA = (10 * 1000);
struct IntroSet
{
ServiceInfo A;
@ -101,6 +102,80 @@ namespace llarp
return i.print(out, -1, -1);
}
/// public version of the introset that is encrypted
struct EncryptedIntroSet
{
using Payload_t = std::vector< byte_t >;
PubKey derivedSigningKey;
llarp_time_t signedAt = 0;
Payload_t introsetPayload;
TunnelNonce nounce;
absl::optional< Tag > topic;
Signature sig;
bool
Sign(const PrivateKey& k);
bool
IsExpired(llarp_time_t now) const;
bool
BEncode(llarp_buffer_t* buf) const;
bool
BDecode(llarp_buffer_t* buf)
{
return bencode_decode_dict(*this, buf);
}
bool
DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf);
bool
OtherIsNewer(const EncryptedIntroSet& other) const;
/// verify signature and timestamp
bool
Verify(llarp_time_t now) const;
std::ostream&
print(std::ostream& stream, int level, int spaces) const;
util::StatusObject
ExtractStatus() const;
absl::optional< IntroSet >
MaybeDecrypt(const PubKey& rootKey) const;
};
inline std::ostream&
operator<<(std::ostream& out, const EncryptedIntroSet& i)
{
return i.print(out, -1, -1);
}
inline bool
operator<(const EncryptedIntroSet& lhs, const EncryptedIntroSet& rhs)
{
return lhs.derivedSigningKey < rhs.derivedSigningKey;
}
inline bool
operator==(const EncryptedIntroSet& lhs, const EncryptedIntroSet& rhs)
{
return std::tie(lhs.signedAt, lhs.derivedSigningKey, lhs.nounce, lhs.sig)
== std::tie(rhs.signedAt, rhs.derivedSigningKey, rhs.nounce, rhs.sig);
}
inline bool
operator!=(const EncryptedIntroSet& lhs, const EncryptedIntroSet& rhs)
{
return !(lhs == rhs);
}
using EncryptedIntroSetLookupHandler =
std::function< void(const std::vector< EncryptedIntroSet >&) >;
using IntroSetLookupHandler =
std::function< void(const std::vector< IntroSet >&) >;

@ -28,8 +28,7 @@ namespace llarp
/// handle lookup result
virtual bool
HandleResponse(__attribute__((unused))
const std::set< IntroSet >& results)
HandleResponse(const std::set< EncryptedIntroSet >&)
{
return false;
}

@ -56,6 +56,7 @@ namespace llarp
OutboundContext::OutboundContext(const IntroSet& introset, Endpoint* parent)
: path::Builder(parent->Router(), 4, path::default_len)
, SendContext(introset.A, {}, this, parent)
, location(introset.A.Addr().ToKey())
, currentIntroSet(introset)
{
@ -83,15 +84,14 @@ namespace llarp
}
bool
OutboundContext::OnIntroSetUpdate(__attribute__((unused))
const Address& addr,
const IntroSet* i,
OutboundContext::OnIntroSetUpdate(const Address&,
absl::optional< const IntroSet > i,
const RouterID& endpoint)
{
if(markedBad)
return true;
updatingIntroSet = false;
if(i)
if(i.has_value())
{
if(currentIntroSet.T >= i->T)
{
@ -105,7 +105,7 @@ namespace llarp
LogError("got expired introset from lookup from ", endpoint);
return true;
}
currentIntroSet = *i;
currentIntroSet = i.value();
}
else
{
@ -238,7 +238,7 @@ namespace llarp
HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup(
m_Endpoint,
util::memFn(&OutboundContext::OnIntroSetUpdate, shared_from_this()),
addr, m_Endpoint->GenTXID());
location, PubKey{addr.as_array()}, m_Endpoint->GenTXID());
updatingIntroSet = job->SendRequestViaPath(path, m_Endpoint->Router());
}

@ -115,9 +115,10 @@ namespace llarp
OnGeneratedIntroFrame(AsyncKeyExchange* k, PathID_t p);
bool
OnIntroSetUpdate(const Address& addr, const IntroSet* i,
OnIntroSetUpdate(const Address& addr, absl::optional< const IntroSet > i,
const RouterID& endpoint);
const dht::Key_t location;
uint64_t m_UpdateIntrosetTX = 0;
IntroSet currentIntroSet;
Introduction m_NextIntro;

@ -9,17 +9,8 @@ namespace llarp
namespace service
{
bool
CachedTagResult::HandleResponse(const std::set< IntroSet >& introsets)
CachedTagResult::HandleResponse(const std::set< EncryptedIntroSet >&)
{
auto now = m_parent->Now();
for(const auto& introset : introsets)
if(result.insert(introset).second)
lastModified = now;
LogInfo("Tag result for ", tag.ToString(), " got ", introsets.size(),
" results from lookup, have ", result.size(),
" cached last modified at ", lastModified, " is ",
now - lastModified, "ms old");
return true;
}
@ -29,9 +20,8 @@ namespace llarp
auto itr = result.begin();
while(itr != result.end())
{
if(itr->HasExpiredIntros(now))
if(itr->IsExpired(now))
{
LogInfo("Removing expired tag Entry ", itr->A.Name());
itr = result.erase(itr);
lastModified = now;
}

@ -20,7 +20,7 @@ namespace llarp
const static llarp_time_t TTL = 10000;
llarp_time_t lastRequest = 0;
llarp_time_t lastModified = 0;
std::set< IntroSet > result;
std::set< EncryptedIntroSet > result;
Tag tag;
Endpoint* m_parent;
@ -45,7 +45,7 @@ namespace llarp
BuildRequestMessage(uint64_t txid);
bool
HandleResponse(const std::set< IntroSet >& results);
HandleResponse(const std::set< EncryptedIntroSet >& results);
};
struct TagLookupJob : public IServiceLookup
@ -61,7 +61,7 @@ namespace llarp
}
bool
HandleResponse(const std::set< IntroSet >& results) override
HandleResponse(const std::set< EncryptedIntroSet >& results) override
{
return m_result->HandleResponse(results);
}

@ -11,6 +11,10 @@ namespace llarp
template < typename Val_t, typename Hash_t = typename Val_t::Hash >
struct DecayingHashSet
{
DecayingHashSet(std::chrono::milliseconds cacheInterval)
: DecayingHashSet(cacheInterval.count())
{
}
DecayingHashSet(llarp_time_t cacheInterval = 5000)
: m_CacheInterval(cacheInterval)
{
@ -30,7 +34,7 @@ namespace llarp
{
if(now == 0)
now = llarp::time_now_ms();
return m_Values.emplace(v, now + m_CacheInterval).second;
return m_Values.emplace(v, now).second;
}
/// decay hashset entries
@ -42,7 +46,7 @@ namespace llarp
auto itr = m_Values.begin();
while(itr != m_Values.end())
{
if(itr->second <= now)
if((m_CacheInterval + itr->second) <= now)
itr = m_Values.erase(itr);
else
++itr;
@ -55,8 +59,14 @@ namespace llarp
return m_CacheInterval;
}
void
DecayInterval(llarp_time_t interval)
{
m_CacheInterval = interval;
}
private:
const llarp_time_t m_CacheInterval;
llarp_time_t m_CacheInterval;
std::unordered_map< Val_t, llarp_time_t, Hash_t > m_Values;
};
} // namespace util

@ -85,7 +85,7 @@ namespace llarp
LogContext();
LogLevel curLevel = eLogInfo;
LogLevel startupLevel = eLogInfo;
LogLevel runtimeLevel = eLogWarn;
LogLevel runtimeLevel = eLogInfo;
ILogStream_ptr logStream;
std::string nodeName = "lokinet";
@ -106,13 +106,12 @@ namespace llarp
/** internal */
template < typename... TArgs >
void
inline static void
_Log(LogLevel lvl, const char* fname, int lineno, TArgs&&... args) noexcept
{
auto& log = LogContext::Instance();
if(log.curLevel > lvl)
return;
std::stringstream ss;
LogAppend(ss, std::forward< TArgs >(args)...);
log.logStream->AppendLog(lvl, fname, lineno, log.nodeName, ss.str());

@ -2,6 +2,7 @@
#define LLARP_TIME_HPP
#include <util/types.hpp>
#include <chrono>
namespace llarp
{

@ -70,7 +70,7 @@ Build requirements:
* C++ 14 capable C++ compiler
* gcovr (if generating test coverage with gcc)
* libuv >= 1.27.0
* libsodium >= 1.0.17
* libsodium >= 1.0.18
* libcurl
### Linux

@ -70,7 +70,8 @@ Requerimientos de compilación:
* Compilador C++ que pueda usar C++ 17
* gcovr (para generar la covertura de prueba en gcc)
* libuv >= 1.27.0
* libsodium
* libsodium >= 1.0.18
* libcurl
### Linux

@ -43,9 +43,14 @@ namespace llarp
bool(byte_t *, const llarp_buffer_t &,
const SharedSecret &));
MOCK_METHOD3(sign,
bool(Signature &, const SecretKey &,
const llarp_buffer_t &));
MOCK_METHOD4(derive_subkey, bool(PubKey &, const PubKey &, uint64_t, const AlignedBuffer<32> *));
MOCK_METHOD4(derive_subkey_private,
bool(PrivateKey &, const SecretKey &, uint64_t, const AlignedBuffer<32> *));
MOCK_METHOD(bool, sign, (Signature &, const SecretKey &, const llarp_buffer_t &));
MOCK_METHOD(bool, sign, (Signature &, const PrivateKey &, const llarp_buffer_t &));
MOCK_METHOD3(verify,
bool(const PubKey &, const llarp_buffer_t &,
@ -70,7 +75,7 @@ namespace llarp
MOCK_METHOD3(pqe_encrypt,
bool(PQCipherBlock &, SharedSecret &, const PQPubKey &));
MOCK_METHOD1(check_identity_privkey, bool(const SecretKey&));
MOCK_METHOD1(check_identity_privkey, bool(const SecretKey &));
};
} // namespace test
} // namespace llarp

@ -20,35 +20,23 @@ namespace llarp
const dht::Key_t&, RouterLookupHandler));
MOCK_METHOD6(LookupIntroSetRecursive,
void(const service::Address&, const dht::Key_t&, uint64_t,
void(const dht::Key_t&, const dht::Key_t&, uint64_t,
const dht::Key_t&, uint64_t,
service::IntroSetLookupHandler));
service::EncryptedIntroSetLookupHandler));
MOCK_METHOD5(LookupIntroSetIterative,
void(const service::Address&, const dht::Key_t&, uint64_t,
const dht::Key_t&, service::IntroSetLookupHandler));
MOCK_METHOD3(
FindRandomIntroSetsWithTagExcluding,
std::set< service::IntroSet >(const service::Tag&, size_t,
const std::set< service::IntroSet >&));
void(const dht::Key_t&, const dht::Key_t&, uint64_t,
const dht::Key_t&,
service::EncryptedIntroSetLookupHandler));
MOCK_CONST_METHOD1(HasRouterLookup, bool(const RouterID& target));
MOCK_METHOD5(LookupTagRecursive,
void(const service::Tag&, const dht::Key_t&, uint64_t,
const dht::Key_t&, uint64_t));
MOCK_METHOD4(LookupTagForPath,
void(const service::Tag&, uint64_t, const PathID_t&,
const dht::Key_t&));
MOCK_METHOD4(LookupRouterForPath,
void(const RouterID& target, uint64_t txid,
const PathID_t& path, const dht::Key_t& askpeer));
MOCK_METHOD5(LookupIntroSetForPath,
void(const service::Address&, uint64_t, const PathID_t&,
void(const dht::Key_t&, uint64_t, const PathID_t&,
const dht::Key_t&, uint64_t));
MOCK_METHOD3(DHTSendTo, void(const RouterID&, dht::IMessage*, bool));
@ -73,16 +61,16 @@ namespace llarp
MOCK_METHOD6(PropagateIntroSetTo,
void(const dht::Key_t& source, uint64_t sourceTX,
const service::IntroSet& introset,
const service::EncryptedIntroSet& introset,
const dht::Key_t& peer, uint64_t S,
const std::set< dht::Key_t >& exclude));
MOCK_METHOD3(Init,
void(const dht::Key_t&, AbstractRouter*, llarp_time_t));
MOCK_CONST_METHOD1(
GetIntroSetByServiceAddress,
const llarp::service::IntroSet*(const llarp::service::Address&));
MOCK_CONST_METHOD1(GetIntroSetByLocation,
absl::optional< llarp::service::EncryptedIntroSet >(
const llarp::dht::Key_t&));
MOCK_CONST_METHOD0(ExtractStatus, util::StatusObject());
@ -98,10 +86,6 @@ namespace llarp
const PendingIntrosetLookups&());
MOCK_METHOD0(pendingIntrosetLookups, PendingIntrosetLookups&());
MOCK_METHOD0(pendingTagLookups, PendingTagLookups&());
MOCK_CONST_METHOD0(pendingTagLookups, const PendingTagLookups&());
MOCK_METHOD0(pendingRouterLookups, PendingRouterLookups&());
MOCK_CONST_METHOD0(pendingRouterLookups, const PendingRouterLookups&());
@ -118,6 +102,8 @@ namespace llarp
MOCK_CONST_METHOD0(Nodes, dht::Bucket< dht::RCNode >*());
MOCK_METHOD1(PutRCNodeAsync, void(const dht::RCNode& val));
MOCK_METHOD1(DelRCNodeAsync, void(const dht::Key_t& val));
MOCK_METHOD2(FloodRCLater, void(const dht::Key_t, const RouterContact));
};
} // namespace test

@ -72,19 +72,18 @@ TEST_F(TestDhtISNode, construct)
ASSERT_THAT(node.ID, Property(&dht::Key_t::IsZero, true));
node.ID.Fill(0xCA);
node.introset.K.Fill(0xDB);
node.introset.derivedSigningKey.Fill(0xDB);
dht::ISNode other{node};
ASSERT_EQ(node.ID, other.ID);
ASSERT_EQ(node.introset, other.introset);
service::IntroSet introSet;
introSet.K.Randomize();
introSet.A.UpdateAddr();
service::EncryptedIntroSet introSet;
introSet.derivedSigningKey.Randomize();
dht::ISNode fromIntro{introSet};
ASSERT_EQ(fromIntro.ID.as_array(), introSet.A.Addr().as_array());
ASSERT_EQ(fromIntro.ID.as_array(), introSet.derivedSigningKey);
}
TEST_F(TestDhtISNode, lt)
@ -94,10 +93,10 @@ TEST_F(TestDhtISNode, lt)
dht::ISNode three;
dht::ISNode eqThree;
one.introset.T = 1;
two.introset.T = 2;
three.introset.T = 3;
eqThree.introset.T = 3;
one.introset.signedAt = 1;
two.introset.signedAt = 2;
three.introset.signedAt = 3;
eqThree.introset.signedAt = 3;
// LT cases
ASSERT_THAT(one, Lt(two));

@ -10,6 +10,8 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#if 0
using namespace llarp;
using namespace ::testing;
@ -17,7 +19,7 @@ using test::makeBuf;
struct MockIntroSetHandler
{
MOCK_METHOD1(call, void(const std::vector< service::IntroSet > &));
MOCK_METHOD1(call, void(const std::vector< service::EncryptedIntroSet > &));
};
static constexpr uint64_t EXPIRY = 1548503831ull;
@ -59,9 +61,8 @@ TEST_F(TestDhtServiceAddressLookup, validate)
// - introset fails to verify
// - introset topic is not the target
// - happy path
{
service::IntroSet introset;
service::EncryptedIntroSet introset;
EXPECT_CALL(context, Now()).WillOnce(Return(EXPIRY));
EXPECT_CALL(m_crypto, verify(_, _, _)).WillOnce(Return(false));
@ -217,3 +218,5 @@ TEST_F(TestDhtServiceAddressLookup, send_reply)
ASSERT_NO_THROW(serviceAddressLookup->SendReply());
}
}
#endif

@ -8,7 +8,7 @@
#include <test_util.hpp>
#include <gtest/gtest.h>
#if 0
using namespace llarp;
using namespace ::testing;
@ -228,3 +228,5 @@ TEST_F(TestDhtTagLookup, send_reply)
ASSERT_NO_THROW(tagLookup.SendReply());
}
}
#endif

@ -1,5 +1,6 @@
#include <crypto/crypto.hpp>
#include <crypto/crypto_libsodium.hpp>
#include <sodium/crypto_scalarmult_ed25519.h>
#include <llarp_test.hpp>
#include <path/path.hpp>
#include <service/address.hpp>
@ -37,11 +38,13 @@ TEST_F(HiddenServiceTest, TestGenerateIntroSet)
I.I.emplace_back(std::move(intro));
}
EXPECT_CALL(m_crypto, sign(I.Z, _, _)).WillOnce(Return(true));
using ::testing::Matcher;
EXPECT_CALL(m_crypto, sign(I.Z, Matcher<const SecretKey &>(_), _)).WillOnce(Return(true));
EXPECT_CALL(m_crypto, verify(_, _, I.Z)).WillOnce(Return(true));
ASSERT_TRUE(ident.SignIntroSet(I, now));
ASSERT_TRUE(I.Verify(now));
EXPECT_CALL(m_crypto, xchacha20(_, _, _)).WillOnce(Return(true));
const auto maybe = ident.EncryptAndSignIntroSet(I, now);
ASSERT_TRUE(maybe.has_value());
ASSERT_TRUE(maybe->Verify(now));
}
TEST_F(HiddenServiceTest, TestAddressToFromString)
@ -73,8 +76,10 @@ TEST_F(ServiceIdentityTest, EnsureKeys)
test::FileGuard guard(p);
EXPECT_CALL(m_crypto, encryption_keygen(_))
.WillOnce(WithArg< 0 >(FillArg< SecretKey >(0x01)));
const SecretKey k;
EXPECT_CALL(m_crypto, derive_subkey_private(_, _, _, _))
.WillRepeatedly(Return(true));
EXPECT_CALL(m_crypto, identity_keygen(_))
.WillOnce(WithArg< 0 >(FillArg< SecretKey >(0x02)));
@ -122,3 +127,198 @@ TEST_F(ServiceIdentityTest, EnsureKeysBrokenFile)
service::Identity identity;
ASSERT_FALSE(identity.EnsureKeys(p.string(), false));
}
struct RealCryptographyTest : public ::testing::Test
{
std::unique_ptr< CryptoManager > _manager;
void
SetUp()
{
_manager = std::make_unique< CryptoManager >(new sodium::CryptoLibSodium());
}
void
TearDown()
{
_manager.reset();
}
};
TEST_F(RealCryptographyTest, TestKnownDerivation)
{
// These values came out of a run of Tor's test code, so that we can confirm we are doing the same
// blinding subkey crypto math as Tor. Our hash value is generated differently so we use the hash
// from a Tor random test suite run.
AlignedBuffer<32> seed{{
0xd0, 0x98, 0x9d, 0x83, 0x0e, 0x03, 0xe1, 0x4e, 0xf6, 0xaf, 0x71, 0xa0, 0xa1, 0xfc, 0x88, 0x38, 0xac, 0xfc, 0xd8, 0x95, 0x06, 0x54, 0x9f, 0x3e, 0xdb, 0xb0, 0xf5, 0x3a, 0xc9, 0x0e, 0x47, 0x90,
}};
AlignedBuffer<64> root_key_data{{
0xc0, 0xe6, 0x58, 0xd6, 0x01, 0xc1, 0xb4, 0xc2, 0x94, 0xb8, 0xf7, 0xa3, 0xec, 0x3e, 0x81, 0xd6, 0x82, 0xb4, 0x89, 0x5c, 0x6d, 0xbf, 0x5c, 0x6e, 0x20, 0xad, 0x39, 0x8f, 0xf4, 0x8f, 0x43, 0x4f,
0x56, 0x4f, 0xdc, 0x22, 0x33, 0x19, 0xb9, 0xbb, 0x4e, 0xc0, 0xba, 0x84, 0x2d, 0xe3, 0xde, 0xf2, 0x26, 0xe8, 0xf7, 0xa8, 0x8f, 0x82, 0x41, 0xe3, 0x1f, 0x5d, 0xe5, 0x56, 0x3a, 0xf4, 0x5e, 0x3c,
}};
AlignedBuffer<32> root_pub_data{{
0x4a, 0x34, 0x3f, 0x9e, 0xf3, 0xda, 0x3d, 0x80, 0x07, 0xc7, 0x09, 0xf9, 0x2f, 0x72, 0xd3, 0x76, 0x56, 0x5a, 0x4c, 0x13, 0xdf, 0xb8, 0xce, 0xc8, 0x53, 0x77, 0x0a, 0x99, 0xbc, 0x06, 0xa7, 0xc0,
}};
AlignedBuffer<32> hash{{
0x64, 0xad, 0xde, 0x17, 0x69, 0x33, 0x92, 0x25, 0x9c, 0xa3, 0xd7, 0x85, 0xa5, 0x2d, 0x3a, 0xa5, 0xa3, 0x9c, 0xdb, 0x99, 0x57, 0xac, 0x54, 0x14, 0x4f, 0x11, 0xa9, 0x90, 0xa0, 0xca, 0xcb, 0xfe,
}};
AlignedBuffer<64> derived_key_data{{
0x96, 0x02, 0xba, 0x16, 0x87, 0x40, 0xb7, 0xb6, 0xc9, 0x0f, 0x85, 0x7b, 0xdc, 0xa9, 0x13, 0x9d, 0x1b, 0xf5, 0x01, 0x54, 0xd1, 0xd1, 0x8f, 0x75, 0x06, 0x4d, 0x4c, 0xea, 0x33, 0xc4, 0xc6, 0x00,
0xb0, 0xef, 0x29, 0x37, 0x7c, 0xe9, 0x84, 0x43, 0x5a, 0x79, 0xa2, 0x3b, 0xef, 0xcd, 0x1c, 0x43, 0xf1, 0x88, 0xff, 0x50, 0xaf, 0x9c, 0x07, 0x6a, 0xc6, 0x19, 0xfb, 0xcc, 0x5d, 0x48, 0x75, 0x92,
}};
AlignedBuffer<32> derived_pub_data{{
0x13, 0xa6, 0x61, 0x5b, 0x78, 0x64, 0x03, 0xd4, 0x8a, 0x88, 0xaa, 0x0d, 0x89, 0xdf, 0x08, 0x46, 0xb3, 0x2f, 0xa9, 0xbb, 0xa8, 0xcc, 0xe1, 0xac, 0x4c, 0xae, 0xc9, 0xd2, 0xf1, 0x35, 0xd1, 0x33,
}};
SecretKey root{seed};
ASSERT_EQ(root.toPublic(), PubKey{root_pub_data});
PrivateKey root_key;
ASSERT_TRUE(root.toPrivate(root_key));
ASSERT_EQ(root_key, PrivateKey{root_key_data});
auto crypto = CryptoManager::instance();
PrivateKey aprime; // a'
ASSERT_TRUE(crypto->derive_subkey_private(aprime, root, 0, &hash));
// We use a different signing hash than Tor, so only the private key value (the first 32 bytes)
// will match:
ASSERT_EQ(aprime.ToHex().substr(0, 64), PrivateKey{derived_key_data}.ToHex().substr(0, 64));
PubKey Aprime; // A'
ASSERT_TRUE(crypto->derive_subkey(Aprime, root.toPublic(), 0, &hash));
ASSERT_EQ(Aprime, PubKey{derived_pub_data});
}
TEST_F(RealCryptographyTest, TestRootSigning)
{
auto crypto = CryptoManager::instance();
SecretKey root_key;
crypto->identity_keygen(root_key);
// We have our own reimplementation of sodium's signing function which can work with derived
// private keys (unlike sodium's built-in which requires starting from a seed). This tests that
// signing using either path produces an identical signature.
const std::string nibbs = "Nibbler";
llarp_buffer_t nibbs_buf{nibbs.data(), nibbs.size()};
Signature sig_sodium;
ASSERT_TRUE(crypto->sign(sig_sodium, root_key, nibbs_buf));
PrivateKey root_privkey;
ASSERT_TRUE(root_key.toPrivate(root_privkey));
Signature sig_ours;
ASSERT_TRUE(crypto->sign(sig_ours, root_privkey, nibbs_buf));
ASSERT_EQ(sig_sodium, sig_ours);
}
TEST_F(RealCryptographyTest, TestGenerateDeriveKey)
{
auto crypto = CryptoManager::instance();
SecretKey root_key;
crypto->identity_keygen(root_key);
PrivateKey root_privkey;
ASSERT_TRUE(root_key.toPrivate(root_privkey));
PrivateKey a;
PubKey A;
ASSERT_TRUE(root_key.toPrivate(a));
ASSERT_TRUE(a.toPublic(A));
ASSERT_EQ(A, root_key.toPublic());
{
// paranoid check to ensure this works as expected
PubKey aB;
crypto_scalarmult_ed25519_base(aB.data(), a.data());
ASSERT_EQ(A, aB);
}
PrivateKey aprime; // a'
ASSERT_TRUE(crypto->derive_subkey_private(aprime, root_key, 1));
PubKey Aprime; // A'
ASSERT_TRUE(crypto->derive_subkey(Aprime, A, 1));
// We should also be able to derive A' via a':
PubKey Aprime_alt;
ASSERT_TRUE(aprime.toPublic(Aprime_alt));
ASSERT_EQ(Aprime, Aprime_alt);
// Generate using the same constant and make sure we get an identical privkey (including the
// signing hash value)
PrivateKey aprime_repeat;
ASSERT_TRUE(crypto->derive_subkey_private(aprime_repeat, root_key, 1));
ASSERT_EQ(aprime_repeat, aprime);
// Generate another using a different constant and make sure we get something different
PrivateKey a2;
PubKey A2;
ASSERT_TRUE(crypto->derive_subkey_private(a2, root_key, 2));
ASSERT_TRUE(crypto->derive_subkey(A2, A, 2));
ASSERT_NE(A2, Aprime);
ASSERT_NE(a2.ToHex().substr(0, 64), aprime.ToHex().substr(0, 64));
ASSERT_NE(a2.ToHex().substr(64), aprime.ToHex().substr(64)); // The hash should be different too
}
TEST_F(RealCryptographyTest, TestSignUsingDerivedKey)
{
auto crypto = CryptoManager::instance();
SecretKey root_key;
crypto->identity_keygen(root_key);
PrivateKey root_privkey;
root_key.toPrivate(root_privkey);
PrivateKey a;
PubKey A;
root_key.toPrivate(a);
a.toPublic(A);
PrivateKey aprime; // a'
crypto->derive_subkey_private(aprime, root_key, 1);
PubKey Aprime; // A'
crypto->derive_subkey(Aprime, A, 1);
const std::string s = "Jeff loves one-letter variable names.";
llarp_buffer_t buf(s.data(), s.size());
Signature sig;
ASSERT_TRUE(crypto->sign(sig, aprime, buf));
ASSERT_TRUE(crypto->verify(Aprime, buf, sig));
}
TEST_F(RealCryptographyTest, TestEncryptAndSignIntroSet)
{
service::Identity ident;
ident.RegenerateKeys();
service::Address addr;
ASSERT_TRUE(ident.pub.CalculateAddress(addr.as_array()));
service::IntroSet I;
auto now = time_now_ms();
I.T = now;
while(I.I.size() < 10)
{
service::Introduction intro;
intro.expiresAt = now + (path::default_lifetime / 2);
intro.router.Randomize();
intro.pathID.Randomize();
I.I.emplace_back(std::move(intro));
}
const auto maybe = ident.EncryptAndSignIntroSet(I, now);
ASSERT_TRUE(maybe.has_value());
ASSERT_TRUE(maybe->Verify(now));
PubKey blind_key;
const PubKey root_key(addr.as_array());
auto crypto = CryptoManager::instance();
ASSERT_TRUE(crypto->derive_subkey(blind_key, root_key, 1));
}

Loading…
Cancel
Save