From e124aa3611f38573898aa79c6eabe77bc874e58f Mon Sep 17 00:00:00 2001 From: aunsane Date: Fri, 15 Dec 2017 01:05:56 +0300 Subject: preparing to build tox from sources --- libs/libsodium/docs/AUTHORS | 135 + libs/libsodium/docs/ChangeLog | 505 ++ libs/libsodium/docs/LICENSE | 18 + libs/libsodium/docs/README.markdown | 46 + libs/libsodium/docs/THANKS | 91 + libs/libsodium/libsodium.vcxproj | 493 ++ libs/libsodium/libsodium.vcxproj.filters | 4 + .../aes256gcm/aesni/aead_aes256gcm_aesni.c | 1079 ++++ .../sodium/aead_chacha20poly1305.c | 399 ++ .../sodium/aead_xchacha20poly1305.c | 160 + libs/libsodium/src/crypto_auth/crypto_auth.c | 41 + .../src/crypto_auth/hmacsha256/auth_hmacsha256.c | 118 + .../src/crypto_auth/hmacsha512/auth_hmacsha512.c | 118 + .../crypto_auth/hmacsha512256/auth_hmacsha512256.c | 93 + libs/libsodium/src/crypto_box/crypto_box.c | 114 + libs/libsodium/src/crypto_box/crypto_box_easy.c | 115 + libs/libsodium/src/crypto_box/crypto_box_seal.c | 68 + .../box_curve25519xchacha20poly1305.c | 204 + .../box_seal_curve25519xchacha20poly1305.c | 79 + .../box_curve25519xsalsa20poly1305.c | 156 + .../src/crypto_core/ed25519/core_ed25519.c | 79 + .../src/crypto_core/ed25519/ref10/ed25519_ref10.c | 2031 ++++++++ .../src/crypto_core/ed25519/ref10/fe_25_5/base.h | 1344 +++++ .../src/crypto_core/ed25519/ref10/fe_25_5/base2.h | 40 + .../crypto_core/ed25519/ref10/fe_25_5/constants.h | 20 + .../src/crypto_core/ed25519/ref10/fe_25_5/fe.h | 220 + .../src/crypto_core/ed25519/ref10/fe_51/base.h | 1344 +++++ .../src/crypto_core/ed25519/ref10/fe_51/base2.h | 40 + .../crypto_core/ed25519/ref10/fe_51/constants.h | 21 + .../src/crypto_core/ed25519/ref10/fe_51/fe.h | 116 + .../src/crypto_core/hchacha20/core_hchacha20.c | 93 + .../src/crypto_core/hsalsa20/core_hsalsa20.c | 21 + .../crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c | 95 + .../src/crypto_core/salsa/ref/core_salsa_ref.c | 195 + .../blake2b/generichash_blake2.c | 55 + .../src/crypto_generichash/blake2b/ref/blake2.h | 109 + .../blake2b/ref/blake2b-compress-avx2.c | 49 + .../blake2b/ref/blake2b-compress-avx2.h | 140 + .../blake2b/ref/blake2b-compress-ref.c | 93 + .../blake2b/ref/blake2b-compress-sse41.c | 87 + .../blake2b/ref/blake2b-compress-sse41.h | 103 + .../blake2b/ref/blake2b-compress-ssse3.c | 90 + .../blake2b/ref/blake2b-compress-ssse3.h | 103 + .../blake2b/ref/blake2b-load-avx2.h | 340 ++ .../blake2b/ref/blake2b-load-sse2.h | 164 + .../blake2b/ref/blake2b-load-sse41.h | 307 ++ .../crypto_generichash/blake2b/ref/blake2b-ref.c | 436 ++ .../blake2b/ref/generichash_blake2b.c | 111 + .../src/crypto_generichash/crypto_generichash.c | 91 + libs/libsodium/src/crypto_hash/crypto_hash.c | 20 + .../src/crypto_hash/sha256/cp/hash_sha256_cp.c | 254 + .../libsodium/src/crypto_hash/sha256/hash_sha256.c | 13 + .../src/crypto_hash/sha512/cp/hash_sha512_cp.c | 282 ++ .../libsodium/src/crypto_hash/sha512/hash_sha512.c | 13 + .../libsodium/src/crypto_kdf/blake2b/kdf_blake2b.c | 52 + libs/libsodium/src/crypto_kdf/crypto_kdf.c | 49 + libs/libsodium/src/crypto_kx/crypto_kx.c | 143 + .../src/crypto_onetimeauth/crypto_onetimeauth.c | 71 + .../poly1305/donna/poly1305_donna.c | 124 + .../poly1305/donna/poly1305_donna.h | 12 + .../poly1305/donna/poly1305_donna32.h | 235 + .../poly1305/donna/poly1305_donna64.h | 220 + .../poly1305/onetimeauth_poly1305.c | 90 + .../poly1305/onetimeauth_poly1305.h | 21 + .../poly1305/sse2/poly1305_sse2.c | 949 ++++ .../poly1305/sse2/poly1305_sse2.h | 12 + .../src/crypto_pwhash/argon2/argon2-core.c | 549 +++ .../src/crypto_pwhash/argon2/argon2-core.h | 297 ++ .../src/crypto_pwhash/argon2/argon2-encoding.c | 305 ++ .../src/crypto_pwhash/argon2/argon2-encoding.h | 33 + .../crypto_pwhash/argon2/argon2-fill-block-avx2.c | 239 + .../argon2/argon2-fill-block-avx512f.c | 244 + .../crypto_pwhash/argon2/argon2-fill-block-ref.c | 233 + .../crypto_pwhash/argon2/argon2-fill-block-ssse3.c | 238 + libs/libsodium/src/crypto_pwhash/argon2/argon2.c | 277 ++ libs/libsodium/src/crypto_pwhash/argon2/argon2.h | 305 ++ .../src/crypto_pwhash/argon2/blake2b-long.c | 79 + .../src/crypto_pwhash/argon2/blake2b-long.h | 8 + .../src/crypto_pwhash/argon2/blamka-round-avx2.h | 150 + .../crypto_pwhash/argon2/blamka-round-avx512f.h | 145 + .../src/crypto_pwhash/argon2/blamka-round-ref.h | 40 + .../src/crypto_pwhash/argon2/blamka-round-ssse3.h | 120 + .../src/crypto_pwhash/argon2/pwhash_argon2i.c | 290 ++ .../src/crypto_pwhash/argon2/pwhash_argon2id.c | 234 + libs/libsodium/src/crypto_pwhash/crypto_pwhash.c | 211 + .../scryptsalsa208sha256/crypto_scrypt-common.c | 263 + .../scryptsalsa208sha256/crypto_scrypt.h | 98 + .../nosse/pwhash_scryptsalsa208sha256_nosse.c | 375 ++ .../scryptsalsa208sha256/pbkdf2-sha256.c | 95 + .../scryptsalsa208sha256/pbkdf2-sha256.h | 45 + .../pwhash_scryptsalsa208sha256.c | 285 ++ .../scryptsalsa208sha256/scrypt_platform.c | 108 + .../sse/pwhash_scryptsalsa208sha256_sse.c | 400 ++ .../src/crypto_scalarmult/crypto_scalarmult.c | 33 + .../curve25519/ref10/x25519_ref10.c | 159 + .../curve25519/ref10/x25519_ref10.h | 10 + .../crypto_scalarmult/curve25519/sandy2x/consts.S | 25 + .../curve25519/sandy2x/consts_namespace.h | 20 + .../curve25519/sandy2x/curve25519_sandy2x.c | 114 + .../curve25519/sandy2x/curve25519_sandy2x.h | 9 + .../src/crypto_scalarmult/curve25519/sandy2x/fe.h | 26 + .../crypto_scalarmult/curve25519/sandy2x/fe51.h | 35 + .../curve25519/sandy2x/fe51_invert.c | 58 + .../curve25519/sandy2x/fe51_mul.S | 197 + .../curve25519/sandy2x/fe51_namespace.h | 16 + .../curve25519/sandy2x/fe51_nsquare.S | 172 + .../curve25519/sandy2x/fe51_pack.S | 226 + .../curve25519/sandy2x/fe_frombytes_sandy2x.c | 78 + .../crypto_scalarmult/curve25519/sandy2x/ladder.S | 1440 ++++++ .../crypto_scalarmult/curve25519/sandy2x/ladder.h | 18 + .../curve25519/sandy2x/ladder_base.S | 1295 +++++ .../curve25519/sandy2x/ladder_base.h | 18 + .../curve25519/sandy2x/ladder_base_namespace.h | 8 + .../curve25519/sandy2x/ladder_namespace.h | 8 + .../crypto_scalarmult/curve25519/sandy2x/sandy2x.S | 17 + .../curve25519/scalarmult_curve25519.c | 59 + .../curve25519/scalarmult_curve25519.h | 11 + .../ed25519/ref10/scalarmult_ed25519_ref10.c | 86 + .../src/crypto_secretbox/crypto_secretbox.c | 67 + .../src/crypto_secretbox/crypto_secretbox_easy.c | 144 + .../secretbox_xchacha20poly1305.c | 177 + .../xsalsa20poly1305/secretbox_xsalsa20poly1305.c | 89 + .../secretstream_xchacha20poly1305.c | 311 ++ .../src/crypto_shorthash/crypto_shorthash.c | 34 + .../siphash24/ref/shorthash_siphash24_ref.c | 65 + .../siphash24/ref/shorthash_siphash_ref.h | 24 + .../siphash24/ref/shorthash_siphashx24_ref.c | 71 + .../siphash24/shorthash_siphash24.c | 11 + .../siphash24/shorthash_siphashx24.c | 11 + libs/libsodium/src/crypto_sign/crypto_sign.c | 115 + .../src/crypto_sign/ed25519/ref10/keypair.c | 91 + .../src/crypto_sign/ed25519/ref10/obsolete.c | 116 + .../libsodium/src/crypto_sign/ed25519/ref10/open.c | 93 + .../libsodium/src/crypto_sign/ed25519/ref10/sign.c | 144 + .../crypto_sign/ed25519/ref10/sign_ed25519_ref10.h | 18 + .../src/crypto_sign/ed25519/sign_ed25519.c | 97 + .../chacha20/dolbeau/chacha20_dolbeau-avx2.c | 180 + .../chacha20/dolbeau/chacha20_dolbeau-avx2.h | 8 + .../chacha20/dolbeau/chacha20_dolbeau-ssse3.c | 174 + .../chacha20/dolbeau/chacha20_dolbeau-ssse3.h | 8 + .../src/crypto_stream/chacha20/dolbeau/u0.h | 86 + .../src/crypto_stream/chacha20/dolbeau/u1.h | 98 + .../src/crypto_stream/chacha20/dolbeau/u4.h | 175 + .../src/crypto_stream/chacha20/dolbeau/u8.h | 357 ++ .../src/crypto_stream/chacha20/ref/chacha20_ref.c | 315 ++ .../src/crypto_stream/chacha20/ref/chacha20_ref.h | 8 + .../src/crypto_stream/chacha20/stream_chacha20.c | 130 + .../src/crypto_stream/chacha20/stream_chacha20.h | 22 + libs/libsodium/src/crypto_stream/crypto_stream.c | 49 + .../src/crypto_stream/salsa20/ref/salsa20_ref.c | 120 + .../src/crypto_stream/salsa20/ref/salsa20_ref.h | 8 + .../src/crypto_stream/salsa20/stream_salsa20.c | 100 + .../src/crypto_stream/salsa20/stream_salsa20.h | 16 + .../crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S | 960 ++++ .../src/crypto_stream/salsa20/xmm6/salsa20_xmm6.c | 31 + .../src/crypto_stream/salsa20/xmm6/salsa20_xmm6.h | 8 + .../salsa20/xmm6int/salsa20_xmm6int-avx2.c | 131 + .../salsa20/xmm6int/salsa20_xmm6int-avx2.h | 8 + .../salsa20/xmm6int/salsa20_xmm6int-sse2.c | 122 + .../salsa20/xmm6int/salsa20_xmm6int-sse2.h | 8 + .../src/crypto_stream/salsa20/xmm6int/u0.h | 195 + .../src/crypto_stream/salsa20/xmm6int/u1.h | 207 + .../src/crypto_stream/salsa20/xmm6int/u4.h | 547 ++ .../src/crypto_stream/salsa20/xmm6int/u8.h | 476 ++ .../salsa2012/ref/stream_salsa2012_ref.c | 106 + .../src/crypto_stream/salsa2012/stream_salsa2012.c | 26 + .../salsa208/ref/stream_salsa208_ref.c | 106 + .../src/crypto_stream/salsa208/stream_salsa208.c | 26 + .../src/crypto_stream/xchacha20/stream_xchacha20.c | 69 + .../src/crypto_stream/xsalsa20/stream_xsalsa20.c | 66 + libs/libsodium/src/crypto_verify/sodium/verify.c | 98 + libs/libsodium/src/include/Makefile.am | 75 + libs/libsodium/src/include/sodium.h | 70 + libs/libsodium/src/include/sodium/core.h | 28 + .../src/include/sodium/crypto_aead_aes256gcm.h | 171 + .../include/sodium/crypto_aead_chacha20poly1305.h | 174 + .../include/sodium/crypto_aead_xchacha20poly1305.h | 97 + libs/libsodium/src/include/sodium/crypto_auth.h | 44 + .../src/include/sodium/crypto_auth_hmacsha256.h | 68 + .../src/include/sodium/crypto_auth_hmacsha512.h | 67 + .../src/include/sodium/crypto_auth_hmacsha512256.h | 62 + libs/libsodium/src/include/sodium/crypto_box.h | 173 + .../crypto_box_curve25519xchacha20poly1305.h | 159 + .../sodium/crypto_box_curve25519xsalsa20poly1305.h | 109 + .../src/include/sodium/crypto_core_ed25519.h | 37 + .../src/include/sodium/crypto_core_hchacha20.h | 35 + .../src/include/sodium/crypto_core_hsalsa20.h | 35 + .../src/include/sodium/crypto_core_salsa20.h | 35 + .../src/include/sodium/crypto_core_salsa2012.h | 35 + .../src/include/sodium/crypto_core_salsa208.h | 39 + .../src/include/sodium/crypto_generichash.h | 75 + .../include/sodium/crypto_generichash_blake2b.h | 117 + libs/libsodium/src/include/sodium/crypto_hash.h | 40 + .../src/include/sodium/crypto_hash_sha256.h | 57 + .../src/include/sodium/crypto_hash_sha512.h | 57 + libs/libsodium/src/include/sodium/crypto_kdf.h | 51 + .../src/include/sodium/crypto_kdf_blake2b.h | 42 + libs/libsodium/src/include/sodium/crypto_kx.h | 64 + .../src/include/sodium/crypto_onetimeauth.h | 62 + .../include/sodium/crypto_onetimeauth_poly1305.h | 67 + libs/libsodium/src/include/sodium/crypto_pwhash.h | 147 + .../src/include/sodium/crypto_pwhash_argon2i.h | 122 + .../src/include/sodium/crypto_pwhash_argon2id.h | 122 + .../sodium/crypto_pwhash_scryptsalsa208sha256.h | 120 + .../src/include/sodium/crypto_scalarmult.h | 45 + .../include/sodium/crypto_scalarmult_curve25519.h | 40 + .../src/include/sodium/crypto_scalarmult_ed25519.h | 41 + .../src/include/sodium/crypto_secretbox.h | 91 + .../sodium/crypto_secretbox_xchacha20poly1305.h | 68 + .../sodium/crypto_secretbox_xsalsa20poly1305.h | 67 + .../sodium/crypto_secretstream_xchacha20poly1305.h | 102 + .../src/include/sodium/crypto_shorthash.h | 39 + .../include/sodium/crypto_shorthash_siphash24.h | 48 + libs/libsodium/src/include/sodium/crypto_sign.h | 103 + .../src/include/sodium/crypto_sign_ed25519.h | 114 + .../sodium/crypto_sign_edwards25519sha512batch.h | 55 + libs/libsodium/src/include/sodium/crypto_stream.h | 56 + .../src/include/sodium/crypto_stream_chacha20.h | 98 + .../src/include/sodium/crypto_stream_salsa20.h | 57 + .../src/include/sodium/crypto_stream_salsa2012.h | 50 + .../src/include/sodium/crypto_stream_salsa208.h | 56 + .../src/include/sodium/crypto_stream_xchacha20.h | 57 + .../src/include/sodium/crypto_stream_xsalsa20.h | 57 + .../src/include/sodium/crypto_verify_16.h | 23 + .../src/include/sodium/crypto_verify_32.h | 23 + .../src/include/sodium/crypto_verify_64.h | 23 + libs/libsodium/src/include/sodium/export.h | 53 + libs/libsodium/src/include/sodium/private/common.h | 246 + .../src/include/sodium/private/ed25519_ref10.h | 125 + .../include/sodium/private/ed25519_ref10_fe_25_5.h | 1050 ++++ .../include/sodium/private/ed25519_ref10_fe_51.h | 518 ++ .../src/include/sodium/private/implementations.h | 11 + libs/libsodium/src/include/sodium/private/mutex.h | 7 + .../src/include/sodium/private/sse2_64_32.h | 50 + libs/libsodium/src/include/sodium/randombytes.h | 68 + .../src/include/sodium/randombytes_nativeclient.h | 23 + .../include/sodium/randombytes_salsa20_random.h | 19 + .../src/include/sodium/randombytes_sysrandom.h | 19 + libs/libsodium/src/include/sodium/runtime.h | 52 + libs/libsodium/src/include/sodium/utils.h | 170 + libs/libsodium/src/include/sodium/version.h | 32 + .../nativeclient/randombytes_nativeclient.c | 61 + libs/libsodium/src/randombytes/randombytes.c | 206 + .../salsa20/randombytes_salsa20_random.c | 564 +++ .../randombytes/sysrandom/randombytes_sysrandom.c | 382 ++ libs/libsodium/src/sodium/codecs.c | 333 ++ libs/libsodium/src/sodium/core.c | 231 + libs/libsodium/src/sodium/runtime.c | 286 ++ libs/libsodium/src/sodium/utils.c | 737 +++ libs/libsodium/src/sodium/version.c | 30 + libs/libsodium/src/stdafx.cxx | 2 + libs/libsodium/src/stdafx.h | 0 libs/libtox/docs/CHANGELOG.md | 450 ++ libs/libtox/docs/COPYING | 674 +++ libs/libtox/docs/DONATORS | 7 + libs/libtox/docs/README.md | 174 + libs/libtox/libtox.vcxproj | 52 + libs/libtox/libtox.vcxproj.filters | 293 ++ libs/libtox/src/stdafx.cxx | 2 + libs/libtox/src/stdafx.h | 0 libs/libtox/src/toxcore/DHT.c | 2853 +++++++++++ libs/libtox/src/toxcore/DHT.h | 448 ++ libs/libtox/src/toxcore/LAN_discovery.c | 410 ++ libs/libtox/src/toxcore/LAN_discovery.h | 52 + libs/libtox/src/toxcore/Messenger.c | 3155 ++++++++++++ libs/libtox/src/toxcore/Messenger.h | 777 +++ libs/libtox/src/toxcore/TCP_client.c | 991 ++++ libs/libtox/src/toxcore/TCP_client.h | 167 + libs/libtox/src/toxcore/TCP_connection.c | 1491 ++++++ libs/libtox/src/toxcore/TCP_connection.h | 223 + libs/libtox/src/toxcore/TCP_server.c | 1417 ++++++ libs/libtox/src/toxcore/TCP_server.h | 167 + libs/libtox/src/toxcore/ccompat.h | 43 + libs/libtox/src/toxcore/crypto_core.api.h | 246 + libs/libtox/src/toxcore/crypto_core.c | 287 ++ libs/libtox/src/toxcore/crypto_core.h | 234 + libs/libtox/src/toxcore/crypto_core_mem.c | 87 + libs/libtox/src/toxcore/friend_connection.c | 937 ++++ libs/libtox/src/toxcore/friend_connection.h | 210 + libs/libtox/src/toxcore/friend_requests.c | 152 + libs/libtox/src/toxcore/friend_requests.h | 76 + libs/libtox/src/toxcore/group.c | 2544 ++++++++++ libs/libtox/src/toxcore/group.h | 395 ++ libs/libtox/src/toxcore/list.c | 266 + libs/libtox/src/toxcore/list.h | 85 + libs/libtox/src/toxcore/logger.c | 77 + libs/libtox/src/toxcore/logger.h | 80 + libs/libtox/src/toxcore/net_crypto.c | 2908 +++++++++++ libs/libtox/src/toxcore/net_crypto.h | 428 ++ libs/libtox/src/toxcore/network.c | 1446 ++++++ libs/libtox/src/toxcore/network.h | 424 ++ libs/libtox/src/toxcore/onion.c | 679 +++ libs/libtox/src/toxcore/onion.h | 165 + libs/libtox/src/toxcore/onion_announce.c | 497 ++ libs/libtox/src/toxcore/onion_announce.h | 140 + libs/libtox/src/toxcore/onion_client.c | 1771 +++++++ libs/libtox/src/toxcore/onion_client.h | 302 ++ libs/libtox/src/toxcore/ping.c | 381 ++ libs/libtox/src/toxcore/ping.h | 54 + libs/libtox/src/toxcore/ping_array.c | 172 + libs/libtox/src/toxcore/ping_array.h | 76 + libs/libtox/src/toxcore/tox.api.h | 2583 ++++++++++ libs/libtox/src/toxcore/tox.c | 1551 ++++++ libs/libtox/src/toxcore/tox.h | 2947 +++++++++++ libs/libtox/src/toxcore/tox_api.c | 97 + libs/libtox/src/toxcore/util.c | 194 + libs/libtox/src/toxcore/util.h | 64 + libs/libtox/src/toxdns/Makefile.inc | 35 + libs/libtox/src/toxdns/toxdns.c | 243 + libs/libtox/src/toxdns/toxdns.h | 96 + libs/libtox/src/toxencryptsave/Makefile.inc | 55 + .../crypto_pwhash_scryptsalsa208sha256.h | 92 + .../crypto_scrypt-common.c | 257 + .../crypto_scrypt.h | 93 + .../crypto_pwhash_scryptsalsa208sha256/export.h | 38 + .../nosse/pwhash_scryptsalsa208sha256_nosse.c | 309 ++ .../note_to_maintainers.txt | 14 + .../pbkdf2-sha256.c | 97 + .../pbkdf2-sha256.h | 52 + .../pwhash_scryptsalsa208sha256.c | 211 + .../crypto_pwhash_scryptsalsa208sha256/runtime.c | 140 + .../crypto_pwhash_scryptsalsa208sha256/runtime.h | 33 + .../scrypt_platform.c | 107 + .../sse/pwhash_scryptsalsa208sha256_sse.c | 398 ++ .../crypto_pwhash_scryptsalsa208sha256/sysendian.h | 153 + .../crypto_pwhash_scryptsalsa208sha256/utils.c | 78 + .../crypto_pwhash_scryptsalsa208sha256/utils.h | 40 + libs/libtox/src/toxencryptsave/defines.h | 2 + .../libtox/src/toxencryptsave/toxencryptsave.api.h | 327 ++ libs/libtox/src/toxencryptsave/toxencryptsave.c | 338 ++ libs/libtox/src/toxencryptsave/toxencryptsave.h | 388 ++ libs/pthreads/docs/ANNOUNCE | 483 ++ libs/pthreads/docs/BUGS | 141 + libs/pthreads/docs/Bmakefile | 268 + libs/pthreads/docs/CONTRIBUTORS | 140 + libs/pthreads/docs/COPYING | 150 + libs/pthreads/docs/ChangeLog | 5211 ++++++++++++++++++++ libs/pthreads/docs/FAQ | 451 ++ libs/pthreads/docs/GNUmakefile | 593 +++ libs/pthreads/docs/MAINTAINERS | 4 + libs/pthreads/docs/Makefile | 514 ++ libs/pthreads/docs/NEWS | 1241 +++++ libs/pthreads/docs/Nmakefile | 24 + libs/pthreads/docs/PROGRESS | 4 + libs/pthreads/docs/README | 601 +++ libs/pthreads/docs/TODO | 7 + libs/pthreads/docs/WinCE-PORT | 222 + libs/pthreads/pthreads.vcxproj | 90 + libs/pthreads/pthreads.vcxproj.filters | 505 ++ libs/pthreads/src/attr.c | 53 + libs/pthreads/src/autostatic.c | 69 + libs/pthreads/src/barrier.c | 47 + libs/pthreads/src/cancel.c | 44 + libs/pthreads/src/cleanup.c | 148 + libs/pthreads/src/condvar.c | 50 + libs/pthreads/src/config.h | 153 + libs/pthreads/src/context.h | 74 + libs/pthreads/src/create.c | 308 ++ libs/pthreads/src/dll.c | 92 + libs/pthreads/src/errno.c | 94 + libs/pthreads/src/exit.c | 44 + libs/pthreads/src/fork.c | 39 + libs/pthreads/src/global.c | 107 + libs/pthreads/src/implement.h | 943 ++++ libs/pthreads/src/misc.c | 50 + libs/pthreads/src/mutex.c | 62 + libs/pthreads/src/need_errno.h | 145 + libs/pthreads/src/nonportable.c | 47 + libs/pthreads/src/private.c | 54 + libs/pthreads/src/pthread.c | 66 + libs/pthreads/src/pthread.h | 1368 +++++ libs/pthreads/src/pthread_attr_destroy.c | 79 + libs/pthreads/src/pthread_attr_getdetachstate.c | 86 + libs/pthreads/src/pthread_attr_getinheritsched.c | 51 + libs/pthreads/src/pthread_attr_getschedparam.c | 52 + libs/pthreads/src/pthread_attr_getschedpolicy.c | 61 + libs/pthreads/src/pthread_attr_getscope.c | 54 + libs/pthreads/src/pthread_attr_getstackaddr.c | 97 + libs/pthreads/src/pthread_attr_getstacksize.c | 100 + libs/pthreads/src/pthread_attr_init.c | 117 + libs/pthreads/src/pthread_attr_setdetachstate.c | 91 + libs/pthreads/src/pthread_attr_setinheritsched.c | 57 + libs/pthreads/src/pthread_attr_setschedparam.c | 63 + libs/pthreads/src/pthread_attr_setschedpolicy.c | 55 + libs/pthreads/src/pthread_attr_setscope.c | 62 + libs/pthreads/src/pthread_attr_setstackaddr.c | 97 + libs/pthreads/src/pthread_attr_setstacksize.c | 110 + libs/pthreads/src/pthread_barrier_destroy.c | 103 + libs/pthreads/src/pthread_barrier_init.c | 69 + libs/pthreads/src/pthread_barrier_wait.c | 104 + libs/pthreads/src/pthread_barrierattr_destroy.c | 83 + libs/pthreads/src/pthread_barrierattr_getpshared.c | 95 + libs/pthreads/src/pthread_barrierattr_init.c | 85 + libs/pthreads/src/pthread_barrierattr_setpshared.c | 119 + libs/pthreads/src/pthread_cancel.c | 189 + libs/pthreads/src/pthread_cond_destroy.c | 253 + libs/pthreads/src/pthread_cond_init.c | 167 + libs/pthreads/src/pthread_cond_signal.c | 231 + libs/pthreads/src/pthread_cond_wait.c | 567 +++ libs/pthreads/src/pthread_condattr_destroy.c | 86 + libs/pthreads/src/pthread_condattr_getpshared.c | 97 + libs/pthreads/src/pthread_condattr_init.c | 87 + libs/pthreads/src/pthread_condattr_setpshared.c | 117 + libs/pthreads/src/pthread_delay_np.c | 172 + libs/pthreads/src/pthread_detach.c | 136 + libs/pthreads/src/pthread_equal.c | 76 + libs/pthreads/src/pthread_exit.c | 106 + libs/pthreads/src/pthread_getconcurrency.c | 45 + libs/pthreads/src/pthread_getschedparam.c | 75 + libs/pthreads/src/pthread_getspecific.c | 87 + libs/pthreads/src/pthread_getunique_np.c | 47 + libs/pthreads/src/pthread_getw32threadhandle_np.c | 65 + libs/pthreads/src/pthread_join.c | 157 + libs/pthreads/src/pthread_key_create.c | 108 + libs/pthreads/src/pthread_key_delete.c | 125 + libs/pthreads/src/pthread_kill.c | 105 + libs/pthreads/src/pthread_mutex_consistent.c | 190 + libs/pthreads/src/pthread_mutex_destroy.c | 148 + libs/pthreads/src/pthread_mutex_init.c | 130 + libs/pthreads/src/pthread_mutex_lock.c | 269 + libs/pthreads/src/pthread_mutex_timedlock.c | 324 ++ libs/pthreads/src/pthread_mutex_trylock.c | 154 + libs/pthreads/src/pthread_mutex_unlock.c | 175 + libs/pthreads/src/pthread_mutexattr_destroy.c | 83 + libs/pthreads/src/pthread_mutexattr_getkind_np.c | 44 + libs/pthreads/src/pthread_mutexattr_getpshared.c | 95 + libs/pthreads/src/pthread_mutexattr_getrobust.c | 113 + libs/pthreads/src/pthread_mutexattr_gettype.c | 56 + libs/pthreads/src/pthread_mutexattr_init.c | 86 + libs/pthreads/src/pthread_mutexattr_setkind_np.c | 44 + libs/pthreads/src/pthread_mutexattr_setpshared.c | 119 + libs/pthreads/src/pthread_mutexattr_setrobust.c | 119 + libs/pthreads/src/pthread_mutexattr_settype.c | 143 + libs/pthreads/src/pthread_num_processors_np.c | 56 + libs/pthreads/src/pthread_once.c | 79 + libs/pthreads/src/pthread_rwlock_destroy.c | 143 + libs/pthreads/src/pthread_rwlock_init.c | 109 + libs/pthreads/src/pthread_rwlock_rdlock.c | 102 + libs/pthreads/src/pthread_rwlock_timedrdlock.c | 109 + libs/pthreads/src/pthread_rwlock_timedwrlock.c | 139 + libs/pthreads/src/pthread_rwlock_tryrdlock.c | 102 + libs/pthreads/src/pthread_rwlock_trywrlock.c | 122 + libs/pthreads/src/pthread_rwlock_unlock.c | 93 + libs/pthreads/src/pthread_rwlock_wrlock.c | 133 + libs/pthreads/src/pthread_rwlockattr_destroy.c | 84 + libs/pthreads/src/pthread_rwlockattr_getpshared.c | 97 + libs/pthreads/src/pthread_rwlockattr_init.c | 83 + libs/pthreads/src/pthread_rwlockattr_setpshared.c | 120 + libs/pthreads/src/pthread_self.c | 141 + libs/pthreads/src/pthread_setcancelstate.c | 125 + libs/pthreads/src/pthread_setcanceltype.c | 126 + libs/pthreads/src/pthread_setconcurrency.c | 53 + libs/pthreads/src/pthread_setschedparam.c | 123 + libs/pthreads/src/pthread_setspecific.c | 167 + libs/pthreads/src/pthread_spin_destroy.c | 111 + libs/pthreads/src/pthread_spin_init.c | 123 + libs/pthreads/src/pthread_spin_lock.c | 80 + libs/pthreads/src/pthread_spin_trylock.c | 77 + libs/pthreads/src/pthread_spin_unlock.c | 71 + libs/pthreads/src/pthread_testcancel.c | 103 + libs/pthreads/src/pthread_timechange_handler_np.c | 108 + libs/pthreads/src/pthread_win32_attach_detach_np.c | 256 + libs/pthreads/src/ptw32_MCS_lock.c | 278 ++ libs/pthreads/src/ptw32_OLL_lock.c | 734 +++ libs/pthreads/src/ptw32_callUserDestroyRoutines.c | 232 + libs/pthreads/src/ptw32_calloc.c | 56 + libs/pthreads/src/ptw32_cond_check_need_init.c | 78 + libs/pthreads/src/ptw32_getprocessors.c | 91 + libs/pthreads/src/ptw32_is_attr.c | 47 + libs/pthreads/src/ptw32_mutex_check_need_init.c | 92 + libs/pthreads/src/ptw32_new.c | 94 + libs/pthreads/src/ptw32_processInitialize.c | 92 + libs/pthreads/src/ptw32_processTerminate.c | 105 + libs/pthreads/src/ptw32_relmillisecs.c | 132 + libs/pthreads/src/ptw32_reuse.c | 151 + libs/pthreads/src/ptw32_rwlock_cancelwrwait.c | 50 + libs/pthreads/src/ptw32_rwlock_check_need_init.c | 77 + libs/pthreads/src/ptw32_semwait.c | 135 + libs/pthreads/src/ptw32_spinlock_check_need_init.c | 78 + libs/pthreads/src/ptw32_threadDestroy.c | 79 + libs/pthreads/src/ptw32_threadStart.c | 357 ++ libs/pthreads/src/ptw32_throw.c | 189 + libs/pthreads/src/ptw32_timespec.c | 83 + libs/pthreads/src/ptw32_tkAssocCreate.c | 118 + libs/pthreads/src/ptw32_tkAssocDestroy.c | 114 + libs/pthreads/src/rwlock.c | 51 + libs/pthreads/src/sched.c | 53 + libs/pthreads/src/sched.h | 183 + libs/pthreads/src/sched_get_priority_max.c | 134 + libs/pthreads/src/sched_get_priority_min.c | 135 + libs/pthreads/src/sched_getscheduler.c | 71 + libs/pthreads/src/sched_setscheduler.c | 83 + libs/pthreads/src/sched_yield.c | 71 + libs/pthreads/src/sem_close.c | 58 + libs/pthreads/src/sem_destroy.c | 144 + libs/pthreads/src/sem_getvalue.c | 110 + libs/pthreads/src/sem_init.c | 169 + libs/pthreads/src/sem_open.c | 58 + libs/pthreads/src/sem_post.c | 128 + libs/pthreads/src/sem_post_multiple.c | 142 + libs/pthreads/src/sem_timedwait.c | 238 + libs/pthreads/src/sem_trywait.c | 117 + libs/pthreads/src/sem_unlink.c | 58 + libs/pthreads/src/sem_wait.c | 187 + libs/pthreads/src/semaphore.c | 69 + libs/pthreads/src/semaphore.h | 169 + libs/pthreads/src/signal.c | 179 + libs/pthreads/src/spin.c | 46 + libs/pthreads/src/sync.c | 43 + libs/pthreads/src/tsd.c | 44 + libs/pthreads/src/w32_CancelableWait.c | 161 + 511 files changed, 111884 insertions(+) create mode 100644 libs/libsodium/docs/AUTHORS create mode 100644 libs/libsodium/docs/ChangeLog create mode 100644 libs/libsodium/docs/LICENSE create mode 100644 libs/libsodium/docs/README.markdown create mode 100644 libs/libsodium/docs/THANKS create mode 100644 libs/libsodium/libsodium.vcxproj create mode 100644 libs/libsodium/libsodium.vcxproj.filters create mode 100644 libs/libsodium/src/crypto_aead/aes256gcm/aesni/aead_aes256gcm_aesni.c create mode 100644 libs/libsodium/src/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c create mode 100644 libs/libsodium/src/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c create mode 100644 libs/libsodium/src/crypto_auth/crypto_auth.c create mode 100644 libs/libsodium/src/crypto_auth/hmacsha256/auth_hmacsha256.c create mode 100644 libs/libsodium/src/crypto_auth/hmacsha512/auth_hmacsha512.c create mode 100644 libs/libsodium/src/crypto_auth/hmacsha512256/auth_hmacsha512256.c create mode 100644 libs/libsodium/src/crypto_box/crypto_box.c create mode 100644 libs/libsodium/src/crypto_box/crypto_box_easy.c create mode 100644 libs/libsodium/src/crypto_box/crypto_box_seal.c create mode 100644 libs/libsodium/src/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c create mode 100644 libs/libsodium/src/crypto_box/curve25519xchacha20poly1305/box_seal_curve25519xchacha20poly1305.c create mode 100644 libs/libsodium/src/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c create mode 100644 libs/libsodium/src/crypto_core/ed25519/core_ed25519.c create mode 100644 libs/libsodium/src/crypto_core/ed25519/ref10/ed25519_ref10.c create mode 100644 libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/base.h create mode 100644 libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/base2.h create mode 100644 libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/constants.h create mode 100644 libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/fe.h create mode 100644 libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/base.h create mode 100644 libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/base2.h create mode 100644 libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/constants.h create mode 100644 libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/fe.h create mode 100644 libs/libsodium/src/crypto_core/hchacha20/core_hchacha20.c create mode 100644 libs/libsodium/src/crypto_core/hsalsa20/core_hsalsa20.c create mode 100644 libs/libsodium/src/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c create mode 100644 libs/libsodium/src/crypto_core/salsa/ref/core_salsa_ref.c create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/generichash_blake2.c create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2.h create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-avx2.h create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ref.c create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-sse41.c create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-sse41.h create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.h create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-avx2.h create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-sse2.h create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-sse41.h create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-ref.c create mode 100644 libs/libsodium/src/crypto_generichash/blake2b/ref/generichash_blake2b.c create mode 100644 libs/libsodium/src/crypto_generichash/crypto_generichash.c create mode 100644 libs/libsodium/src/crypto_hash/crypto_hash.c create mode 100644 libs/libsodium/src/crypto_hash/sha256/cp/hash_sha256_cp.c create mode 100644 libs/libsodium/src/crypto_hash/sha256/hash_sha256.c create mode 100644 libs/libsodium/src/crypto_hash/sha512/cp/hash_sha512_cp.c create mode 100644 libs/libsodium/src/crypto_hash/sha512/hash_sha512.c create mode 100644 libs/libsodium/src/crypto_kdf/blake2b/kdf_blake2b.c create mode 100644 libs/libsodium/src/crypto_kdf/crypto_kdf.c create mode 100644 libs/libsodium/src/crypto_kx/crypto_kx.c create mode 100644 libs/libsodium/src/crypto_onetimeauth/crypto_onetimeauth.c create mode 100644 libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna.c create mode 100644 libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna.h create mode 100644 libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna32.h create mode 100644 libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna64.h create mode 100644 libs/libsodium/src/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c create mode 100644 libs/libsodium/src/crypto_onetimeauth/poly1305/onetimeauth_poly1305.h create mode 100644 libs/libsodium/src/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.c create mode 100644 libs/libsodium/src/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.h create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2-core.c create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2-core.h create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.c create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.h create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx2.c create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx512f.c create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ref.c create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ssse3.c create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2.c create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/argon2.h create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.c create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.h create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx2.h create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx512f.h create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ref.h create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ssse3.h create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2i.c create mode 100644 libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2id.c create mode 100644 libs/libsodium/src/crypto_pwhash/crypto_pwhash.c create mode 100644 libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c create mode 100644 libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt.h create mode 100644 libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c create mode 100644 libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c create mode 100644 libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.h create mode 100644 libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c create mode 100644 libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c create mode 100644 libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c create mode 100644 libs/libsodium/src/crypto_scalarmult/crypto_scalarmult.c create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/ref10/x25519_ref10.c create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/ref10/x25519_ref10.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/consts.S create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/consts_namespace.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_namespace.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder.S create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base.S create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base_namespace.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_namespace.h create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/sandy2x.S create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/scalarmult_curve25519.c create mode 100644 libs/libsodium/src/crypto_scalarmult/curve25519/scalarmult_curve25519.h create mode 100644 libs/libsodium/src/crypto_scalarmult/ed25519/ref10/scalarmult_ed25519_ref10.c create mode 100644 libs/libsodium/src/crypto_secretbox/crypto_secretbox.c create mode 100644 libs/libsodium/src/crypto_secretbox/crypto_secretbox_easy.c create mode 100644 libs/libsodium/src/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c create mode 100644 libs/libsodium/src/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c create mode 100644 libs/libsodium/src/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c create mode 100644 libs/libsodium/src/crypto_shorthash/crypto_shorthash.c create mode 100644 libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c create mode 100644 libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphash_ref.h create mode 100644 libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c create mode 100644 libs/libsodium/src/crypto_shorthash/siphash24/shorthash_siphash24.c create mode 100644 libs/libsodium/src/crypto_shorthash/siphash24/shorthash_siphashx24.c create mode 100644 libs/libsodium/src/crypto_sign/crypto_sign.c create mode 100644 libs/libsodium/src/crypto_sign/ed25519/ref10/keypair.c create mode 100644 libs/libsodium/src/crypto_sign/ed25519/ref10/obsolete.c create mode 100644 libs/libsodium/src/crypto_sign/ed25519/ref10/open.c create mode 100644 libs/libsodium/src/crypto_sign/ed25519/ref10/sign.c create mode 100644 libs/libsodium/src/crypto_sign/ed25519/ref10/sign_ed25519_ref10.h create mode 100644 libs/libsodium/src/crypto_sign/ed25519/sign_ed25519.c create mode 100644 libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c create mode 100644 libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.h create mode 100644 libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c create mode 100644 libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.h create mode 100644 libs/libsodium/src/crypto_stream/chacha20/dolbeau/u0.h create mode 100644 libs/libsodium/src/crypto_stream/chacha20/dolbeau/u1.h create mode 100644 libs/libsodium/src/crypto_stream/chacha20/dolbeau/u4.h create mode 100644 libs/libsodium/src/crypto_stream/chacha20/dolbeau/u8.h create mode 100644 libs/libsodium/src/crypto_stream/chacha20/ref/chacha20_ref.c create mode 100644 libs/libsodium/src/crypto_stream/chacha20/ref/chacha20_ref.h create mode 100644 libs/libsodium/src/crypto_stream/chacha20/stream_chacha20.c create mode 100644 libs/libsodium/src/crypto_stream/chacha20/stream_chacha20.h create mode 100644 libs/libsodium/src/crypto_stream/crypto_stream.c create mode 100644 libs/libsodium/src/crypto_stream/salsa20/ref/salsa20_ref.c create mode 100644 libs/libsodium/src/crypto_stream/salsa20/ref/salsa20_ref.h create mode 100644 libs/libsodium/src/crypto_stream/salsa20/stream_salsa20.c create mode 100644 libs/libsodium/src/crypto_stream/salsa20/stream_salsa20.h create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6.c create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6.h create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.h create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.h create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6int/u0.h create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6int/u1.h create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6int/u4.h create mode 100644 libs/libsodium/src/crypto_stream/salsa20/xmm6int/u8.h create mode 100644 libs/libsodium/src/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c create mode 100644 libs/libsodium/src/crypto_stream/salsa2012/stream_salsa2012.c create mode 100644 libs/libsodium/src/crypto_stream/salsa208/ref/stream_salsa208_ref.c create mode 100644 libs/libsodium/src/crypto_stream/salsa208/stream_salsa208.c create mode 100644 libs/libsodium/src/crypto_stream/xchacha20/stream_xchacha20.c create mode 100644 libs/libsodium/src/crypto_stream/xsalsa20/stream_xsalsa20.c create mode 100644 libs/libsodium/src/crypto_verify/sodium/verify.c create mode 100644 libs/libsodium/src/include/Makefile.am create mode 100644 libs/libsodium/src/include/sodium.h create mode 100644 libs/libsodium/src/include/sodium/core.h create mode 100644 libs/libsodium/src/include/sodium/crypto_aead_aes256gcm.h create mode 100644 libs/libsodium/src/include/sodium/crypto_aead_chacha20poly1305.h create mode 100644 libs/libsodium/src/include/sodium/crypto_aead_xchacha20poly1305.h create mode 100644 libs/libsodium/src/include/sodium/crypto_auth.h create mode 100644 libs/libsodium/src/include/sodium/crypto_auth_hmacsha256.h create mode 100644 libs/libsodium/src/include/sodium/crypto_auth_hmacsha512.h create mode 100644 libs/libsodium/src/include/sodium/crypto_auth_hmacsha512256.h create mode 100644 libs/libsodium/src/include/sodium/crypto_box.h create mode 100644 libs/libsodium/src/include/sodium/crypto_box_curve25519xchacha20poly1305.h create mode 100644 libs/libsodium/src/include/sodium/crypto_box_curve25519xsalsa20poly1305.h create mode 100644 libs/libsodium/src/include/sodium/crypto_core_ed25519.h create mode 100644 libs/libsodium/src/include/sodium/crypto_core_hchacha20.h create mode 100644 libs/libsodium/src/include/sodium/crypto_core_hsalsa20.h create mode 100644 libs/libsodium/src/include/sodium/crypto_core_salsa20.h create mode 100644 libs/libsodium/src/include/sodium/crypto_core_salsa2012.h create mode 100644 libs/libsodium/src/include/sodium/crypto_core_salsa208.h create mode 100644 libs/libsodium/src/include/sodium/crypto_generichash.h create mode 100644 libs/libsodium/src/include/sodium/crypto_generichash_blake2b.h create mode 100644 libs/libsodium/src/include/sodium/crypto_hash.h create mode 100644 libs/libsodium/src/include/sodium/crypto_hash_sha256.h create mode 100644 libs/libsodium/src/include/sodium/crypto_hash_sha512.h create mode 100644 libs/libsodium/src/include/sodium/crypto_kdf.h create mode 100644 libs/libsodium/src/include/sodium/crypto_kdf_blake2b.h create mode 100644 libs/libsodium/src/include/sodium/crypto_kx.h create mode 100644 libs/libsodium/src/include/sodium/crypto_onetimeauth.h create mode 100644 libs/libsodium/src/include/sodium/crypto_onetimeauth_poly1305.h create mode 100644 libs/libsodium/src/include/sodium/crypto_pwhash.h create mode 100644 libs/libsodium/src/include/sodium/crypto_pwhash_argon2i.h create mode 100644 libs/libsodium/src/include/sodium/crypto_pwhash_argon2id.h create mode 100644 libs/libsodium/src/include/sodium/crypto_pwhash_scryptsalsa208sha256.h create mode 100644 libs/libsodium/src/include/sodium/crypto_scalarmult.h create mode 100644 libs/libsodium/src/include/sodium/crypto_scalarmult_curve25519.h create mode 100644 libs/libsodium/src/include/sodium/crypto_scalarmult_ed25519.h create mode 100644 libs/libsodium/src/include/sodium/crypto_secretbox.h create mode 100644 libs/libsodium/src/include/sodium/crypto_secretbox_xchacha20poly1305.h create mode 100644 libs/libsodium/src/include/sodium/crypto_secretbox_xsalsa20poly1305.h create mode 100644 libs/libsodium/src/include/sodium/crypto_secretstream_xchacha20poly1305.h create mode 100644 libs/libsodium/src/include/sodium/crypto_shorthash.h create mode 100644 libs/libsodium/src/include/sodium/crypto_shorthash_siphash24.h create mode 100644 libs/libsodium/src/include/sodium/crypto_sign.h create mode 100644 libs/libsodium/src/include/sodium/crypto_sign_ed25519.h create mode 100644 libs/libsodium/src/include/sodium/crypto_sign_edwards25519sha512batch.h create mode 100644 libs/libsodium/src/include/sodium/crypto_stream.h create mode 100644 libs/libsodium/src/include/sodium/crypto_stream_chacha20.h create mode 100644 libs/libsodium/src/include/sodium/crypto_stream_salsa20.h create mode 100644 libs/libsodium/src/include/sodium/crypto_stream_salsa2012.h create mode 100644 libs/libsodium/src/include/sodium/crypto_stream_salsa208.h create mode 100644 libs/libsodium/src/include/sodium/crypto_stream_xchacha20.h create mode 100644 libs/libsodium/src/include/sodium/crypto_stream_xsalsa20.h create mode 100644 libs/libsodium/src/include/sodium/crypto_verify_16.h create mode 100644 libs/libsodium/src/include/sodium/crypto_verify_32.h create mode 100644 libs/libsodium/src/include/sodium/crypto_verify_64.h create mode 100644 libs/libsodium/src/include/sodium/export.h create mode 100644 libs/libsodium/src/include/sodium/private/common.h create mode 100644 libs/libsodium/src/include/sodium/private/ed25519_ref10.h create mode 100644 libs/libsodium/src/include/sodium/private/ed25519_ref10_fe_25_5.h create mode 100644 libs/libsodium/src/include/sodium/private/ed25519_ref10_fe_51.h create mode 100644 libs/libsodium/src/include/sodium/private/implementations.h create mode 100644 libs/libsodium/src/include/sodium/private/mutex.h create mode 100644 libs/libsodium/src/include/sodium/private/sse2_64_32.h create mode 100644 libs/libsodium/src/include/sodium/randombytes.h create mode 100644 libs/libsodium/src/include/sodium/randombytes_nativeclient.h create mode 100644 libs/libsodium/src/include/sodium/randombytes_salsa20_random.h create mode 100644 libs/libsodium/src/include/sodium/randombytes_sysrandom.h create mode 100644 libs/libsodium/src/include/sodium/runtime.h create mode 100644 libs/libsodium/src/include/sodium/utils.h create mode 100644 libs/libsodium/src/include/sodium/version.h create mode 100644 libs/libsodium/src/randombytes/nativeclient/randombytes_nativeclient.c create mode 100644 libs/libsodium/src/randombytes/randombytes.c create mode 100644 libs/libsodium/src/randombytes/salsa20/randombytes_salsa20_random.c create mode 100644 libs/libsodium/src/randombytes/sysrandom/randombytes_sysrandom.c create mode 100644 libs/libsodium/src/sodium/codecs.c create mode 100644 libs/libsodium/src/sodium/core.c create mode 100644 libs/libsodium/src/sodium/runtime.c create mode 100644 libs/libsodium/src/sodium/utils.c create mode 100644 libs/libsodium/src/sodium/version.c create mode 100644 libs/libsodium/src/stdafx.cxx create mode 100644 libs/libsodium/src/stdafx.h create mode 100644 libs/libtox/docs/CHANGELOG.md create mode 100644 libs/libtox/docs/COPYING create mode 100644 libs/libtox/docs/DONATORS create mode 100644 libs/libtox/docs/README.md create mode 100644 libs/libtox/libtox.vcxproj create mode 100644 libs/libtox/libtox.vcxproj.filters create mode 100644 libs/libtox/src/stdafx.cxx create mode 100644 libs/libtox/src/stdafx.h create mode 100644 libs/libtox/src/toxcore/DHT.c create mode 100644 libs/libtox/src/toxcore/DHT.h create mode 100644 libs/libtox/src/toxcore/LAN_discovery.c create mode 100644 libs/libtox/src/toxcore/LAN_discovery.h create mode 100644 libs/libtox/src/toxcore/Messenger.c create mode 100644 libs/libtox/src/toxcore/Messenger.h create mode 100644 libs/libtox/src/toxcore/TCP_client.c create mode 100644 libs/libtox/src/toxcore/TCP_client.h create mode 100644 libs/libtox/src/toxcore/TCP_connection.c create mode 100644 libs/libtox/src/toxcore/TCP_connection.h create mode 100644 libs/libtox/src/toxcore/TCP_server.c create mode 100644 libs/libtox/src/toxcore/TCP_server.h create mode 100644 libs/libtox/src/toxcore/ccompat.h create mode 100644 libs/libtox/src/toxcore/crypto_core.api.h create mode 100644 libs/libtox/src/toxcore/crypto_core.c create mode 100644 libs/libtox/src/toxcore/crypto_core.h create mode 100644 libs/libtox/src/toxcore/crypto_core_mem.c create mode 100644 libs/libtox/src/toxcore/friend_connection.c create mode 100644 libs/libtox/src/toxcore/friend_connection.h create mode 100644 libs/libtox/src/toxcore/friend_requests.c create mode 100644 libs/libtox/src/toxcore/friend_requests.h create mode 100644 libs/libtox/src/toxcore/group.c create mode 100644 libs/libtox/src/toxcore/group.h create mode 100644 libs/libtox/src/toxcore/list.c create mode 100644 libs/libtox/src/toxcore/list.h create mode 100644 libs/libtox/src/toxcore/logger.c create mode 100644 libs/libtox/src/toxcore/logger.h create mode 100644 libs/libtox/src/toxcore/net_crypto.c create mode 100644 libs/libtox/src/toxcore/net_crypto.h create mode 100644 libs/libtox/src/toxcore/network.c create mode 100644 libs/libtox/src/toxcore/network.h create mode 100644 libs/libtox/src/toxcore/onion.c create mode 100644 libs/libtox/src/toxcore/onion.h create mode 100644 libs/libtox/src/toxcore/onion_announce.c create mode 100644 libs/libtox/src/toxcore/onion_announce.h create mode 100644 libs/libtox/src/toxcore/onion_client.c create mode 100644 libs/libtox/src/toxcore/onion_client.h create mode 100644 libs/libtox/src/toxcore/ping.c create mode 100644 libs/libtox/src/toxcore/ping.h create mode 100644 libs/libtox/src/toxcore/ping_array.c create mode 100644 libs/libtox/src/toxcore/ping_array.h create mode 100644 libs/libtox/src/toxcore/tox.api.h create mode 100644 libs/libtox/src/toxcore/tox.c create mode 100644 libs/libtox/src/toxcore/tox.h create mode 100644 libs/libtox/src/toxcore/tox_api.c create mode 100644 libs/libtox/src/toxcore/util.c create mode 100644 libs/libtox/src/toxcore/util.h create mode 100644 libs/libtox/src/toxdns/Makefile.inc create mode 100644 libs/libtox/src/toxdns/toxdns.c create mode 100644 libs/libtox/src/toxdns/toxdns.h create mode 100644 libs/libtox/src/toxencryptsave/Makefile.inc create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c create mode 100644 libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h create mode 100644 libs/libtox/src/toxencryptsave/defines.h create mode 100644 libs/libtox/src/toxencryptsave/toxencryptsave.api.h create mode 100644 libs/libtox/src/toxencryptsave/toxencryptsave.c create mode 100644 libs/libtox/src/toxencryptsave/toxencryptsave.h create mode 100644 libs/pthreads/docs/ANNOUNCE create mode 100644 libs/pthreads/docs/BUGS create mode 100644 libs/pthreads/docs/Bmakefile create mode 100644 libs/pthreads/docs/CONTRIBUTORS create mode 100644 libs/pthreads/docs/COPYING create mode 100644 libs/pthreads/docs/ChangeLog create mode 100644 libs/pthreads/docs/FAQ create mode 100644 libs/pthreads/docs/GNUmakefile create mode 100644 libs/pthreads/docs/MAINTAINERS create mode 100644 libs/pthreads/docs/Makefile create mode 100644 libs/pthreads/docs/NEWS create mode 100644 libs/pthreads/docs/Nmakefile create mode 100644 libs/pthreads/docs/PROGRESS create mode 100644 libs/pthreads/docs/README create mode 100644 libs/pthreads/docs/TODO create mode 100644 libs/pthreads/docs/WinCE-PORT create mode 100644 libs/pthreads/pthreads.vcxproj create mode 100644 libs/pthreads/pthreads.vcxproj.filters create mode 100644 libs/pthreads/src/attr.c create mode 100644 libs/pthreads/src/autostatic.c create mode 100644 libs/pthreads/src/barrier.c create mode 100644 libs/pthreads/src/cancel.c create mode 100644 libs/pthreads/src/cleanup.c create mode 100644 libs/pthreads/src/condvar.c create mode 100644 libs/pthreads/src/config.h create mode 100644 libs/pthreads/src/context.h create mode 100644 libs/pthreads/src/create.c create mode 100644 libs/pthreads/src/dll.c create mode 100644 libs/pthreads/src/errno.c create mode 100644 libs/pthreads/src/exit.c create mode 100644 libs/pthreads/src/fork.c create mode 100644 libs/pthreads/src/global.c create mode 100644 libs/pthreads/src/implement.h create mode 100644 libs/pthreads/src/misc.c create mode 100644 libs/pthreads/src/mutex.c create mode 100644 libs/pthreads/src/need_errno.h create mode 100644 libs/pthreads/src/nonportable.c create mode 100644 libs/pthreads/src/private.c create mode 100644 libs/pthreads/src/pthread.c create mode 100644 libs/pthreads/src/pthread.h create mode 100644 libs/pthreads/src/pthread_attr_destroy.c create mode 100644 libs/pthreads/src/pthread_attr_getdetachstate.c create mode 100644 libs/pthreads/src/pthread_attr_getinheritsched.c create mode 100644 libs/pthreads/src/pthread_attr_getschedparam.c create mode 100644 libs/pthreads/src/pthread_attr_getschedpolicy.c create mode 100644 libs/pthreads/src/pthread_attr_getscope.c create mode 100644 libs/pthreads/src/pthread_attr_getstackaddr.c create mode 100644 libs/pthreads/src/pthread_attr_getstacksize.c create mode 100644 libs/pthreads/src/pthread_attr_init.c create mode 100644 libs/pthreads/src/pthread_attr_setdetachstate.c create mode 100644 libs/pthreads/src/pthread_attr_setinheritsched.c create mode 100644 libs/pthreads/src/pthread_attr_setschedparam.c create mode 100644 libs/pthreads/src/pthread_attr_setschedpolicy.c create mode 100644 libs/pthreads/src/pthread_attr_setscope.c create mode 100644 libs/pthreads/src/pthread_attr_setstackaddr.c create mode 100644 libs/pthreads/src/pthread_attr_setstacksize.c create mode 100644 libs/pthreads/src/pthread_barrier_destroy.c create mode 100644 libs/pthreads/src/pthread_barrier_init.c create mode 100644 libs/pthreads/src/pthread_barrier_wait.c create mode 100644 libs/pthreads/src/pthread_barrierattr_destroy.c create mode 100644 libs/pthreads/src/pthread_barrierattr_getpshared.c create mode 100644 libs/pthreads/src/pthread_barrierattr_init.c create mode 100644 libs/pthreads/src/pthread_barrierattr_setpshared.c create mode 100644 libs/pthreads/src/pthread_cancel.c create mode 100644 libs/pthreads/src/pthread_cond_destroy.c create mode 100644 libs/pthreads/src/pthread_cond_init.c create mode 100644 libs/pthreads/src/pthread_cond_signal.c create mode 100644 libs/pthreads/src/pthread_cond_wait.c create mode 100644 libs/pthreads/src/pthread_condattr_destroy.c create mode 100644 libs/pthreads/src/pthread_condattr_getpshared.c create mode 100644 libs/pthreads/src/pthread_condattr_init.c create mode 100644 libs/pthreads/src/pthread_condattr_setpshared.c create mode 100644 libs/pthreads/src/pthread_delay_np.c create mode 100644 libs/pthreads/src/pthread_detach.c create mode 100644 libs/pthreads/src/pthread_equal.c create mode 100644 libs/pthreads/src/pthread_exit.c create mode 100644 libs/pthreads/src/pthread_getconcurrency.c create mode 100644 libs/pthreads/src/pthread_getschedparam.c create mode 100644 libs/pthreads/src/pthread_getspecific.c create mode 100644 libs/pthreads/src/pthread_getunique_np.c create mode 100644 libs/pthreads/src/pthread_getw32threadhandle_np.c create mode 100644 libs/pthreads/src/pthread_join.c create mode 100644 libs/pthreads/src/pthread_key_create.c create mode 100644 libs/pthreads/src/pthread_key_delete.c create mode 100644 libs/pthreads/src/pthread_kill.c create mode 100644 libs/pthreads/src/pthread_mutex_consistent.c create mode 100644 libs/pthreads/src/pthread_mutex_destroy.c create mode 100644 libs/pthreads/src/pthread_mutex_init.c create mode 100644 libs/pthreads/src/pthread_mutex_lock.c create mode 100644 libs/pthreads/src/pthread_mutex_timedlock.c create mode 100644 libs/pthreads/src/pthread_mutex_trylock.c create mode 100644 libs/pthreads/src/pthread_mutex_unlock.c create mode 100644 libs/pthreads/src/pthread_mutexattr_destroy.c create mode 100644 libs/pthreads/src/pthread_mutexattr_getkind_np.c create mode 100644 libs/pthreads/src/pthread_mutexattr_getpshared.c create mode 100644 libs/pthreads/src/pthread_mutexattr_getrobust.c create mode 100644 libs/pthreads/src/pthread_mutexattr_gettype.c create mode 100644 libs/pthreads/src/pthread_mutexattr_init.c create mode 100644 libs/pthreads/src/pthread_mutexattr_setkind_np.c create mode 100644 libs/pthreads/src/pthread_mutexattr_setpshared.c create mode 100644 libs/pthreads/src/pthread_mutexattr_setrobust.c create mode 100644 libs/pthreads/src/pthread_mutexattr_settype.c create mode 100644 libs/pthreads/src/pthread_num_processors_np.c create mode 100644 libs/pthreads/src/pthread_once.c create mode 100644 libs/pthreads/src/pthread_rwlock_destroy.c create mode 100644 libs/pthreads/src/pthread_rwlock_init.c create mode 100644 libs/pthreads/src/pthread_rwlock_rdlock.c create mode 100644 libs/pthreads/src/pthread_rwlock_timedrdlock.c create mode 100644 libs/pthreads/src/pthread_rwlock_timedwrlock.c create mode 100644 libs/pthreads/src/pthread_rwlock_tryrdlock.c create mode 100644 libs/pthreads/src/pthread_rwlock_trywrlock.c create mode 100644 libs/pthreads/src/pthread_rwlock_unlock.c create mode 100644 libs/pthreads/src/pthread_rwlock_wrlock.c create mode 100644 libs/pthreads/src/pthread_rwlockattr_destroy.c create mode 100644 libs/pthreads/src/pthread_rwlockattr_getpshared.c create mode 100644 libs/pthreads/src/pthread_rwlockattr_init.c create mode 100644 libs/pthreads/src/pthread_rwlockattr_setpshared.c create mode 100644 libs/pthreads/src/pthread_self.c create mode 100644 libs/pthreads/src/pthread_setcancelstate.c create mode 100644 libs/pthreads/src/pthread_setcanceltype.c create mode 100644 libs/pthreads/src/pthread_setconcurrency.c create mode 100644 libs/pthreads/src/pthread_setschedparam.c create mode 100644 libs/pthreads/src/pthread_setspecific.c create mode 100644 libs/pthreads/src/pthread_spin_destroy.c create mode 100644 libs/pthreads/src/pthread_spin_init.c create mode 100644 libs/pthreads/src/pthread_spin_lock.c create mode 100644 libs/pthreads/src/pthread_spin_trylock.c create mode 100644 libs/pthreads/src/pthread_spin_unlock.c create mode 100644 libs/pthreads/src/pthread_testcancel.c create mode 100644 libs/pthreads/src/pthread_timechange_handler_np.c create mode 100644 libs/pthreads/src/pthread_win32_attach_detach_np.c create mode 100644 libs/pthreads/src/ptw32_MCS_lock.c create mode 100644 libs/pthreads/src/ptw32_OLL_lock.c create mode 100644 libs/pthreads/src/ptw32_callUserDestroyRoutines.c create mode 100644 libs/pthreads/src/ptw32_calloc.c create mode 100644 libs/pthreads/src/ptw32_cond_check_need_init.c create mode 100644 libs/pthreads/src/ptw32_getprocessors.c create mode 100644 libs/pthreads/src/ptw32_is_attr.c create mode 100644 libs/pthreads/src/ptw32_mutex_check_need_init.c create mode 100644 libs/pthreads/src/ptw32_new.c create mode 100644 libs/pthreads/src/ptw32_processInitialize.c create mode 100644 libs/pthreads/src/ptw32_processTerminate.c create mode 100644 libs/pthreads/src/ptw32_relmillisecs.c create mode 100644 libs/pthreads/src/ptw32_reuse.c create mode 100644 libs/pthreads/src/ptw32_rwlock_cancelwrwait.c create mode 100644 libs/pthreads/src/ptw32_rwlock_check_need_init.c create mode 100644 libs/pthreads/src/ptw32_semwait.c create mode 100644 libs/pthreads/src/ptw32_spinlock_check_need_init.c create mode 100644 libs/pthreads/src/ptw32_threadDestroy.c create mode 100644 libs/pthreads/src/ptw32_threadStart.c create mode 100644 libs/pthreads/src/ptw32_throw.c create mode 100644 libs/pthreads/src/ptw32_timespec.c create mode 100644 libs/pthreads/src/ptw32_tkAssocCreate.c create mode 100644 libs/pthreads/src/ptw32_tkAssocDestroy.c create mode 100644 libs/pthreads/src/rwlock.c create mode 100644 libs/pthreads/src/sched.c create mode 100644 libs/pthreads/src/sched.h create mode 100644 libs/pthreads/src/sched_get_priority_max.c create mode 100644 libs/pthreads/src/sched_get_priority_min.c create mode 100644 libs/pthreads/src/sched_getscheduler.c create mode 100644 libs/pthreads/src/sched_setscheduler.c create mode 100644 libs/pthreads/src/sched_yield.c create mode 100644 libs/pthreads/src/sem_close.c create mode 100644 libs/pthreads/src/sem_destroy.c create mode 100644 libs/pthreads/src/sem_getvalue.c create mode 100644 libs/pthreads/src/sem_init.c create mode 100644 libs/pthreads/src/sem_open.c create mode 100644 libs/pthreads/src/sem_post.c create mode 100644 libs/pthreads/src/sem_post_multiple.c create mode 100644 libs/pthreads/src/sem_timedwait.c create mode 100644 libs/pthreads/src/sem_trywait.c create mode 100644 libs/pthreads/src/sem_unlink.c create mode 100644 libs/pthreads/src/sem_wait.c create mode 100644 libs/pthreads/src/semaphore.c create mode 100644 libs/pthreads/src/semaphore.h create mode 100644 libs/pthreads/src/signal.c create mode 100644 libs/pthreads/src/spin.c create mode 100644 libs/pthreads/src/sync.c create mode 100644 libs/pthreads/src/tsd.c create mode 100644 libs/pthreads/src/w32_CancelableWait.c (limited to 'libs') diff --git a/libs/libsodium/docs/AUTHORS b/libs/libsodium/docs/AUTHORS new file mode 100644 index 0000000000..39e55f6288 --- /dev/null +++ b/libs/libsodium/docs/AUTHORS @@ -0,0 +1,135 @@ + +Designers +========= + +argon2 Alex Biryukov + Daniel Dinu + Dmitry Khovratovich + +blake2 Jean-Philippe Aumasson + Christian Winnerlein + Samuel Neves + Zooko Wilcox-O'Hearn + +chacha20 Daniel J. Bernstein + +chacha20poly1305 Adam Langley + Yoav Nir + +curve25519 Daniel J. Bernstein + +curve25519xsalsa20poly1305 Daniel J. Bernstein + +ed25519 Daniel J. Bernstein + Bo-Yin Yang + Niels Duif + Peter Schwabe + Tanja Lange + +poly1305 Daniel J. Bernstein + +salsa20 Daniel J. Bernstein + +scrypt Colin Percival + +siphash Jean-Philippe Aumasson + Daniel J. Bernstein + +Implementors +============ + +crypto_aead/aes256gcm/aesni Romain Dolbeau + Frank Denis + +crypto_aead/chacha20poly1305 Frank Denis + +crypto_aead/xchacha20poly1305 Frank Denis + Jason A. Donenfeld + +crypto_auth/hmacsha256 Colin Percival +crypto_auth/hmacsha512 +crypto_auth/hmacsha512256 + +crypto_box/curve25519xsalsa20poly1305 Daniel J. Bernstein + +crypto_box/curve25519xchacha20poly1305 Frank Denis + +crypto_core/ed25519 Daniel J. Bernstein + Adam Langley + +crypto_core/hchacha20 Frank Denis + +crypto_core/hsalsa20 Daniel J. Bernstein +crypto_core/salsa + +crypto_generichash/blake2b Jean-Philippe Aumasson + Christian Winnerlein + Samuel Neves + Zooko Wilcox-O'Hearn + +crypto_hash/sha256 Colin Percival +crypto_hash/sha512 +crypto_hash/sha512256 + +crypto_kdf Frank Denis + +crypto_kx Frank Denis + +crypto_onetimeauth/poly1305/donna Andrew "floodyberry" Moon +crypto_onetimeauth/poly1305/sse2 + +crypto_pwhash/argon2 Samuel Neves + Dmitry Khovratovich + Jean-Philippe Aumasson + Daniel Dinu + Thomas Pornin + +crypto_pwhash/scryptsalsa208sha256 Colin Percival + Alexander Peslyak + +crypto_scalarmult/curve25519/ref10 Daniel J. Bernstein + +crypto_scalarmult/curve25519/sandy2x Tung Chou + +crypto_scalarmult/ed25519 Frank Denis + +crypto_secretbox/xsalsa20poly1305 Daniel J. Bernstein + +crypto_secretbox/xchacha20poly1305 Frank Denis + +crypto_secretstream/xchacha20poly1305 Frank Denis + +crypto_shorthash/siphash24 Jean-Philippe Aumasson + Daniel J. Bernstein + +crypto_sign/ed25519 Peter Schwabe + Daniel J. Bernstein + Niels Duif + Tanja Lange + Bo-Yin Yang + +crypto_stream/chacha20/ref Daniel J. Bernstein + +crypto_stream/chacha20/dolbeau Romain Dolbeau + Daniel J. Bernstein + +crypto_stream/salsa20/ref Daniel J. Bernstein +crypto_stream/salsa20/xmm6 + +crypto_stream/salsa20/xmm6int Romain Dolbeau + Daniel J. Bernstein + +crypto_stream/salsa2012/ref Daniel J. Bernstein +crypto_stream/salsa2008/ref + +crypto_stream/xchacha20 Frank Denis + +crypto_verify Frank Denis + +sodium/codecs.c Frank Denis + Thomas Pornin + Christian Winnerlein + +sodium/core.c Frank Denis +sodium/runtime.h +sodium/utils.c diff --git a/libs/libsodium/docs/ChangeLog b/libs/libsodium/docs/ChangeLog new file mode 100644 index 0000000000..2c6f7f1777 --- /dev/null +++ b/libs/libsodium/docs/ChangeLog @@ -0,0 +1,505 @@ + +* Version 1.0.16 + - Signatures computations and verifications are now way faster on +64-bit platforms with compilers supporting 128-bit arithmetic (gcc, +clang, icc). This includes the WebAssembly target. + - New low-level APIs for computations over edwards25519: +`crypto_scalarmult_ed25519()`, `crypto_scalarmult_ed25519_base()`, +`crypto_core_ed25519_is_valid_point()`, `crypto_core_ed25519_add()`, +`crypto_core_ed25519_sub()` and `crypto_core_ed25519_from_uniform()` +(elligator representative to point). + - `crypto_sign_open()`, `crypto_sign_verify_detached() and +`crypto_sign_edwards25519sha512batch_open` now reject public keys in +non-canonical form in addition to low-order points. + - The library can be built with `ED25519_NONDETERMINISTIC` defined in +order to use synthetic nonces for EdDSA. This is disabled by default. + - Webassembly: `crypto_pwhash_*()` functions are now included in +non-sumo builds. + - `sodium_stackzero()` was added to wipe content off the stack. + - Android: support new SDKs where unified headers have become the +default. + - The Salsa20-based PRNG example is now thread-safe on platforms with +support for thread-local storage, optionally mixes bits from RDRAND. + - CMAKE: static library detection on Unix systems has been improved +(thanks to @BurningEnlightenment, @nibua-r, @mellery451) + - Argon2 and scrypt are slightly faster on Linux. + +* Version 1.0.15 + - The default password hashing algorithm is now Argon2id. The +`pwhash_str_verify()` function can still verify Argon2i hashes +without any changes, and `pwhash()` can still compute Argon2i hashes +as well. + - The aes128ctr primitive was removed. It was slow, non-standard, not +authenticated, and didn't seem to be used by any opensource project. + - Argon2id required at least 3 passes like Argon2i, despite a minimum +of `1` as defined by the `OPSLIMIT_MIN` constant. This has been fixed. + - The secretstream construction was slightly changed to be consistent +with forthcoming variants. + - The Javascript and Webassembly versions have been merged, and the +module now returns a `.ready` promise that will resolve after the +Webassembly code is loaded and compiled. + - Note that due to these incompatible changes, the library version +major was bumped up. + +* Version 1.0.14 + - iOS binaries should now be compatible with WatchOS and TVOS. + - WebAssembly is now officially supported. Special thanks to +@facekapow and @pepyakin who helped to make it happen. + - Internal consistency checks failing and primitives used with +dangerous/out-of-bounds/invalid parameters used to call abort(3). +Now, a custom handler *that doesn't return* can be set with the +`set_sodium_misuse()` function. It still aborts by default or if the +handler ever returns. This is not a replacement for non-fatal, +expected runtime errors. This handler will be only called in +unexpected situations due to potential bugs in the library or in +language bindings. + - `*_MESSAGEBYTES_MAX` macros (and the corresponding +`_messagebytes_max()` symbols) have been added to represent the +maximum message size that can be safely handled by a primitive. +Language bindings are encouraged to check user inputs against these +maximum lengths. + - The test suite has been extended to cover more edge cases. + - crypto_sign_ed25519_pk_to_curve25519() now rejects points that are +not on the curve, or not in the main subgroup. + - Further changes have been made to ensure that smart compilers will +not optimize out code that we don't want to be optimized. + - Visual Studio solutions are now included in distribution tarballs. + - The `sodium_runtime_has_*` symbols for CPU features detection are +now defined as weak symbols, i.e. they can be replaced with an +application-defined implementation. This can be useful to disable +AVX* when temperature/power consumption is a concern. + - `crypto_kx_*()` now aborts if called with no non-NULL pointers to +store keys to. + - SSE2 implementations of `crypto_verify_*()` have been added. + - Passwords can be hashed using a specific algorithm with the new +`crypto_pwhash_str_alg()` function. + - Due to popular demand, base64 encoding (`sodium_bin2base64()`) and +decoding (`sodium_base642bin()`) have been implemented. + - A new `crypto_secretstream_*()` API was added to safely encrypt files +and multi-part messages. + - The `sodium_pad()` and `sodium_unpad()` helper functions have been +added in order to add & remove padding. + - An AVX512 optimized implementation of Argon2 has been added (written +by Ondrej Mosnáček, thanks!) + - The `crypto_pwhash_str_needs_rehash()` function was added to check if +a password hash string matches the given parameters, or if it needs an +update. + - The library can now be compiled with recent versions of +emscripten/binaryen that don't allow multiple variables declarations +using a single `var` statement. + +* Version 1.0.13 + - Javascript: the sumo builds now include all symbols. They were +previously limited to symbols defined in minimal builds. + - The public `crypto_pwhash_argon2i_MEMLIMIT_MAX` constant was +incorrectly defined on 32-bit platforms. This has been fixed. + - Version 1.0.12 didn't compile on OpenBSD/i386 using the base gcc +compiler. This has been fixed. + - The Android compilation scripts have been updated for NDK r14b. + - armv7s-optimized code was re-added to iOS builds. + - An AVX2 optimized implementation of the Argon2 round function was +added. + - The Argon2id variant of Argon2 has been implemented. The +high-level `crypto_pwhash_str_verify()` function automatically detects +the algorithm and can verify both Argon2i and Argon2id hashed passwords. +The default algorithm for newly hashed passwords remains Argon2i in +this version to avoid breaking compatibility with verifiers running +libsodium <= 1.0.12. + - A `crypto_box_curve25519xchacha20poly1305_seal*()` function set was +implemented. + - scrypt was removed from minimal builds. + - libsodium is now available on NuGet. + +* Version 1.0.12 + - Ed25519ph was implemented, adding a multi-part signature API +(`crypto_sign_init()`, `crypto_sign_update()`, `crypto_sign_final_*()`). + - New constants and related accessors have been added for Scrypt and +Argon2. + - XChaCha20 has been implemented. Like XSalsa20, this construction +extends the ChaCha20 cipher to accept a 192-bit nonce. This makes it safe +to use ChaCha20 with random nonces. + - `crypto_secretbox`, `crypto_box` and `crypto_aead` now offer +variants leveraging XChaCha20. + - SHA-2 is about 20% faster, which also gives a speed boost to +signature and signature verification. + - AVX2 implementations of Salsa20 and ChaCha20 have been added. They +are twice as fast as the SSE2 implementations. The speed gain is +even more significant on Windows, that previously didn't use +vectorized implementations. + - New high-level API: `crypto_kdf`, to easily derive one or more +subkeys from a master key. + - Siphash with a 128-bit output has been implemented, and is +available as `crypto_shorthash_siphashx_*`. + - New `*_keygen()` helpers functions have been added to create secret +keys for all constructions. This improves code clarity and can prevent keys +from being partially initialized. + - A new `randombytes_buf_deterministic()` function was added to +deterministically fill a memory region with pseudorandom data. This +function can especially be useful to write reproducible tests. + - A preliminary `crypto_kx_*()` API was added to compute shared session +keys. + - AVX2 detection is more reliable. + - The pthreads library is not required any more when using MingW. + - `contrib/Findsodium.cmake` was added as an example to include +libsodium in a project using cmake. + - Compatibility with gcc 2.x has been restored. + - Minimal builds can be checked using `sodium_library_minimal()`. + - The `--enable-opt` compilation switch has become compatible with more +platforms. + - Android builds are now using clang on platforms where it is +available. + +* Version 1.0.11 + - `sodium_init()` is now thread-safe, and can be safely called multiple +times. + - Android binaries now properly support 64-bit Android, targeting +platform 24, but without breaking compatibility with platforms 16 and +21. + - Better support for old gcc versions. + - On FreeBSD, core dumps are disabled on regions allocated with +sodium allocation functions. + - AVX2 detection was fixed, resulting in faster Blake2b hashing on +platforms where it was not properly detected. + - The Sandy2x Curve25519 implementation was not as fast as expected +on some platforms. This has been fixed. + - The NativeClient target was improved. Most notably, it now supports +optimized implementations, and uses pepper_49 by default. + - The library can be compiled with recent Emscripten versions. +Changes have been made to produce smaller code, and the default heap +size was reduced in the standard version. + - The code can now be compiled on SLES11 service pack 4. + - Decryption functions can now accept a NULL pointer for the output. +This checks the MAC without writing the decrypted message. + - crypto_generichash_final() now returns -1 if called twice. + - Support for Visual Studio 2008 was improved. + +* Version 1.0.10 + - This release only fixes a compilation issue reported with some older +gcc versions. There are no functional changes over the previous release. + +* Version 1.0.9 + - The Javascript target now includes a `--sumo` option to include all +the symbols of the original C library. + - A detached API was added to the ChaCha20-Poly1305 and AES256-GCM +implementations. + - The Argon2i password hashing function was added, and is accessible +directly and through a new, high-level `crypto_pwhash` API. The scrypt +function remains available as well. + - A speed-record AVX2 implementation of BLAKE2b was added (thanks to +Samuel Neves). + - The library can now be compiled using C++Builder (thanks to @jcolli44) + - Countermeasures for Ed25519 signatures malleability have been added +to match the irtf-cfrg-eddsa draft (note that malleability is irrelevant to +the standard definition of signature security). Signatures with a small-order +`R` point are now also rejected. + - Some implementations are now slightly faster when using the Clang +compiler. + - The HChaCha20 core function was implemented (`crypto_core_hchacha20()`). + - No-op stubs were added for all AES256-GCM public functions even when +compiled on non-Intel platforms. + - `crypt_generichash_blake2b_statebytes()` was added. + - New macros were added for the IETF variant of the ChaCha20-Poly1305 +construction. + - The library can now be compiled on Minix. + - HEASLR is now enabled on MinGW builds. + +* Version 1.0.8 + - Handle the case where the CPU supports AVX, but we are running +on an hypervisor with AVX disabled/not supported. + - Faster (2x) scalarmult_base() when using the ref10 implementation. + +* Version 1.0.7 + - More functions whose return value should be checked have been +tagged with `__attribute__ ((warn_unused_result))`: `crypto_box_easy()`, +`crypto_box_detached()`, `crypto_box_beforenm()`, `crypto_box()`, and +`crypto_scalarmult()`. + - Sandy2x, the fastest Curve25519 implementation ever, has been +merged in, and is automatically used on CPUs supporting the AVX +instructions set. + - An SSE2 optimized implementation of Poly1305 was added, and is +twice as fast as the portable one. + - An SSSE3 optimized implementation of ChaCha20 was added, and is +twice as fast as the portable one. + - Faster `sodium_increment()` for common nonce sizes. + - New helper functions have been added: `sodium_is_zero()` and + `sodium_add()`. + - `sodium_runtime_has_aesni()` now properly detects the CPU flag when + compiled using Visual Studio. + +* Version 1.0.6 + - Optimized implementations of Blake2 have been added for modern +Intel platforms. `crypto_generichash()` is now faster than MD5 and SHA1 +implementations while being far more secure. + - Functions for which the return value should be checked have been +tagged with `__attribute__ ((warn_unused_result))`. This will +intentionally break code compiled with `-Werror` that didn't bother +checking critical return values. + - The `crypto_sign_edwards25519sha512batch_*()` functions have been +tagged as deprecated. + - Undocumented symbols that were exported, but were only useful for +internal purposes have been removed or made private: +`sodium_runtime_get_cpu_features()`, the implementation-specific +`crypto_onetimeauth_poly1305_donna()` symbols, +`crypto_onetimeauth_poly1305_set_implementation()`, +`crypto_onetimeauth_poly1305_implementation_name()` and +`crypto_onetimeauth_pick_best_implementation()`. + - `sodium_compare()` now works as documented, and compares numbers +in little-endian format instead of behaving like `memcmp()`. + - The previous changes should not break actual applications, but to be +safe, the library version major was incremented. + - `sodium_runtime_has_ssse3()` and `sodium_runtime_has_sse41()` have +been added. + - The library can now be compiled with the CompCert compiler. + +* Version 1.0.5 + - Compilation issues on some platforms were fixed: missing alignment +directives were added (required at least on RHEL-6/i386), a workaround +for a VRP bug on gcc/armv7 was added, and the library can now be compiled +with the SunPro compiler. + - Javascript target: io.js is not supported any more. Use nodejs. + +* Version 1.0.4 + - Support for AES256-GCM has been added. This requires +a CPU with the aesni and pclmul extensions, and is accessible via the +crypto_aead_aes256gcm_*() functions. + - The Javascript target doesn't use eval() any more, so that the +library can be used in Chrome packaged applications. + - QNX and CloudABI are now supported. + - Support for NaCl has finally been added. + - ChaCha20 with an extended (96 bit) nonce and a 32-bit counter has +been implemented as crypto_stream_chacha20_ietf(), +crypto_stream_chacha20_ietf_xor() and crypto_stream_chacha20_ietf_xor_ic(). +An IETF-compatible version of ChaCha20Poly1305 is available as +crypto_aead_chacha20poly1305_ietf_npubbytes(), +crypto_aead_chacha20poly1305_ietf_encrypt() and +crypto_aead_chacha20poly1305_ietf_decrypt(). + - The sodium_increment() helper function has been added, to increment +an arbitrary large number (such as a nonce). + - The sodium_compare() helper function has been added, to compare +arbitrary large numbers (such as nonces, in order to prevent replay +attacks). + +* Version 1.0.3 + - In addition to sodium_bin2hex(), sodium_hex2bin() is now a +constant-time function. + - crypto_stream_xsalsa20_ic() has been added. + - crypto_generichash_statebytes(), crypto_auth_*_statebytes() and +crypto_hash_*_statebytes() have been added in order to retrieve the +size of structures keeping states from foreign languages. + - The JavaScript target doesn't require /dev/urandom or an external +randombytes() implementation any more. Other minor Emscripten-related +improvements have been made in order to support libsodium.js + - Custom randombytes implementations do not need to provide their own +implementation of randombytes_uniform() any more. randombytes_stir() +and randombytes_close() can also be NULL pointers if they are not +required. + - On Linux, getrandom(2) is being used instead of directly accessing +/dev/urandom, if the kernel supports this system call. + - crypto_box_seal() and crypto_box_seal_open() have been added. + - Visual Studio 2015 is now supported. + +* Version 1.0.2 + - The _easy and _detached APIs now support precalculated keys; +crypto_box_easy_afternm(), crypto_box_open_easy_afternm(), +crypto_box_detached_afternm() and crypto_box_open_detached_afternm() +have been added as an alternative to the NaCl interface. + - Memory allocation functions can now be used on operating systems with +no memory protection. + - crypto_sign_open() and crypto_sign_edwards25519sha512batch_open() +now accept a NULL pointer instead of a pointer to the message size, if +storing this information is not required. + - The close-on-exec flag is now set on the descriptor returned when +opening /dev/urandom. + - A libsodium-uninstalled.pc file to use pkg-config even when +libsodium is not installed, has been added. + - The iOS target now includes armv7s and arm64 optimized code, as well +as i386 and x86_64 code for the iOS simulator. + - sodium_free() can now be called on regions with PROT_NONE protection. + - The Javascript tests can run on Ubuntu, where the node binary was +renamed nodejs. io.js can also be used instead of node. + +* Version 1.0.1 + - DLL_EXPORT was renamed SODIUM_DLL_EXPORT in order to avoid +collisions with similar macros defined by other libraries. + - sodium_bin2hex() is now constant-time. + - crypto_secretbox_detached() now supports overlapping input and output +regions. + - NaCl's donna_c64 implementation of curve25519 was reading an extra byte +past the end of the buffer containing the base point. This has been +fixed. + +* Version 1.0.0 + - The API and ABI are now stable. New features will be added, but +backward-compatibility is guaranteed through all the 1.x.y releases. + - crypto_sign() properly works with overlapping regions again. Thanks +to @pysiak for reporting this regression introduced in version 0.6.1. + - The test suite has been extended. + +* Version 0.7.1 (1.0 RC2) + - This is the second release candidate of Sodium 1.0. Minor +compilation, readability and portability changes have been made and the +test suite was improved, but the API is the same as the previous release +candidate. + +* Version 0.7.0 (1.0 RC1) + - Allocating memory to store sensitive data can now be done using +sodium_malloc() and sodium_allocarray(). These functions add guard +pages around the protected data to make it less likely to be +accessible in a heartbleed-like scenario. In addition, the protection +for memory regions allocated that way can be changed using +sodium_mprotect_noaccess(), sodium_mprotect_readonly() and +sodium_mprotect_readwrite(). + - ed25519 keys can be converted to curve25519 keys with +crypto_sign_ed25519_pk_to_curve25519() and +crypto_sign_ed25519_sk_to_curve25519(). This allows using the same +keys for signature and encryption. + - The seed and the public key can be extracted from an ed25519 key +using crypto_sign_ed25519_sk_to_seed() and crypto_sign_ed25519_sk_to_pk(). + - aes256 was removed. A timing-attack resistant implementation might +be added later, but not before version 1.0 is tagged. + - The crypto_pwhash_scryptxsalsa208sha256_* compatibility layer was +removed. Use crypto_pwhash_scryptsalsa208sha256_*. + - The compatibility layer for implementation-specific functions was +removed. + - Compilation issues with Mingw64 on MSYS (not MSYS2) were fixed. + - crypto_pwhash_scryptsalsa208sha256_STRPREFIX was added: it contains +the prefix produced by crypto_pwhash_scryptsalsa208sha256_str() + +* Version 0.6.1 + - Important bug fix: when crypto_sign_open() was given a signed +message too short to even contain a signature, it was putting an +unlimited amount of zeros into the target buffer instead of +immediately returning -1. The bug was introduced in version 0.5.0. + - New API: crypto_sign_detached() and crypto_sign_verify_detached() +to produce and verify ed25519 signatures without having to duplicate +the message. + - New ./configure switch: --enable-minimal, to create a smaller +library, with only the functions required for the high-level API. +Mainly useful for the JavaScript target and embedded systems. + - All the symbols are now exported by the Emscripten build script. + - The pkg-config .pc file is now always installed even if the +pkg-config tool is not available during the installation. + +* Version 0.6.0 + - The ChaCha20 stream cipher has been added, as crypto_stream_chacha20_* + - The ChaCha20Poly1305 AEAD construction has been implemented, as +crypto_aead_chacha20poly1305_* + - The _easy API does not require any heap allocations any more and +does not have any overhead over the NaCl API. With the password +hashing function being an obvious exception, the library doesn't +allocate and will not allocate heap memory ever. + - crypto_box and crypto_secretbox have a new _detached API to store +the authentication tag and the encrypted message separately. + - crypto_pwhash_scryptxsalsa208sha256*() functions have been renamed +crypto_pwhash_scryptsalsa208sha256*(). + - The low-level crypto_pwhash_scryptsalsa208sha256_ll() function +allows setting individual parameters of the scrypt function. + - New macros and functions for recommended crypto_pwhash_* parameters +have been added. + - Similarly to crypto_sign_seed_keypair(), crypto_box_seed_keypair() +has been introduced to deterministically generate a key pair from a seed. + - crypto_onetimeauth() now provides a streaming interface. + - crypto_stream_chacha20_xor_ic() and crypto_stream_salsa20_xor_ic() +have been added to use a non-zero initial block counter. + - On Windows, CryptGenRandom() was replaced by RtlGenRandom(), which +doesn't require the Crypt API. + - The high bit in curve25519 is masked instead of processing the key as +a 256-bit value. + - The curve25519 ref implementation was replaced by the latest ref10 +implementation from Supercop. + - sodium_mlock() now prevents memory from being included in coredumps +on Linux 3.4+ + +* Version 0.5.0 + - sodium_mlock()/sodium_munlock() have been introduced to lock pages +in memory before storing sensitive data, and to zero them before +unlocking them. + - High-level wrappers for crypto_box and crypto_secretbox +(crypto_box_easy and crypto_secretbox_easy) can be used to avoid +dealing with the specific memory layout regular functions depend on. + - crypto_pwhash_scryptsalsa208sha256* functions have been added +to derive a key from a password, and for password storage. + - Salsa20 and ed25519 implementations now support overlapping +inputs/keys/outputs (changes imported from supercop-20140505). + - New build scripts for Visual Studio, Emscripten, different Android +architectures and msys2 are available. + - The poly1305-53 implementation has been replaced with Floodyberry's +poly1305-donna32 and poly1305-donna64 implementations. + - sodium_hex2bin() has been added to complement sodium_bin2hex(). + - On OpenBSD and Bitrig, arc4random() is used instead of reading +/dev/urandom. + - crypto_auth_hmac_sha512() has been implemented. + - sha256 and sha512 now have a streaming interface. + - hmacsha256, hmacsha512 and hmacsha512256 now support keys of +arbitrary length, and have a streaming interface. + - crypto_verify_64() has been implemented. + - first-class Visual Studio build system, thanks to @evoskuil + - CPU features are now detected at runtime. + +* Version 0.4.5 + - Restore compatibility with OSX <= 10.6 + +* Version 0.4.4 + - Visual Studio is officially supported (VC 2010 & VC 2013) + - mingw64 is now supported + - big-endian architectures are now supported as well + - The donna_c64 implementation of curve25519_donna_c64 now handles +non-canonical points like the ref implementation + - Missing scalarmult_curve25519 and stream_salsa20 constants are now exported + - A crypto_onetimeauth_poly1305_ref() wrapper has been added + +* Version 0.4.3 + - crypto_sign_seedbytes() and crypto_sign_SEEDBYTES were added. + - crypto_onetimeauth_poly1305_implementation_name() was added. + - poly1305-ref has been replaced by a faster implementation, +Floodyberry's poly1305-donna-unrolled. + - Stackmarkings have been added to assembly code, for Hardened Gentoo. + - pkg-config can now be used in order to retrieve compilations flags for +using libsodium. + - crypto_stream_aes256estream_*() can now deal with unaligned input +on platforms that require word alignment. + - portability improvements. + +* Version 0.4.2 + - All NaCl constants are now also exposed as functions. + - The Android and iOS cross-compilation script have been improved. + - libsodium can now be cross-compiled to Windows from Linux. + - libsodium can now be compiled with emscripten. + - New convenience function (prototyped in utils.h): sodium_bin2hex(). + +* Version 0.4.1 + - sodium_version_*() functions were not exported in version 0.4. They +are now visible as intended. + - sodium_init() now calls randombytes_stir(). + - optimized assembly version of salsa20 is now used on amd64. + - further cleanups and enhanced compatibility with non-C99 compilers. + +* Version 0.4 + - Most constants and operations are now available as actual functions +instead of macros, making it easier to use from other languages. + - New operation: crypto_generichash, featuring a variable key size, a +variable output size, and a streaming API. Currently implemented using +Blake2b. + - The package can be compiled in a separate directory. + - aes128ctr functions are exported. + - Optimized versions of curve25519 (curve25519_donna_c64), poly1305 +(poly1305_53) and ed25519 (ed25519_ref10) are available. Optionally calling +sodium_init() once before using the library makes it pick the fastest +implementation. + - New convenience function: sodium_memzero() in order to securely +wipe a memory area. + - A whole bunch of cleanups and portability enhancements. + - On Windows, a .REF file is generated along with the shared library, +for use with Visual Studio. The installation path for these has become +$prefix/bin as expected by MingW. + +* Version 0.3 + - The crypto_shorthash operation has been added, implemented using +SipHash-2-4. + +* Version 0.2 + - crypto_sign_seed_keypair() has been added + +* Version 0.1 + - Initial release. + diff --git a/libs/libsodium/docs/LICENSE b/libs/libsodium/docs/LICENSE new file mode 100644 index 0000000000..2489a68143 --- /dev/null +++ b/libs/libsodium/docs/LICENSE @@ -0,0 +1,18 @@ +/* + * ISC License + * + * Copyright (c) 2013-2017 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ diff --git a/libs/libsodium/docs/README.markdown b/libs/libsodium/docs/README.markdown new file mode 100644 index 0000000000..815240abea --- /dev/null +++ b/libs/libsodium/docs/README.markdown @@ -0,0 +1,46 @@ +[![Build Status](https://travis-ci.org/jedisct1/libsodium.svg?branch=master)](https://travis-ci.org/jedisct1/libsodium?branch=master) +[![Windows build status](https://ci.appveyor.com/api/projects/status/fu8s2elx25il98hj?svg=true)](https://ci.appveyor.com/project/jedisct1/libsodium) +[![Coverity Scan Build Status](https://scan.coverity.com/projects/2397/badge.svg)](https://scan.coverity.com/projects/2397) + +![libsodium](https://raw.github.com/jedisct1/libsodium/master/logo.png) +============ + +Sodium is a new, easy-to-use software library for encryption, +decryption, signatures, password hashing and more. + +It is a portable, cross-compilable, installable, packageable +fork of [NaCl](http://nacl.cr.yp.to/), with a compatible API, and an +extended API to improve usability even further. + +Its goal is to provide all of the core operations needed to build +higher-level cryptographic tools. + +Sodium supports a variety of compilers and operating systems, +including Windows (with MingW or Visual Studio, x86 and x64), iOS, Android, +as well as Javascript and Webassembly. + +## Documentation + +The documentation is available on Gitbook: + +* [libsodium documentation](https://download.libsodium.org/doc/) - +online, requires Javascript. +* [offline documentation](https://www.gitbook.com/book/jedisct1/libsodium/details) +in PDF, MOBI and ePUB formats. + +## Integrity Checking + +The integrity checking instructions (including the signing key for libsodium) +are available in the [installation](https://download.libsodium.org/doc/installation/index.html#integrity-checking) +section of the documentation. + +## Community + +A mailing-list is available to discuss libsodium. + +In order to join, just send a random mail to `sodium-subscribe` {at} +`pureftpd` {dot} `org`. + +## License + +[ISC license](https://en.wikipedia.org/wiki/ISC_license). diff --git a/libs/libsodium/docs/THANKS b/libs/libsodium/docs/THANKS new file mode 100644 index 0000000000..0d0da788f3 --- /dev/null +++ b/libs/libsodium/docs/THANKS @@ -0,0 +1,91 @@ +Special thanks to people, companies and organizations having written +libsodium bindings for their favorite programming languages: + +@alethia7 +@artemisc +@carblue +@dnaq +@ektrah +@graxrabble +@harleqin +@joshjdevl +@jrmarino +@jshahbazi +@lvh +@neheb + +Adam Caudill (@adamcaudill) +Alexander Morris (@alexpmorris) +Amit Murthy (@amitmurthy) +Andrew Bennett (@potatosalad) +Andrew Lambert (@charonn0) +Bruce Mitchener (@waywardmonkeys) +Bruno Oliveira (@abstractj) +Caolan McMahon (@caolan) +Chris Rebert (@cvrebert) +Christian Hermann (@bitbeans) +Christian Wiese (@morfoh) +Christian Wiese (@morfoh) +Colm MacCárthaigh (@colmmacc) +David Parrish (@dmp1ce) +Donald Stufft (@dstufft) +Douglas Campos (@qmx) +Drew Crawford (@drewcrawford) +Emil Bay (@emilbayes) +Eric Dong (@quantum1423) +Eric Voskuil (@evoskuil) +Farid Hajji (@fhajji) +Frank Siebenlist (@franks42) +Gabriel Handford (@gabriel) +Geo Carncross (@geocar) +Henrik Gassmann (BurningEnlightenment) +Jachym Holecek (@freza) +Jack Wink (@jackwink) +James Ruan (@jamesruan) +Jan de Muijnck-Hughes (@jfdm) +Jason McCampbell (@jasonmccampbell) +Jeroen Habraken (@VeXocide) +Jeroen Ooms (@jeroen) +Jesper Louis Andersen (@jlouis) +Joe Eli McIlvain (@jemc) +Jonathan Stowe (@jonathanstowe) +Joseph Abrahamson (@tel) +Julien Kauffmann (@ereOn) +Kenneth Ballenegger (@kballenegger) +Loic Maury (@loicmaury) +Michael Gorlick (@mgorlick) +Michael Gregorowicz (@mgregoro) +Michał Zieliński (@zielmicha) +Omar Ayub (@electricFeel) +Pedro Paixao (@paixaop) +Project ArteMisc (@artemisc) +Rich FitzJohn (@richfitz) +Ruben De Visscher (@rubendv) +Rudolf Von Krugstein (@rudolfvonkrugstein) +Samuel Neves (@sneves) +Scott Arciszewski (@paragonie-scott) +Stanislav Ovsiannikov (@naphaso) +Stefan Marsiske (@stef) +Stephan Touset (@stouset) +Stephen Chavez (@redragonx) +Steve Gibson (@sggrc) +Tony Arcieri (@bascule) +Tony Garnock-Jones (@tonyg) +Y. T. Chung (@zonyitoo) + +Bytecurry Software +Cryptotronix +Facebook +FSF France +MaidSafe +Paragonie Initiative Enterprises +Python Cryptographic Authority + +(this list may not be complete, if you don't see your name, please +submit a pull request!) + +Also thanks to: + +- Coverity, Inc. to provide static analysis. +- FSF France for providing access to their compilation servers. +- Private Internet Access for having sponsored a complete security audit. diff --git a/libs/libsodium/libsodium.vcxproj b/libs/libsodium/libsodium.vcxproj new file mode 100644 index 0000000000..182ac4184b --- /dev/null +++ b/libs/libsodium/libsodium.vcxproj @@ -0,0 +1,493 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {A185B162-6CB6-4502-B03F-B56F7699A8D9} + libsodium + libsodium + + + false + false + DynamicLibrary + $(SolutionDir)$(Configuration)\Libs\ + $(SolutionDir)$(Configuration)64\Libs\ + + + + .mir + $(OutDir)$(TargetName)$(TargetExt) + + + + SODIUM_DLL_EXPORT;%(PreprocessorDefinitions) + 4244;4310;4702;%(DisableSpecificWarnings) + $(ProjectDir)src\include;$(ProjectDir)src\include\sodium;%(AdditionalIncludeDirectories) + + + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/libsodium/libsodium.vcxproj.filters b/libs/libsodium/libsodium.vcxproj.filters new file mode 100644 index 0000000000..8f90aeb3d5 --- /dev/null +++ b/libs/libsodium/libsodium.vcxproj.filters @@ -0,0 +1,4 @@ + + + + diff --git a/libs/libsodium/src/crypto_aead/aes256gcm/aesni/aead_aes256gcm_aesni.c b/libs/libsodium/src/crypto_aead/aes256gcm/aesni/aead_aes256gcm_aesni.c new file mode 100644 index 0000000000..dc54bca76b --- /dev/null +++ b/libs/libsodium/src/crypto_aead/aes256gcm/aesni/aead_aes256gcm_aesni.c @@ -0,0 +1,1079 @@ + +/* + * AES256-GCM, based on the "Intel Carry-Less Multiplication Instruction and its Usage for Computing + * the GCM Mode" paper and reference code, using the aggregated reduction method. + * Originally adapted by Romain Dolbeau. + */ + +#include +#include +#include +#include + +#include "core.h" +#include "crypto_aead_aes256gcm.h" +#include "export.h" +#include "private/common.h" +#include "private/sse2_64_32.h" +#include "randombytes.h" +#include "runtime.h" +#include "utils.h" + +#if defined(HAVE_TMMINTRIN_H) && defined(HAVE_WMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("ssse3") +# pragma GCC target("aes") +# pragma GCC target("pclmul") +# endif + +#include +#include + +#ifndef ENOSYS +# define ENOSYS ENXIO +#endif + +#if defined(__INTEL_COMPILER) || defined(_bswap64) +#elif defined(_MSC_VER) +# define _bswap64(a) _byteswap_uint64(a) +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +# define _bswap64(a) __builtin_bswap64(a) +#else +static inline uint64_t +_bswap64(const uint64_t x) +{ + return + ((x << 56) & 0xFF00000000000000UL) | ((x << 40) & 0x00FF000000000000UL) | + ((x << 24) & 0x0000FF0000000000UL) | ((x << 8) & 0x000000FF00000000UL) | + ((x >> 8) & 0x00000000FF000000UL) | ((x >> 24) & 0x0000000000FF0000UL) | + ((x >> 40) & 0x000000000000FF00UL) | ((x >> 56) & 0x00000000000000FFUL); +} +#endif + +typedef struct context { + CRYPTO_ALIGN(16) unsigned char H[16]; + __m128i rkeys[16]; +} context; + +static inline void +aesni_key256_expand(const unsigned char *key, __m128i * const rkeys) +{ + __m128i X0, X1, X2, X3; + int i = 0; + + X0 = _mm_loadu_si128((const __m128i *) &key[0]); + rkeys[i++] = X0; + + X2 = _mm_loadu_si128((const __m128i *) &key[16]); + rkeys[i++] = X2; + +#define EXPAND_KEY_1(S) do { \ + X1 = _mm_shuffle_epi32(_mm_aeskeygenassist_si128(X2, (S)), 0xff); \ + X3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(X3), _mm_castsi128_ps(X0), 0x10)); \ + X0 = _mm_xor_si128(X0, X3); \ + X3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(X3), _mm_castsi128_ps(X0), 0x8c)); \ + X0 = _mm_xor_si128(_mm_xor_si128(X0, X3), X1); \ + rkeys[i++] = X0; \ +} while (0) + +#define EXPAND_KEY_2(S) do { \ + X1 = _mm_shuffle_epi32(_mm_aeskeygenassist_si128(X0, (S)), 0xaa); \ + X3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(X3), _mm_castsi128_ps(X2), 0x10)); \ + X2 = _mm_xor_si128(X2, X3); \ + X3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(X3), _mm_castsi128_ps(X2), 0x8c)); \ + X2 = _mm_xor_si128(_mm_xor_si128(X2, X3), X1); \ + rkeys[i++] = X2; \ +} while (0) + + X3 = _mm_setzero_si128(); + EXPAND_KEY_1(0x01); EXPAND_KEY_2(0x01); + EXPAND_KEY_1(0x02); EXPAND_KEY_2(0x02); + EXPAND_KEY_1(0x04); EXPAND_KEY_2(0x04); + EXPAND_KEY_1(0x08); EXPAND_KEY_2(0x08); + EXPAND_KEY_1(0x10); EXPAND_KEY_2(0x10); + EXPAND_KEY_1(0x20); EXPAND_KEY_2(0x20); + EXPAND_KEY_1(0x40); +} + +/** single, by-the-book AES encryption with AES-NI */ +static inline void +aesni_encrypt1(unsigned char *out, __m128i nv, const __m128i *rkeys) +{ + __m128i temp = _mm_xor_si128(nv, rkeys[0]); + + temp = _mm_aesenc_si128(temp, rkeys[1]); + temp = _mm_aesenc_si128(temp, rkeys[2]); + temp = _mm_aesenc_si128(temp, rkeys[3]); + temp = _mm_aesenc_si128(temp, rkeys[4]); + temp = _mm_aesenc_si128(temp, rkeys[5]); + temp = _mm_aesenc_si128(temp, rkeys[6]); + temp = _mm_aesenc_si128(temp, rkeys[7]); + temp = _mm_aesenc_si128(temp, rkeys[8]); + temp = _mm_aesenc_si128(temp, rkeys[9]); + temp = _mm_aesenc_si128(temp, rkeys[10]); + temp = _mm_aesenc_si128(temp, rkeys[11]); + temp = _mm_aesenc_si128(temp, rkeys[12]); + temp = _mm_aesenc_si128(temp, rkeys[13]); + + temp = _mm_aesenclast_si128(temp, rkeys[14]); + _mm_storeu_si128((__m128i *) out, temp); +} + +/** multiple-blocks-at-once AES encryption with AES-NI ; + on Haswell, aesenc has a latency of 7 and a throughput of 1 + so the sequence of aesenc should be bubble-free if you + have at least 8 blocks. Let's build an arbitratry-sized + function */ +/* Step 1 : loading the nonce */ +/* load & increment the n vector (non-vectorized, unused for now) */ +#define NVDECLx(a) \ + __m128i nv##a + +#define NVx(a) \ + nv##a = _mm_shuffle_epi8(_mm_load_si128((const __m128i *) n), pt); \ + n[3]++ + +/* Step 2 : define value in round one (xor with subkey #0, aka key) */ +#define TEMPDECLx(a) \ + __m128i temp##a + +#define TEMPx(a) \ + temp##a = _mm_xor_si128(nv##a, rkeys[0]) + +/* Step 3: one round of AES */ +#define AESENCx(a) \ + temp##a = _mm_aesenc_si128(temp##a, rkeys[roundctr]) + +/* Step 4: last round of AES */ +#define AESENCLASTx(a) \ + temp##a = _mm_aesenclast_si128(temp##a, rkeys[14]) + +/* Step 5: store result */ +#define STOREx(a) \ + _mm_storeu_si128((__m128i *) (out + (a * 16)), temp##a) + +/* all the MAKE* macros are for automatic explicit unrolling */ +#define MAKE4(X) \ + X(0); \ + X(1); \ + X(2); \ + X(3) + +#define MAKE8(X) \ + X(0); \ + X(1); \ + X(2); \ + X(3); \ + X(4); \ + X(5); \ + X(6); \ + X(7) + +#define COUNTER_INC2(N) (N)[3] += 2 + +/* create a function of unrolling N ; the MAKEN is the unrolling + macro, defined above. The N in MAKEN must match N, obviously. */ +#define FUNC(N, MAKEN) \ + static inline void aesni_encrypt##N(unsigned char *out, uint32_t *n, const __m128i *rkeys) \ + { \ + const __m128i pt = _mm_set_epi8(12, 13, 14, 15, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); \ + int roundctr; \ + MAKEN(NVDECLx); \ + MAKEN(TEMPDECLx); \ + \ + MAKEN(NVx); \ + MAKEN(TEMPx); \ + for (roundctr = 1; roundctr < 14; roundctr++) { \ + MAKEN(AESENCx); \ + } \ + MAKEN(AESENCLASTx); \ + MAKEN(STOREx); \ + } + +FUNC(8, MAKE8) + +/* all GF(2^128) fnctions are by the book, meaning this one: + +*/ + +static inline void +addmul(unsigned char *c, const unsigned char *a, unsigned int xlen, const unsigned char *b) +{ + const __m128i rev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + __m128i A, B, C; + __m128i tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; + __m128i tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17, tmp18; + __m128i tmp19, tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27; + __m128i tmp28, tmp29, tmp30, tmp31, tmp32, tmp33, tmp34, tmp35, tmp36; + + if (xlen >= 16) { + A = _mm_loadu_si128((const __m128i *) a); + } else { + CRYPTO_ALIGN(16) unsigned char padded[16]; + unsigned int i; + + memset(padded, 0, 16); + for (i = 0; i < xlen; i++) { + padded[i] = a[i]; + } + A = _mm_load_si128((const __m128i *) padded); + } + A = _mm_shuffle_epi8(A, rev); + B = _mm_loadu_si128((const __m128i *) b); + C = _mm_loadu_si128((const __m128i *) c); + A = _mm_xor_si128(A, C); + tmp3 = _mm_clmulepi64_si128(A, B, 0x00); + tmp4 = _mm_clmulepi64_si128(A, B, 0x10); + tmp5 = _mm_clmulepi64_si128(A, B, 0x01); + tmp6 = _mm_clmulepi64_si128(A, B, 0x11); + tmp10 = _mm_xor_si128(tmp4, tmp5); + tmp13 = _mm_slli_si128(tmp10, 8); + tmp11 = _mm_srli_si128(tmp10, 8); + tmp15 = _mm_xor_si128(tmp3, tmp13); + tmp17 = _mm_xor_si128(tmp6, tmp11); + tmp7 = _mm_srli_epi32(tmp15, 31); + tmp8 = _mm_srli_epi32(tmp17, 31); + tmp16 = _mm_slli_epi32(tmp15, 1); + tmp18 = _mm_slli_epi32(tmp17, 1); + tmp9 = _mm_srli_si128(tmp7, 12); + tmp22 = _mm_slli_si128(tmp8, 4); + tmp25 = _mm_slli_si128(tmp7, 4); + tmp29 = _mm_or_si128(tmp16, tmp25); + tmp19 = _mm_or_si128(tmp18, tmp22); + tmp20 = _mm_or_si128(tmp19, tmp9); + tmp26 = _mm_slli_epi32(tmp29, 31); + tmp23 = _mm_slli_epi32(tmp29, 30); + tmp32 = _mm_slli_epi32(tmp29, 25); + tmp27 = _mm_xor_si128(tmp26, tmp23); + tmp28 = _mm_xor_si128(tmp27, tmp32); + tmp24 = _mm_srli_si128(tmp28, 4); + tmp33 = _mm_slli_si128(tmp28, 12); + tmp30 = _mm_xor_si128(tmp29, tmp33); + tmp2 = _mm_srli_epi32(tmp30, 1); + tmp12 = _mm_srli_epi32(tmp30, 2); + tmp14 = _mm_srli_epi32(tmp30, 7); + tmp34 = _mm_xor_si128(tmp2, tmp12); + tmp35 = _mm_xor_si128(tmp34, tmp14); + tmp36 = _mm_xor_si128(tmp35, tmp24); + tmp31 = _mm_xor_si128(tmp30, tmp36); + tmp21 = _mm_xor_si128(tmp20, tmp31); + _mm_storeu_si128((__m128i *) c, tmp21); +} + +/* pure multiplication, for pre-computing powers of H */ +static inline __m128i +mulv(__m128i A, __m128i B) +{ + __m128i tmp3 = _mm_clmulepi64_si128(A, B, 0x00); + __m128i tmp4 = _mm_clmulepi64_si128(A, B, 0x10); + __m128i tmp5 = _mm_clmulepi64_si128(A, B, 0x01); + __m128i tmp6 = _mm_clmulepi64_si128(A, B, 0x11); + __m128i tmp10 = _mm_xor_si128(tmp4, tmp5); + __m128i tmp13 = _mm_slli_si128(tmp10, 8); + __m128i tmp11 = _mm_srli_si128(tmp10, 8); + __m128i tmp15 = _mm_xor_si128(tmp3, tmp13); + __m128i tmp17 = _mm_xor_si128(tmp6, tmp11); + __m128i tmp7 = _mm_srli_epi32(tmp15, 31); + __m128i tmp8 = _mm_srli_epi32(tmp17, 31); + __m128i tmp16 = _mm_slli_epi32(tmp15, 1); + __m128i tmp18 = _mm_slli_epi32(tmp17, 1); + __m128i tmp9 = _mm_srli_si128(tmp7, 12); + __m128i tmp22 = _mm_slli_si128(tmp8, 4); + __m128i tmp25 = _mm_slli_si128(tmp7, 4); + __m128i tmp29 = _mm_or_si128(tmp16, tmp25); + __m128i tmp19 = _mm_or_si128(tmp18, tmp22); + __m128i tmp20 = _mm_or_si128(tmp19, tmp9); + __m128i tmp26 = _mm_slli_epi32(tmp29, 31); + __m128i tmp23 = _mm_slli_epi32(tmp29, 30); + __m128i tmp32 = _mm_slli_epi32(tmp29, 25); + __m128i tmp27 = _mm_xor_si128(tmp26, tmp23); + __m128i tmp28 = _mm_xor_si128(tmp27, tmp32); + __m128i tmp24 = _mm_srli_si128(tmp28, 4); + __m128i tmp33 = _mm_slli_si128(tmp28, 12); + __m128i tmp30 = _mm_xor_si128(tmp29, tmp33); + __m128i tmp2 = _mm_srli_epi32(tmp30, 1); + __m128i tmp12 = _mm_srli_epi32(tmp30, 2); + __m128i tmp14 = _mm_srli_epi32(tmp30, 7); + __m128i tmp34 = _mm_xor_si128(tmp2, tmp12); + __m128i tmp35 = _mm_xor_si128(tmp34, tmp14); + __m128i tmp36 = _mm_xor_si128(tmp35, tmp24); + __m128i tmp31 = _mm_xor_si128(tmp30, tmp36); + __m128i C = _mm_xor_si128(tmp20, tmp31); + + return C; +} + +/* 4 multiply-accumulate at once; again + + for the Aggregated Reduction Method & sample code. + Algorithm by Krzysztof Jankowski, Pierre Laurent - Intel */ + +#define RED_DECL(a) __m128i H##a##_X##a##_lo, H##a##_X##a##_hi, tmp##a, tmp##a##B +#define RED_SHUFFLE(a) X##a = _mm_shuffle_epi8(X##a, rev) +#define RED_MUL_LOW(a) H##a##_X##a##_lo = _mm_clmulepi64_si128(H##a, X##a, 0x00) +#define RED_MUL_HIGH(a) H##a##_X##a##_hi = _mm_clmulepi64_si128(H##a, X##a, 0x11) +#define RED_MUL_MID(a) \ + tmp##a = _mm_shuffle_epi32(H##a, 0x4e); \ + tmp##a##B = _mm_shuffle_epi32(X##a, 0x4e); \ + tmp##a = _mm_xor_si128(tmp##a, H##a); \ + tmp##a##B = _mm_xor_si128(tmp##a##B, X##a); \ + tmp##a = _mm_clmulepi64_si128(tmp##a, tmp##a##B, 0x00) + +#define MULREDUCE4(rev, H0_, H1_, H2_, H3_, X0_, X1_, X2_, X3_, accv) \ +do { \ + MAKE4(RED_DECL); \ + __m128i lo, hi; \ + __m128i tmp8, tmp9; \ + __m128i H0 = H0_; \ + __m128i H1 = H1_; \ + __m128i H2 = H2_; \ + __m128i H3 = H3_; \ + __m128i X0 = X0_; \ + __m128i X1 = X1_; \ + __m128i X2 = X2_; \ + __m128i X3 = X3_; \ +\ +/* byte-revert the inputs & xor the first one into the accumulator */ \ +\ + MAKE4(RED_SHUFFLE); \ + X3 = _mm_xor_si128(X3, accv); \ +\ +/* 4 low H*X (x0*h0) */ \ +\ + MAKE4(RED_MUL_LOW); \ + lo = _mm_xor_si128(H0_X0_lo, H1_X1_lo); \ + lo = _mm_xor_si128(lo, H2_X2_lo); \ + lo = _mm_xor_si128(lo, H3_X3_lo); \ +\ +/* 4 high H*X (x1*h1) */ \ +\ + MAKE4(RED_MUL_HIGH); \ + hi = _mm_xor_si128(H0_X0_hi, H1_X1_hi); \ + hi = _mm_xor_si128(hi, H2_X2_hi); \ + hi = _mm_xor_si128(hi, H3_X3_hi); \ +\ +/* 4 middle H*X, using Karatsuba, i.e. \ + x1*h0+x0*h1 =(x1+x0)*(h1+h0)-x1*h1-x0*h0 \ + we already have all x1y1 & x0y0 (accumulated in hi & lo) \ + (0 is low half and 1 is high half) \ + */ \ +/* permute the high and low 64 bits in H1 & X1, \ + so create (h0,h1) from (h1,h0) and (x0,x1) from (x1,x0), \ + then compute (h0+h1,h1+h0) and (x0+x1,x1+x0), \ + and finally multiply \ + */ \ + MAKE4(RED_MUL_MID); \ +\ +/* substracts x1*h1 and x0*h0 */ \ + tmp0 = _mm_xor_si128(tmp0, lo); \ + tmp0 = _mm_xor_si128(tmp0, hi); \ + tmp0 = _mm_xor_si128(tmp1, tmp0); \ + tmp0 = _mm_xor_si128(tmp2, tmp0); \ + tmp0 = _mm_xor_si128(tmp3, tmp0);\ +\ + /* reduction */ \ + tmp0B = _mm_slli_si128(tmp0, 8); \ + tmp0 = _mm_srli_si128(tmp0, 8); \ + lo = _mm_xor_si128(tmp0B, lo); \ + hi = _mm_xor_si128(tmp0, hi); \ + tmp3 = lo; \ + tmp2B = hi; \ + tmp3B = _mm_srli_epi32(tmp3, 31); \ + tmp8 = _mm_srli_epi32(tmp2B, 31); \ + tmp3 = _mm_slli_epi32(tmp3, 1); \ + tmp2B = _mm_slli_epi32(tmp2B, 1); \ + tmp9 = _mm_srli_si128(tmp3B, 12); \ + tmp8 = _mm_slli_si128(tmp8, 4); \ + tmp3B = _mm_slli_si128(tmp3B, 4); \ + tmp3 = _mm_or_si128(tmp3, tmp3B); \ + tmp2B = _mm_or_si128(tmp2B, tmp8); \ + tmp2B = _mm_or_si128(tmp2B, tmp9); \ + tmp3B = _mm_slli_epi32(tmp3, 31); \ + tmp8 = _mm_slli_epi32(tmp3, 30); \ + tmp9 = _mm_slli_epi32(tmp3, 25); \ + tmp3B = _mm_xor_si128(tmp3B, tmp8); \ + tmp3B = _mm_xor_si128(tmp3B, tmp9); \ + tmp8 = _mm_srli_si128(tmp3B, 4); \ + tmp3B = _mm_slli_si128(tmp3B, 12); \ + tmp3 = _mm_xor_si128(tmp3, tmp3B); \ + tmp2 = _mm_srli_epi32(tmp3, 1); \ + tmp0B = _mm_srli_epi32(tmp3, 2); \ + tmp1B = _mm_srli_epi32(tmp3, 7); \ + tmp2 = _mm_xor_si128(tmp2, tmp0B); \ + tmp2 = _mm_xor_si128(tmp2, tmp1B); \ + tmp2 = _mm_xor_si128(tmp2, tmp8); \ + tmp3 = _mm_xor_si128(tmp3, tmp2); \ + tmp2B = _mm_xor_si128(tmp2B, tmp3); \ +\ + accv = tmp2B; \ +} while(0) + +#define XORx(a) \ + temp##a = _mm_xor_si128(temp##a, \ + _mm_loadu_si128((const __m128i *) (in + a * 16))) + +#define LOADx(a) \ + __m128i in##a = _mm_loadu_si128((const __m128i *) (in + a * 16)) + +/* full encrypt & checksum 8 blocks at once */ +#define aesni_encrypt8full(out_, n_, rkeys, in_, accum, hv_, h2v_, h3v_, h4v_, rev) \ +do { \ + unsigned char *out = out_; \ + uint32_t *n = n_; \ + const unsigned char *in = in_; \ + const __m128i hv = hv_; \ + const __m128i h2v = h2v_; \ + const __m128i h3v = h3v_; \ + const __m128i h4v = h4v_; \ + const __m128i pt = _mm_set_epi8(12, 13, 14, 15, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); \ + __m128i accv_; \ + int roundctr; \ + \ + MAKE8(NVDECLx); \ + MAKE8(TEMPDECLx); \ + MAKE8(NVx); \ + MAKE8(TEMPx); \ + for (roundctr = 1; roundctr < 14; roundctr++) { \ + MAKE8(AESENCx); \ + } \ + MAKE8(AESENCLASTx); \ + MAKE8(XORx); \ + MAKE8(STOREx); \ + accv_ = _mm_load_si128((const __m128i *) accum); \ + MULREDUCE4(rev, hv, h2v, h3v, h4v, temp3, temp2, temp1, temp0, accv_); \ + MULREDUCE4(rev, hv, h2v, h3v, h4v, temp7, temp6, temp5, temp4, accv_); \ + _mm_store_si128((__m128i *) accum, accv_); \ +} while(0) + +/* checksum 8 blocks at once */ +#define aesni_addmul8full(in_, accum, hv_, h2v_, h3v_, h4v_, rev) \ +do { \ + const unsigned char *in = in_; \ + const __m128i hv = hv_; \ + const __m128i h2v = h2v_; \ + const __m128i h3v = h3v_; \ + const __m128i h4v = h4v_; \ + __m128i accv_; \ + \ + MAKE8(LOADx); \ + accv_ = _mm_load_si128((const __m128i *) accum); \ + MULREDUCE4(rev, hv, h2v, h3v, h4v, in3, in2, in1, in0, accv_); \ + MULREDUCE4(rev, hv, h2v, h3v, h4v, in7, in6, in5, in4, accv_); \ + _mm_store_si128((__m128i *) accum, accv_); \ +} while(0) + +/* decrypt 8 blocks at once */ +#define aesni_decrypt8full(out_, n_, rkeys, in_) \ +do { \ + unsigned char *out = out_; \ + uint32_t *n = n_; \ + const unsigned char *in = in_; \ + const __m128i pt = _mm_set_epi8(12, 13, 14, 15, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); \ + int roundctr; \ +\ + MAKE8(NVDECLx); \ + MAKE8(TEMPDECLx); \ + MAKE8(NVx); \ + MAKE8(TEMPx); \ + for (roundctr = 1; roundctr < 14; roundctr++) { \ + MAKE8(AESENCx); \ + } \ + MAKE8(AESENCLASTx); \ + MAKE8(XORx); \ + MAKE8(STOREx); \ +} while(0) + +int +crypto_aead_aes256gcm_beforenm(crypto_aead_aes256gcm_state *ctx_, + const unsigned char *k) +{ + context *ctx = (context *) ctx_; + __m128i *rkeys = ctx->rkeys; + __m128i zero = _mm_setzero_si128(); + unsigned char *H = ctx->H; + + COMPILER_ASSERT((sizeof *ctx_) >= (sizeof *ctx)); + aesni_key256_expand(k, rkeys); + aesni_encrypt1(H, zero, rkeys); + + return 0; +} + +int +crypto_aead_aes256gcm_encrypt_detached_afternm(unsigned char *c, + unsigned char *mac, unsigned long long *maclen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) +{ + const __m128i rev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + const context *ctx = (const context *) ctx_; + const __m128i *rkeys = ctx->rkeys; + __m128i Hv, H2v, H3v, H4v, accv; + unsigned long long i, j; + unsigned long long adlen_rnd64 = adlen & ~63ULL; + unsigned long long mlen_rnd128 = mlen & ~127ULL; + CRYPTO_ALIGN(16) uint32_t n2[4]; + CRYPTO_ALIGN(16) unsigned char H[16]; + CRYPTO_ALIGN(16) unsigned char T[16]; + CRYPTO_ALIGN(16) unsigned char accum[16]; + CRYPTO_ALIGN(16) unsigned char fb[16]; + + (void) nsec; + memcpy(H, ctx->H, sizeof H); + if (mlen > crypto_aead_aes256gcm_MESSAGEBYTES_MAX) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + memcpy(&n2[0], npub, 3 * 4); + n2[3] = 0x01000000; + aesni_encrypt1(T, _mm_load_si128((const __m128i *) n2), rkeys); + { + uint64_t x; + x = _bswap64((uint64_t) (8 * adlen)); + memcpy(&fb[0], &x, sizeof x); + x = _bswap64((uint64_t) (8 * mlen)); + memcpy(&fb[8], &x, sizeof x); + } + /* we store H (and it's power) byte-reverted once and for all */ + Hv = _mm_shuffle_epi8(_mm_load_si128((const __m128i *) H), rev); + _mm_store_si128((__m128i *) H, Hv); + H2v = mulv(Hv, Hv); + H3v = mulv(H2v, Hv); + H4v = mulv(H3v, Hv); + + accv = _mm_setzero_si128(); + /* unrolled by 4 GCM (by 8 doesn't improve using MULREDUCE4) */ + for (i = 0; i < adlen_rnd64; i += 64) { + __m128i X4_ = _mm_loadu_si128((const __m128i *) (ad + i + 0)); + __m128i X3_ = _mm_loadu_si128((const __m128i *) (ad + i + 16)); + __m128i X2_ = _mm_loadu_si128((const __m128i *) (ad + i + 32)); + __m128i X1_ = _mm_loadu_si128((const __m128i *) (ad + i + 48)); + MULREDUCE4(rev, Hv, H2v, H3v, H4v, X1_, X2_, X3_, X4_, accv); + } + _mm_store_si128((__m128i *) accum, accv); + + /* GCM remainder loop */ + for (i = adlen_rnd64; i < adlen; i += 16) { + unsigned int blocklen = 16; + + if (i + (unsigned long long) blocklen > adlen) { + blocklen = (unsigned int) (adlen - i); + } + addmul(accum, ad + i, blocklen, H); + } + +/* this only does 8 full blocks, so no fancy bounds checking is necessary*/ +#define LOOPRND128 \ + do { \ + const int iter = 8; \ + const int lb = iter * 16; \ + \ + for (i = 0; i < mlen_rnd128; i += lb) { \ + aesni_encrypt8full(c + i, n2, rkeys, m + i, accum, Hv, H2v, H3v, H4v, rev); \ + } \ + } while(0) + +/* remainder loop, with the slower GCM update to accommodate partial blocks */ +#define LOOPRMD128 \ + do { \ + const int iter = 8; \ + const int lb = iter * 16; \ + \ + for (i = mlen_rnd128; i < mlen; i += lb) { \ + CRYPTO_ALIGN(16) unsigned char outni[8 * 16]; \ + unsigned long long mj = lb; \ + \ + aesni_encrypt8(outni, n2, rkeys); \ + if ((i + mj) >= mlen) { \ + mj = mlen - i; \ + } \ + for (j = 0; j < mj; j++) { \ + c[i + j] = m[i + j] ^ outni[j]; \ + } \ + for (j = 0; j < mj; j += 16) { \ + unsigned int bl = 16; \ + \ + if (j + (unsigned long long) bl >= mj) { \ + bl = (unsigned int) (mj - j); \ + } \ + addmul(accum, c + i + j, bl, H); \ + } \ + } \ + } while(0) + + n2[3] &= 0x00ffffff; + COUNTER_INC2(n2); + LOOPRND128; + LOOPRMD128; + + addmul(accum, fb, 16, H); + + for (i = 0; i < 16; ++i) { + mac[i] = T[i] ^ accum[15 - i]; + } + if (maclen_p != NULL) { + *maclen_p = 16; + } + return 0; +} + +int +crypto_aead_aes256gcm_encrypt_afternm(unsigned char *c, unsigned long long *clen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) +{ + int ret = crypto_aead_aes256gcm_encrypt_detached_afternm(c, + c + mlen, NULL, + m, mlen, + ad, adlen, + nsec, npub, ctx_); + if (clen_p != NULL) { + *clen_p = mlen + crypto_aead_aes256gcm_ABYTES; + } + return ret; +} + +int +crypto_aead_aes256gcm_decrypt_detached_afternm(unsigned char *m, unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) +{ + const __m128i rev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + const context *ctx = (const context *) ctx_; + const __m128i *rkeys = ctx->rkeys; + __m128i Hv, H2v, H3v, H4v, accv; + unsigned long long i, j; + unsigned long long adlen_rnd64 = adlen & ~63ULL; + unsigned long long mlen; + unsigned long long mlen_rnd128; + CRYPTO_ALIGN(16) uint32_t n2[4]; + CRYPTO_ALIGN(16) unsigned char H[16]; + CRYPTO_ALIGN(16) unsigned char T[16]; + CRYPTO_ALIGN(16) unsigned char accum[16]; + CRYPTO_ALIGN(16) unsigned char fb[16]; + + (void) nsec; + if (clen > crypto_aead_aes256gcm_MESSAGEBYTES_MAX) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + mlen = clen; + + memcpy(&n2[0], npub, 3 * 4); + n2[3] = 0x01000000; + aesni_encrypt1(T, _mm_load_si128((const __m128i *) n2), rkeys); + + { + uint64_t x; + x = _bswap64((uint64_t)(8 * adlen)); + memcpy(&fb[0], &x, sizeof x); + x = _bswap64((uint64_t)(8 * mlen)); + memcpy(&fb[8], &x, sizeof x); + } + + memcpy(H, ctx->H, sizeof H); + Hv = _mm_shuffle_epi8(_mm_load_si128((const __m128i *) H), rev); + _mm_store_si128((__m128i *) H, Hv); + H2v = mulv(Hv, Hv); + H3v = mulv(H2v, Hv); + H4v = mulv(H3v, Hv); + + accv = _mm_setzero_si128(); + for (i = 0; i < adlen_rnd64; i += 64) { + __m128i X4_ = _mm_loadu_si128((const __m128i *) (ad + i + 0)); + __m128i X3_ = _mm_loadu_si128((const __m128i *) (ad + i + 16)); + __m128i X2_ = _mm_loadu_si128((const __m128i *) (ad + i + 32)); + __m128i X1_ = _mm_loadu_si128((const __m128i *) (ad + i + 48)); + MULREDUCE4(rev, Hv, H2v, H3v, H4v, X1_, X2_, X3_, X4_, accv); + } + _mm_store_si128((__m128i *) accum, accv); + + for (i = adlen_rnd64; i < adlen; i += 16) { + unsigned int blocklen = 16; + if (i + (unsigned long long) blocklen > adlen) { + blocklen = (unsigned int) (adlen - i); + } + addmul(accum, ad + i, blocklen, H); + } + + mlen_rnd128 = mlen & ~127ULL; + +#define LOOPACCUMDRND128 \ + do { \ + const int iter = 8; \ + const int lb = iter * 16; \ + for (i = 0; i < mlen_rnd128; i += lb) { \ + aesni_addmul8full(c + i, accum, Hv, H2v, H3v, H4v, rev); \ + } \ + } while(0) + +#define LOOPDRND128 \ + do { \ + const int iter = 8; \ + const int lb = iter * 16; \ + \ + for (i = 0; i < mlen_rnd128; i += lb) { \ + aesni_decrypt8full(m + i, n2, rkeys, c + i); \ + } \ + } while(0) + +#define LOOPACCUMDRMD128 \ + do { \ + const int iter = 8; \ + const int lb = iter * 16; \ + \ + for (i = mlen_rnd128; i < mlen; i += lb) { \ + unsigned long long mj = lb; \ + \ + if ((i + mj) >= mlen) { \ + mj = mlen - i; \ + } \ + for (j = 0; j < mj; j += 16) { \ + unsigned int bl = 16; \ + \ + if (j + (unsigned long long) bl >= mj) { \ + bl = (unsigned int) (mj - j); \ + } \ + addmul(accum, c + i + j, bl, H); \ + } \ + } \ + } while(0) + +#define LOOPDRMD128 \ + do { \ + const int iter = 8; \ + const int lb = iter * 16; \ + \ + for (i = mlen_rnd128; i < mlen; i += lb) { \ + CRYPTO_ALIGN(16) unsigned char outni[8 * 16]; \ + unsigned long long mj = lb; \ + \ + if ((i + mj) >= mlen) { \ + mj = mlen - i; \ + } \ + aesni_encrypt8(outni, n2, rkeys); \ + for (j = 0; j < mj; j++) { \ + m[i + j] = c[i + j] ^ outni[j]; \ + } \ + } \ + } while(0) + + n2[3] &= 0x00ffffff; + + COUNTER_INC2(n2); + LOOPACCUMDRND128; + LOOPACCUMDRMD128; + addmul(accum, fb, 16, H); + { + unsigned char d = 0; + + for (i = 0; i < 16; i++) { + d |= (mac[i] ^ (T[i] ^ accum[15 - i])); + } + if (d != 0) { + if (m != NULL) { + memset(m, 0, mlen); + } + return -1; + } + if (m == NULL) { + return 0; + } + } + n2[3] = 0U; + COUNTER_INC2(n2); + LOOPDRND128; + LOOPDRMD128; + + return 0; +} + +int +crypto_aead_aes256gcm_decrypt_afternm(unsigned char *m, unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) +{ + unsigned long long mlen = 0ULL; + int ret = -1; + + if (clen >= crypto_aead_aes256gcm_ABYTES) { + ret = crypto_aead_aes256gcm_decrypt_detached_afternm + (m, nsec, c, clen - crypto_aead_aes256gcm_ABYTES, + c + clen - crypto_aead_aes256gcm_ABYTES, + ad, adlen, npub, ctx_); + } + if (mlen_p != NULL) { + if (ret == 0) { + mlen = clen - crypto_aead_aes256gcm_ABYTES; + } + *mlen_p = mlen; + } + return ret; +} + +int +crypto_aead_aes256gcm_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + CRYPTO_ALIGN(16) crypto_aead_aes256gcm_state ctx; + + crypto_aead_aes256gcm_beforenm(&ctx, k); + + return crypto_aead_aes256gcm_encrypt_detached_afternm + (c, mac, maclen_p, m, mlen, ad, adlen, nsec, npub, + (const crypto_aead_aes256gcm_state *) &ctx); +} + +int +crypto_aead_aes256gcm_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + CRYPTO_ALIGN(16) crypto_aead_aes256gcm_state ctx; + int ret; + + crypto_aead_aes256gcm_beforenm(&ctx, k); + + ret = crypto_aead_aes256gcm_encrypt_afternm + (c, clen_p, m, mlen, ad, adlen, nsec, npub, + (const crypto_aead_aes256gcm_state *) &ctx); + sodium_memzero(ctx, sizeof ctx); + + return ret; +} + +int +crypto_aead_aes256gcm_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + CRYPTO_ALIGN(16) crypto_aead_aes256gcm_state ctx; + + crypto_aead_aes256gcm_beforenm(&ctx, k); + + return crypto_aead_aes256gcm_decrypt_detached_afternm + (m, nsec, c, clen, mac, ad, adlen, npub, + (const crypto_aead_aes256gcm_state *) &ctx); +} + +int +crypto_aead_aes256gcm_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + CRYPTO_ALIGN(16) crypto_aead_aes256gcm_state ctx; + int ret; + + crypto_aead_aes256gcm_beforenm(&ctx, k); + + ret = crypto_aead_aes256gcm_decrypt_afternm + (m, mlen_p, nsec, c, clen, ad, adlen, npub, + (const crypto_aead_aes256gcm_state *) &ctx); + sodium_memzero(ctx, sizeof ctx); + + return ret; +} + +int +crypto_aead_aes256gcm_is_available(void) +{ + return sodium_runtime_has_pclmul() & sodium_runtime_has_aesni(); +} + +#else + +int +crypto_aead_aes256gcm_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + errno = ENOSYS; + return -1; +} + +int +crypto_aead_aes256gcm_encrypt(unsigned char *c, unsigned long long *clen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, const unsigned char *npub, + const unsigned char *k) +{ + errno = ENOSYS; + return -1; +} + +int +crypto_aead_aes256gcm_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + errno = ENOSYS; + return -1; +} + +int +crypto_aead_aes256gcm_decrypt(unsigned char *m, unsigned long long *mlen_p, + unsigned char *nsec, const unsigned char *c, + unsigned long long clen, const unsigned char *ad, + unsigned long long adlen, const unsigned char *npub, + const unsigned char *k) +{ + errno = ENOSYS; + return -1; +} + +int +crypto_aead_aes256gcm_beforenm(crypto_aead_aes256gcm_state *ctx_, + const unsigned char *k) +{ + errno = ENOSYS; + return -1; +} + +int +crypto_aead_aes256gcm_encrypt_detached_afternm(unsigned char *c, + unsigned char *mac, unsigned long long *maclen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) +{ + errno = ENOSYS; + return -1; +} + +int +crypto_aead_aes256gcm_encrypt_afternm(unsigned char *c, unsigned long long *clen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) +{ + errno = ENOSYS; + return -1; +} + +int +crypto_aead_aes256gcm_decrypt_detached_afternm(unsigned char *m, unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) +{ + errno = ENOSYS; + return -1; +} + +int +crypto_aead_aes256gcm_decrypt_afternm(unsigned char *m, unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) +{ + errno = ENOSYS; + return -1; +} + +int +crypto_aead_aes256gcm_is_available(void) +{ + return 0; +} + +#endif + +size_t +crypto_aead_aes256gcm_keybytes(void) +{ + return crypto_aead_aes256gcm_KEYBYTES; +} + +size_t +crypto_aead_aes256gcm_nsecbytes(void) +{ + return crypto_aead_aes256gcm_NSECBYTES; +} + +size_t +crypto_aead_aes256gcm_npubbytes(void) +{ + return crypto_aead_aes256gcm_NPUBBYTES; +} + +size_t +crypto_aead_aes256gcm_abytes(void) +{ + return crypto_aead_aes256gcm_ABYTES; +} + +size_t +crypto_aead_aes256gcm_statebytes(void) +{ + return (sizeof(crypto_aead_aes256gcm_state) + (size_t) 15U) & ~(size_t) 15U; +} + +size_t +crypto_aead_aes256gcm_messagebytes_max(void) +{ + return crypto_aead_aes256gcm_MESSAGEBYTES_MAX; +} + +void +crypto_aead_aes256gcm_keygen(unsigned char k[crypto_aead_aes256gcm_KEYBYTES]) +{ + randombytes_buf(k, crypto_aead_aes256gcm_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c b/libs/libsodium/src/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c new file mode 100644 index 0000000000..c79407a185 --- /dev/null +++ b/libs/libsodium/src/crypto_aead/chacha20poly1305/sodium/aead_chacha20poly1305.c @@ -0,0 +1,399 @@ + +#include +#include +#include +#include + +#include "core.h" +#include "crypto_aead_chacha20poly1305.h" +#include "crypto_onetimeauth_poly1305.h" +#include "crypto_stream_chacha20.h" +#include "crypto_verify_16.h" +#include "randombytes.h" +#include "utils.h" + +#include "private/common.h" + +static const unsigned char _pad0[16] = { 0 }; + +int +crypto_aead_chacha20poly1305_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + crypto_onetimeauth_poly1305_state state; + unsigned char block0[64U]; + unsigned char slen[8U]; + + (void) nsec; + crypto_stream_chacha20(block0, sizeof block0, npub, k); + crypto_onetimeauth_poly1305_init(&state, block0); + sodium_memzero(block0, sizeof block0); + + crypto_onetimeauth_poly1305_update(&state, ad, adlen); + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + crypto_stream_chacha20_xor_ic(c, m, mlen, npub, 1U, k); + + crypto_onetimeauth_poly1305_update(&state, c, mlen); + STORE64_LE(slen, (uint64_t) mlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_final(&state, mac); + sodium_memzero(&state, sizeof state); + + if (maclen_p != NULL) { + *maclen_p = crypto_aead_chacha20poly1305_ABYTES; + } + return 0; +} + +int +crypto_aead_chacha20poly1305_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned long long clen = 0ULL; + int ret; + + if (mlen > crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + ret = crypto_aead_chacha20poly1305_encrypt_detached(c, + c + mlen, NULL, + m, mlen, + ad, adlen, + nsec, npub, k); + if (clen_p != NULL) { + if (ret == 0) { + clen = mlen + crypto_aead_chacha20poly1305_ABYTES; + } + *clen_p = clen; + } + return ret; +} + +int +crypto_aead_chacha20poly1305_ietf_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + crypto_onetimeauth_poly1305_state state; + unsigned char block0[64U]; + unsigned char slen[8U]; + + (void) nsec; + crypto_stream_chacha20_ietf(block0, sizeof block0, npub, k); + crypto_onetimeauth_poly1305_init(&state, block0); + sodium_memzero(block0, sizeof block0); + + crypto_onetimeauth_poly1305_update(&state, ad, adlen); + crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - adlen) & 0xf); + + crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, npub, 1U, k); + + crypto_onetimeauth_poly1305_update(&state, c, mlen); + crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - mlen) & 0xf); + + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + STORE64_LE(slen, (uint64_t) mlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_final(&state, mac); + sodium_memzero(&state, sizeof state); + + if (maclen_p != NULL) { + *maclen_p = crypto_aead_chacha20poly1305_ietf_ABYTES; + } + return 0; +} + +int +crypto_aead_chacha20poly1305_ietf_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned long long clen = 0ULL; + int ret; + + if (mlen > crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + ret = crypto_aead_chacha20poly1305_ietf_encrypt_detached(c, + c + mlen, NULL, + m, mlen, + ad, adlen, + nsec, npub, k); + if (clen_p != NULL) { + if (ret == 0) { + clen = mlen + crypto_aead_chacha20poly1305_ietf_ABYTES; + } + *clen_p = clen; + } + return ret; +} + +int +crypto_aead_chacha20poly1305_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + crypto_onetimeauth_poly1305_state state; + unsigned char block0[64U]; + unsigned char slen[8U]; + unsigned char computed_mac[crypto_aead_chacha20poly1305_ABYTES]; + unsigned long long mlen; + int ret; + + (void) nsec; + crypto_stream_chacha20(block0, sizeof block0, npub, k); + crypto_onetimeauth_poly1305_init(&state, block0); + sodium_memzero(block0, sizeof block0); + + crypto_onetimeauth_poly1305_update(&state, ad, adlen); + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + mlen = clen; + crypto_onetimeauth_poly1305_update(&state, c, mlen); + STORE64_LE(slen, (uint64_t) mlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_final(&state, computed_mac); + sodium_memzero(&state, sizeof state); + + COMPILER_ASSERT(sizeof computed_mac == 16U); + ret = crypto_verify_16(computed_mac, mac); + sodium_memzero(computed_mac, sizeof computed_mac); + if (m == NULL) { + return ret; + } + if (ret != 0) { + memset(m, 0, mlen); + return -1; + } + crypto_stream_chacha20_xor_ic(m, c, mlen, npub, 1U, k); + + return 0; +} + +int +crypto_aead_chacha20poly1305_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned long long mlen = 0ULL; + int ret = -1; + + if (clen >= crypto_aead_chacha20poly1305_ABYTES) { + ret = crypto_aead_chacha20poly1305_decrypt_detached + (m, nsec, + c, clen - crypto_aead_chacha20poly1305_ABYTES, + c + clen - crypto_aead_chacha20poly1305_ABYTES, + ad, adlen, npub, k); + } + if (mlen_p != NULL) { + if (ret == 0) { + mlen = clen - crypto_aead_chacha20poly1305_ABYTES; + } + *mlen_p = mlen; + } + return ret; +} + +int +crypto_aead_chacha20poly1305_ietf_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + crypto_onetimeauth_poly1305_state state; + unsigned char block0[64U]; + unsigned char slen[8U]; + unsigned char computed_mac[crypto_aead_chacha20poly1305_ietf_ABYTES]; + unsigned long long mlen; + int ret; + + (void) nsec; + crypto_stream_chacha20_ietf(block0, sizeof block0, npub, k); + crypto_onetimeauth_poly1305_init(&state, block0); + sodium_memzero(block0, sizeof block0); + + crypto_onetimeauth_poly1305_update(&state, ad, adlen); + crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - adlen) & 0xf); + + mlen = clen; + crypto_onetimeauth_poly1305_update(&state, c, mlen); + crypto_onetimeauth_poly1305_update(&state, _pad0, (0x10 - mlen) & 0xf); + + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + STORE64_LE(slen, (uint64_t) mlen); + crypto_onetimeauth_poly1305_update(&state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_final(&state, computed_mac); + sodium_memzero(&state, sizeof state); + + COMPILER_ASSERT(sizeof computed_mac == 16U); + ret = crypto_verify_16(computed_mac, mac); + sodium_memzero(computed_mac, sizeof computed_mac); + if (m == NULL) { + return ret; + } + if (ret != 0) { + memset(m, 0, mlen); + return -1; + } + crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, npub, 1U, k); + + return 0; +} + +int +crypto_aead_chacha20poly1305_ietf_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned long long mlen = 0ULL; + int ret = -1; + + if (clen >= crypto_aead_chacha20poly1305_ietf_ABYTES) { + ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached + (m, nsec, + c, clen - crypto_aead_chacha20poly1305_ietf_ABYTES, + c + clen - crypto_aead_chacha20poly1305_ietf_ABYTES, + ad, adlen, npub, k); + } + if (mlen_p != NULL) { + if (ret == 0) { + mlen = clen - crypto_aead_chacha20poly1305_ietf_ABYTES; + } + *mlen_p = mlen; + } + return ret; +} + +size_t +crypto_aead_chacha20poly1305_ietf_keybytes(void) +{ + return crypto_aead_chacha20poly1305_ietf_KEYBYTES; +} + +size_t +crypto_aead_chacha20poly1305_ietf_npubbytes(void) +{ + return crypto_aead_chacha20poly1305_ietf_NPUBBYTES; +} + +size_t +crypto_aead_chacha20poly1305_ietf_nsecbytes(void) +{ + return crypto_aead_chacha20poly1305_ietf_NSECBYTES; +} + +size_t +crypto_aead_chacha20poly1305_ietf_abytes(void) +{ + return crypto_aead_chacha20poly1305_ietf_ABYTES; +} + +size_t +crypto_aead_chacha20poly1305_ietf_messagebytes_max(void) +{ + return crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX; +} + +void +crypto_aead_chacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_chacha20poly1305_ietf_KEYBYTES]) +{ + randombytes_buf(k, crypto_aead_chacha20poly1305_ietf_KEYBYTES); +} + +size_t +crypto_aead_chacha20poly1305_keybytes(void) +{ + return crypto_aead_chacha20poly1305_KEYBYTES; +} + +size_t +crypto_aead_chacha20poly1305_npubbytes(void) +{ + return crypto_aead_chacha20poly1305_NPUBBYTES; +} + +size_t +crypto_aead_chacha20poly1305_nsecbytes(void) +{ + return crypto_aead_chacha20poly1305_NSECBYTES; +} + +size_t +crypto_aead_chacha20poly1305_abytes(void) +{ + return crypto_aead_chacha20poly1305_ABYTES; +} + +size_t +crypto_aead_chacha20poly1305_messagebytes_max(void) +{ + return crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX; +} + +void +crypto_aead_chacha20poly1305_keygen(unsigned char k[crypto_aead_chacha20poly1305_KEYBYTES]) +{ + randombytes_buf(k, crypto_aead_chacha20poly1305_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c b/libs/libsodium/src/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c new file mode 100644 index 0000000000..c18cdf9458 --- /dev/null +++ b/libs/libsodium/src/crypto_aead/xchacha20poly1305/sodium/aead_xchacha20poly1305.c @@ -0,0 +1,160 @@ + +#include +#include +#include +#include + +#include "core.h" +#include "crypto_aead_xchacha20poly1305.h" +#include "crypto_aead_chacha20poly1305.h" +#include "crypto_core_hchacha20.h" +#include "randombytes.h" +#include "utils.h" + +#include "private/common.h" + +int +crypto_aead_xchacha20poly1305_ietf_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES]; + unsigned char npub2[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0 }; + int ret; + + crypto_core_hchacha20(k2, npub, k, NULL); + memcpy(npub2 + 4, npub + crypto_core_hchacha20_INPUTBYTES, + crypto_aead_chacha20poly1305_ietf_NPUBBYTES - 4); + ret = crypto_aead_chacha20poly1305_ietf_encrypt_detached + (c, mac, maclen_p, m, mlen, ad, adlen, nsec, npub2, k2); + sodium_memzero(k2, crypto_core_hchacha20_OUTPUTBYTES); + + return ret; +} + +int +crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned long long clen = 0ULL; + int ret; + + if (mlen > UINT64_MAX - crypto_aead_xchacha20poly1305_ietf_ABYTES) { + sodium_misuse(); + } + ret = crypto_aead_xchacha20poly1305_ietf_encrypt_detached + (c, c + mlen, NULL, m, mlen, ad, adlen, nsec, npub, k); + if (clen_p != NULL) { + if (ret == 0) { + clen = mlen + crypto_aead_xchacha20poly1305_ietf_ABYTES; + } + *clen_p = clen; + } + return ret; +} + +int +crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES]; + unsigned char npub2[crypto_aead_chacha20poly1305_ietf_NPUBBYTES] = { 0 }; + int ret; + + crypto_core_hchacha20(k2, npub, k, NULL); + memcpy(npub2 + 4, npub + crypto_core_hchacha20_INPUTBYTES, + crypto_aead_chacha20poly1305_ietf_NPUBBYTES - 4); + ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached + (m, nsec, c, clen, mac, ad, adlen, npub2, k2); + sodium_memzero(k2, crypto_core_hchacha20_OUTPUTBYTES); + + return ret; + +} + +int +crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned long long mlen = 0ULL; + int ret = -1; + + if (clen >= crypto_aead_xchacha20poly1305_ietf_ABYTES) { + ret = crypto_aead_xchacha20poly1305_ietf_decrypt_detached + (m, nsec, + c, clen - crypto_aead_xchacha20poly1305_ietf_ABYTES, + c + clen - crypto_aead_xchacha20poly1305_ietf_ABYTES, + ad, adlen, npub, k); + } + if (mlen_p != NULL) { + if (ret == 0) { + mlen = clen - crypto_aead_xchacha20poly1305_ietf_ABYTES; + } + *mlen_p = mlen; + } + return ret; +} + +size_t +crypto_aead_xchacha20poly1305_ietf_keybytes(void) +{ + return crypto_aead_xchacha20poly1305_ietf_KEYBYTES; +} + +size_t +crypto_aead_xchacha20poly1305_ietf_npubbytes(void) +{ + return crypto_aead_xchacha20poly1305_ietf_NPUBBYTES; +} + +size_t +crypto_aead_xchacha20poly1305_ietf_nsecbytes(void) +{ + return crypto_aead_xchacha20poly1305_ietf_NSECBYTES; +} + +size_t +crypto_aead_xchacha20poly1305_ietf_abytes(void) +{ + return crypto_aead_xchacha20poly1305_ietf_ABYTES; +} + +size_t +crypto_aead_xchacha20poly1305_ietf_messagebytes_max(void) +{ + return crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX; +} + +void +crypto_aead_xchacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES]) +{ + randombytes_buf(k, crypto_aead_xchacha20poly1305_ietf_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_auth/crypto_auth.c b/libs/libsodium/src/crypto_auth/crypto_auth.c new file mode 100644 index 0000000000..d061c8c1c5 --- /dev/null +++ b/libs/libsodium/src/crypto_auth/crypto_auth.c @@ -0,0 +1,41 @@ + +#include "crypto_auth.h" +#include "randombytes.h" + +size_t +crypto_auth_bytes(void) +{ + return crypto_auth_BYTES; +} + +size_t +crypto_auth_keybytes(void) +{ + return crypto_auth_KEYBYTES; +} + +const char * +crypto_auth_primitive(void) +{ + return crypto_auth_PRIMITIVE; +} + +int +crypto_auth(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + return crypto_auth_hmacsha512256(out, in, inlen, k); +} + +int +crypto_auth_verify(const unsigned char *h, const unsigned char *in, + unsigned long long inlen,const unsigned char *k) +{ + return crypto_auth_hmacsha512256_verify(h, in, inlen, k); +} + +void +crypto_auth_keygen(unsigned char k[crypto_auth_KEYBYTES]) +{ + randombytes_buf(k, crypto_auth_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_auth/hmacsha256/auth_hmacsha256.c b/libs/libsodium/src/crypto_auth/hmacsha256/auth_hmacsha256.c new file mode 100644 index 0000000000..a951e932b8 --- /dev/null +++ b/libs/libsodium/src/crypto_auth/hmacsha256/auth_hmacsha256.c @@ -0,0 +1,118 @@ + +#include +#include +#include + +#include "crypto_auth_hmacsha256.h" +#include "crypto_hash_sha256.h" +#include "crypto_verify_32.h" +#include "randombytes.h" +#include "utils.h" + +size_t +crypto_auth_hmacsha256_bytes(void) +{ + return crypto_auth_hmacsha256_BYTES; +} + +size_t +crypto_auth_hmacsha256_keybytes(void) +{ + return crypto_auth_hmacsha256_KEYBYTES; +} + +size_t +crypto_auth_hmacsha256_statebytes(void) +{ + return sizeof(crypto_auth_hmacsha256_state); +} + +void +crypto_auth_hmacsha256_keygen(unsigned char k[crypto_auth_hmacsha256_KEYBYTES]) +{ + randombytes_buf(k, crypto_auth_hmacsha256_KEYBYTES); +} + +int +crypto_auth_hmacsha256_init(crypto_auth_hmacsha256_state *state, + const unsigned char *key, size_t keylen) +{ + unsigned char pad[64]; + unsigned char khash[32]; + size_t i; + + if (keylen > 64) { + crypto_hash_sha256_init(&state->ictx); + crypto_hash_sha256_update(&state->ictx, key, keylen); + crypto_hash_sha256_final(&state->ictx, khash); + key = khash; + keylen = 32; + } + crypto_hash_sha256_init(&state->ictx); + memset(pad, 0x36, 64); + for (i = 0; i < keylen; i++) { + pad[i] ^= key[i]; + } + crypto_hash_sha256_update(&state->ictx, pad, 64); + + crypto_hash_sha256_init(&state->octx); + memset(pad, 0x5c, 64); + for (i = 0; i < keylen; i++) { + pad[i] ^= key[i]; + } + crypto_hash_sha256_update(&state->octx, pad, 64); + + sodium_memzero((void *) pad, sizeof pad); + sodium_memzero((void *) khash, sizeof khash); + + return 0; +} + +int +crypto_auth_hmacsha256_update(crypto_auth_hmacsha256_state *state, + const unsigned char *in, unsigned long long inlen) +{ + crypto_hash_sha256_update(&state->ictx, in, inlen); + + return 0; +} + +int +crypto_auth_hmacsha256_final(crypto_auth_hmacsha256_state *state, + unsigned char *out) +{ + unsigned char ihash[32]; + + crypto_hash_sha256_final(&state->ictx, ihash); + crypto_hash_sha256_update(&state->octx, ihash, 32); + crypto_hash_sha256_final(&state->octx, out); + + sodium_memzero((void *) ihash, sizeof ihash); + + return 0; +} + +int +crypto_auth_hmacsha256(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + crypto_auth_hmacsha256_state state; + + crypto_auth_hmacsha256_init(&state, k, crypto_auth_hmacsha256_KEYBYTES); + crypto_auth_hmacsha256_update(&state, in, inlen); + crypto_auth_hmacsha256_final(&state, out); + + return 0; +} + +int +crypto_auth_hmacsha256_verify(const unsigned char *h, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + unsigned char correct[32]; + + crypto_auth_hmacsha256(correct, in, inlen, k); + + return crypto_verify_32(h, correct) | (-(h == correct)) | + sodium_memcmp(correct, h, 32); +} diff --git a/libs/libsodium/src/crypto_auth/hmacsha512/auth_hmacsha512.c b/libs/libsodium/src/crypto_auth/hmacsha512/auth_hmacsha512.c new file mode 100644 index 0000000000..018d7a4e87 --- /dev/null +++ b/libs/libsodium/src/crypto_auth/hmacsha512/auth_hmacsha512.c @@ -0,0 +1,118 @@ + +#include +#include +#include + +#include "crypto_auth_hmacsha512.h" +#include "crypto_hash_sha512.h" +#include "crypto_verify_64.h" +#include "randombytes.h" +#include "utils.h" + +size_t +crypto_auth_hmacsha512_bytes(void) +{ + return crypto_auth_hmacsha512_BYTES; +} + +size_t +crypto_auth_hmacsha512_keybytes(void) +{ + return crypto_auth_hmacsha512_KEYBYTES; +} + +size_t +crypto_auth_hmacsha512_statebytes(void) +{ + return sizeof(crypto_auth_hmacsha512_state); +} + +void +crypto_auth_hmacsha512_keygen(unsigned char k[crypto_auth_hmacsha512_KEYBYTES]) +{ + randombytes_buf(k, crypto_auth_hmacsha512_KEYBYTES); +} + +int +crypto_auth_hmacsha512_init(crypto_auth_hmacsha512_state *state, + const unsigned char *key, size_t keylen) +{ + unsigned char pad[128]; + unsigned char khash[64]; + size_t i; + + if (keylen > 128) { + crypto_hash_sha512_init(&state->ictx); + crypto_hash_sha512_update(&state->ictx, key, keylen); + crypto_hash_sha512_final(&state->ictx, khash); + key = khash; + keylen = 64; + } + crypto_hash_sha512_init(&state->ictx); + memset(pad, 0x36, 128); + for (i = 0; i < keylen; i++) { + pad[i] ^= key[i]; + } + crypto_hash_sha512_update(&state->ictx, pad, 128); + + crypto_hash_sha512_init(&state->octx); + memset(pad, 0x5c, 128); + for (i = 0; i < keylen; i++) { + pad[i] ^= key[i]; + } + crypto_hash_sha512_update(&state->octx, pad, 128); + + sodium_memzero((void *) pad, sizeof pad); + sodium_memzero((void *) khash, sizeof khash); + + return 0; +} + +int +crypto_auth_hmacsha512_update(crypto_auth_hmacsha512_state *state, + const unsigned char *in, unsigned long long inlen) +{ + crypto_hash_sha512_update(&state->ictx, in, inlen); + + return 0; +} + +int +crypto_auth_hmacsha512_final(crypto_auth_hmacsha512_state *state, + unsigned char *out) +{ + unsigned char ihash[64]; + + crypto_hash_sha512_final(&state->ictx, ihash); + crypto_hash_sha512_update(&state->octx, ihash, 64); + crypto_hash_sha512_final(&state->octx, out); + + sodium_memzero((void *) ihash, sizeof ihash); + + return 0; +} + +int +crypto_auth_hmacsha512(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + crypto_auth_hmacsha512_state state; + + crypto_auth_hmacsha512_init(&state, k, crypto_auth_hmacsha512_KEYBYTES); + crypto_auth_hmacsha512_update(&state, in, inlen); + crypto_auth_hmacsha512_final(&state, out); + + return 0; +} + +int +crypto_auth_hmacsha512_verify(const unsigned char *h, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + unsigned char correct[64]; + + crypto_auth_hmacsha512(correct, in, inlen, k); + + return crypto_verify_64(h, correct) | (-(h == correct)) | + sodium_memcmp(correct, h, 64); +} diff --git a/libs/libsodium/src/crypto_auth/hmacsha512256/auth_hmacsha512256.c b/libs/libsodium/src/crypto_auth/hmacsha512256/auth_hmacsha512256.c new file mode 100644 index 0000000000..432d6dbee5 --- /dev/null +++ b/libs/libsodium/src/crypto_auth/hmacsha512256/auth_hmacsha512256.c @@ -0,0 +1,93 @@ + +#include +#include +#include + +#include "crypto_auth_hmacsha512.h" +#include "crypto_auth_hmacsha512256.h" +#include "crypto_hash_sha512.h" +#include "crypto_verify_32.h" +#include "randombytes.h" +#include "utils.h" + +size_t +crypto_auth_hmacsha512256_bytes(void) +{ + return crypto_auth_hmacsha512256_BYTES; +} + +size_t +crypto_auth_hmacsha512256_keybytes(void) +{ + return crypto_auth_hmacsha512256_KEYBYTES; +} + +size_t +crypto_auth_hmacsha512256_statebytes(void) +{ + return sizeof(crypto_auth_hmacsha512256_state); +} + +void +crypto_auth_hmacsha512256_keygen( + unsigned char k[crypto_auth_hmacsha512256_KEYBYTES]) +{ + randombytes_buf(k, crypto_auth_hmacsha512256_KEYBYTES); +} + +int +crypto_auth_hmacsha512256_init(crypto_auth_hmacsha512256_state *state, + const unsigned char *key, size_t keylen) +{ + return crypto_auth_hmacsha512_init((crypto_auth_hmacsha512_state *) state, + key, keylen); +} + +int +crypto_auth_hmacsha512256_update(crypto_auth_hmacsha512256_state *state, + const unsigned char *in, + unsigned long long inlen) +{ + return crypto_auth_hmacsha512_update((crypto_auth_hmacsha512_state *) state, + in, inlen); +} + +int +crypto_auth_hmacsha512256_final(crypto_auth_hmacsha512256_state *state, + unsigned char *out) +{ + unsigned char out0[64]; + + crypto_auth_hmacsha512_final((crypto_auth_hmacsha512_state *) state, out0); + memcpy(out, out0, 32); + + return 0; +} + +int +crypto_auth_hmacsha512256(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + crypto_auth_hmacsha512256_state state; + + crypto_auth_hmacsha512256_init(&state, k, + crypto_auth_hmacsha512256_KEYBYTES); + crypto_auth_hmacsha512256_update(&state, in, inlen); + crypto_auth_hmacsha512256_final(&state, out); + + return 0; +} + +int +crypto_auth_hmacsha512256_verify(const unsigned char *h, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k) +{ + unsigned char correct[32]; + + crypto_auth_hmacsha512256(correct, in, inlen, k); + + return crypto_verify_32(h, correct) | (-(h == correct)) | + sodium_memcmp(correct, h, 32); +} diff --git a/libs/libsodium/src/crypto_box/crypto_box.c b/libs/libsodium/src/crypto_box/crypto_box.c new file mode 100644 index 0000000000..7e4f00bd15 --- /dev/null +++ b/libs/libsodium/src/crypto_box/crypto_box.c @@ -0,0 +1,114 @@ + +#include "crypto_box.h" + +size_t +crypto_box_seedbytes(void) +{ + return crypto_box_SEEDBYTES; +} + +size_t +crypto_box_publickeybytes(void) +{ + return crypto_box_PUBLICKEYBYTES; +} + +size_t +crypto_box_secretkeybytes(void) +{ + return crypto_box_SECRETKEYBYTES; +} + +size_t +crypto_box_beforenmbytes(void) +{ + return crypto_box_BEFORENMBYTES; +} + +size_t +crypto_box_noncebytes(void) +{ + return crypto_box_NONCEBYTES; +} + +size_t +crypto_box_zerobytes(void) +{ + return crypto_box_ZEROBYTES; +} + +size_t +crypto_box_boxzerobytes(void) +{ + return crypto_box_BOXZEROBYTES; +} + +size_t +crypto_box_macbytes(void) +{ + return crypto_box_MACBYTES; +} + +size_t +crypto_box_messagebytes_max(void) +{ + return crypto_box_MESSAGEBYTES_MAX; +} + +const char * +crypto_box_primitive(void) +{ + return crypto_box_PRIMITIVE; +} + +int +crypto_box_seed_keypair(unsigned char *pk, unsigned char *sk, + const unsigned char *seed) +{ + return crypto_box_curve25519xsalsa20poly1305_seed_keypair(pk, sk, seed); +} + +int +crypto_box_keypair(unsigned char *pk, unsigned char *sk) +{ + return crypto_box_curve25519xsalsa20poly1305_keypair(pk, sk); +} + +int +crypto_box_beforenm(unsigned char *k, const unsigned char *pk, + const unsigned char *sk) +{ + return crypto_box_curve25519xsalsa20poly1305_beforenm(k, pk, sk); +} + +int +crypto_box_afternm(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + return crypto_box_curve25519xsalsa20poly1305_afternm(c, m, mlen, n, k); +} + +int +crypto_box_open_afternm(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + return crypto_box_curve25519xsalsa20poly1305_open_afternm(m, c, clen, n, k); +} + +int +crypto_box(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk) +{ + return crypto_box_curve25519xsalsa20poly1305(c, m, mlen, n, pk, sk); +} + +int +crypto_box_open(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk) +{ + return crypto_box_curve25519xsalsa20poly1305_open(m, c, clen, n, pk, sk); +} diff --git a/libs/libsodium/src/crypto_box/crypto_box_easy.c b/libs/libsodium/src/crypto_box/crypto_box_easy.c new file mode 100644 index 0000000000..deb40b4083 --- /dev/null +++ b/libs/libsodium/src/crypto_box/crypto_box_easy.c @@ -0,0 +1,115 @@ + +#include +#include +#include + +#include "core.h" +#include "crypto_box.h" +#include "crypto_secretbox.h" +#include "private/common.h" +#include "utils.h" + +int +crypto_box_detached_afternm(unsigned char *c, unsigned char *mac, + const unsigned char *m, unsigned long long mlen, + const unsigned char *n, const unsigned char *k) +{ + return crypto_secretbox_detached(c, mac, m, mlen, n, k); +} + +int +crypto_box_detached(unsigned char *c, unsigned char *mac, + const unsigned char *m, unsigned long long mlen, + const unsigned char *n, const unsigned char *pk, + const unsigned char *sk) +{ + unsigned char k[crypto_box_BEFORENMBYTES]; + int ret; + + COMPILER_ASSERT(crypto_box_BEFORENMBYTES >= crypto_secretbox_KEYBYTES); + if (crypto_box_beforenm(k, pk, sk) != 0) { + return -1; + } + ret = crypto_box_detached_afternm(c, mac, m, mlen, n, k); + sodium_memzero(k, sizeof k); + + return ret; +} + +int +crypto_box_easy_afternm(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + if (mlen > crypto_box_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + return crypto_box_detached_afternm(c + crypto_box_MACBYTES, c, m, mlen, n, + k); +} + +int +crypto_box_easy(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk) +{ + if (mlen > crypto_box_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + return crypto_box_detached(c + crypto_box_MACBYTES, c, m, mlen, n, + pk, sk); +} + +int +crypto_box_open_detached_afternm(unsigned char *m, const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) +{ + return crypto_secretbox_open_detached(m, c, mac, clen, n, k); +} + +int +crypto_box_open_detached(unsigned char *m, const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk) +{ + unsigned char k[crypto_box_BEFORENMBYTES]; + int ret; + + if (crypto_box_beforenm(k, pk, sk) != 0) { + return -1; + } + ret = crypto_box_open_detached_afternm(m, c, mac, clen, n, k); + sodium_memzero(k, sizeof k); + + return ret; +} + +int +crypto_box_open_easy_afternm(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + if (clen < crypto_box_MACBYTES) { + return -1; + } + return crypto_box_open_detached_afternm(m, c + crypto_box_MACBYTES, c, + clen - crypto_box_MACBYTES, + n, k); +} + +int +crypto_box_open_easy(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk) +{ + if (clen < crypto_box_MACBYTES) { + return -1; + } + return crypto_box_open_detached(m, c + crypto_box_MACBYTES, c, + clen - crypto_box_MACBYTES, + n, pk, sk); +} diff --git a/libs/libsodium/src/crypto_box/crypto_box_seal.c b/libs/libsodium/src/crypto_box/crypto_box_seal.c new file mode 100644 index 0000000000..7181334578 --- /dev/null +++ b/libs/libsodium/src/crypto_box/crypto_box_seal.c @@ -0,0 +1,68 @@ + +#include + +#include "crypto_box.h" +#include "crypto_generichash.h" +#include "private/common.h" +#include "utils.h" + +static int +_crypto_box_seal_nonce(unsigned char *nonce, + const unsigned char *pk1, const unsigned char *pk2) +{ + crypto_generichash_state st; + + crypto_generichash_init(&st, NULL, 0U, crypto_box_NONCEBYTES); + crypto_generichash_update(&st, pk1, crypto_box_PUBLICKEYBYTES); + crypto_generichash_update(&st, pk2, crypto_box_PUBLICKEYBYTES); + crypto_generichash_final(&st, nonce, crypto_box_NONCEBYTES); + + return 0; +} + +int +crypto_box_seal(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *pk) +{ + unsigned char nonce[crypto_box_NONCEBYTES]; + unsigned char epk[crypto_box_PUBLICKEYBYTES]; + unsigned char esk[crypto_box_SECRETKEYBYTES]; + int ret; + + if (crypto_box_keypair(epk, esk) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + memcpy(c, epk, crypto_box_PUBLICKEYBYTES); + _crypto_box_seal_nonce(nonce, epk, pk); + ret = crypto_box_easy(c + crypto_box_PUBLICKEYBYTES, m, mlen, + nonce, pk, esk); + sodium_memzero(esk, sizeof esk); + sodium_memzero(epk, sizeof epk); + sodium_memzero(nonce, sizeof nonce); + + return ret; +} + +int +crypto_box_seal_open(unsigned char *m, const unsigned char *c, + unsigned long long clen, + const unsigned char *pk, const unsigned char *sk) +{ + unsigned char nonce[crypto_box_NONCEBYTES]; + + if (clen < crypto_box_SEALBYTES) { + return -1; + } + _crypto_box_seal_nonce(nonce, c, pk); + + COMPILER_ASSERT(crypto_box_PUBLICKEYBYTES < crypto_box_SEALBYTES); + return crypto_box_open_easy(m, c + crypto_box_PUBLICKEYBYTES, + clen - crypto_box_PUBLICKEYBYTES, + nonce, c, sk); +} + +size_t +crypto_box_sealbytes(void) +{ + return crypto_box_SEALBYTES; +} diff --git a/libs/libsodium/src/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c b/libs/libsodium/src/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c new file mode 100644 index 0000000000..5e2532eab7 --- /dev/null +++ b/libs/libsodium/src/crypto_box/curve25519xchacha20poly1305/box_curve25519xchacha20poly1305.c @@ -0,0 +1,204 @@ + +#include +#include +#include +#include + +#include "core.h" +#include "crypto_box_curve25519xchacha20poly1305.h" +#include "crypto_core_hchacha20.h" +#include "crypto_hash_sha512.h" +#include "crypto_scalarmult_curve25519.h" +#include "crypto_secretbox_xchacha20poly1305.h" +#include "private/common.h" +#include "randombytes.h" +#include "utils.h" + +int +crypto_box_curve25519xchacha20poly1305_seed_keypair(unsigned char *pk, + unsigned char *sk, + const unsigned char *seed) +{ + unsigned char hash[64]; + + crypto_hash_sha512(hash, seed, 32); + memcpy(sk, hash, 32); + sodium_memzero(hash, sizeof hash); + + return crypto_scalarmult_curve25519_base(pk, sk); +} + +int +crypto_box_curve25519xchacha20poly1305_keypair(unsigned char *pk, + unsigned char *sk) +{ + randombytes_buf(sk, 32); + + return crypto_scalarmult_curve25519_base(pk, sk); +} + +int +crypto_box_curve25519xchacha20poly1305_beforenm(unsigned char *k, + const unsigned char *pk, + const unsigned char *sk) +{ + static const unsigned char zero[16] = { 0 }; + unsigned char s[32]; + + if (crypto_scalarmult_curve25519(s, sk, pk) != 0) { + return -1; + } + return crypto_core_hchacha20(k, zero, s, NULL); +} + +int +crypto_box_curve25519xchacha20poly1305_detached_afternm( + unsigned char *c, unsigned char *mac, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, const unsigned char *k) +{ + return crypto_secretbox_xchacha20poly1305_detached(c, mac, m, mlen, n, k); +} + +int +crypto_box_curve25519xchacha20poly1305_detached( + unsigned char *c, unsigned char *mac, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, const unsigned char *pk, + const unsigned char *sk) +{ + unsigned char k[crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES]; + int ret; + + COMPILER_ASSERT(crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES >= + crypto_secretbox_xchacha20poly1305_KEYBYTES); + if (crypto_box_curve25519xchacha20poly1305_beforenm(k, pk, sk) != 0) { + return -1; + } + ret = crypto_box_curve25519xchacha20poly1305_detached_afternm(c, mac, m, + mlen, n, k); + sodium_memzero(k, sizeof k); + + return ret; +} + +int +crypto_box_curve25519xchacha20poly1305_easy_afternm(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k) +{ + if (mlen > crypto_box_curve25519xchacha20poly1305_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + return crypto_box_curve25519xchacha20poly1305_detached_afternm( + c + crypto_box_curve25519xchacha20poly1305_MACBYTES, c, m, mlen, n, k); +} + +int +crypto_box_curve25519xchacha20poly1305_easy( + unsigned char *c, const unsigned char *m, unsigned long long mlen, + const unsigned char *n, const unsigned char *pk, const unsigned char *sk) +{ + if (mlen > crypto_box_curve25519xchacha20poly1305_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + return crypto_box_curve25519xchacha20poly1305_detached( + c + crypto_box_curve25519xchacha20poly1305_MACBYTES, c, m, mlen, n, pk, + sk); +} + +int +crypto_box_curve25519xchacha20poly1305_open_detached_afternm( + unsigned char *m, const unsigned char *c, const unsigned char *mac, + unsigned long long clen, const unsigned char *n, const unsigned char *k) +{ + return crypto_secretbox_xchacha20poly1305_open_detached(m, c, mac, clen, n, + k); +} + +int +crypto_box_curve25519xchacha20poly1305_open_detached( + unsigned char *m, const unsigned char *c, const unsigned char *mac, + unsigned long long clen, const unsigned char *n, const unsigned char *pk, + const unsigned char *sk) +{ + unsigned char k[crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES]; + int ret; + + if (crypto_box_curve25519xchacha20poly1305_beforenm(k, pk, sk) != 0) { + return -1; + } + ret = crypto_box_curve25519xchacha20poly1305_open_detached_afternm( + m, c, mac, clen, n, k); + sodium_memzero(k, sizeof k); + + return ret; +} + +int +crypto_box_curve25519xchacha20poly1305_open_easy_afternm( + unsigned char *m, const unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + if (clen < crypto_box_curve25519xchacha20poly1305_MACBYTES) { + return -1; + } + return crypto_box_curve25519xchacha20poly1305_open_detached_afternm( + m, c + crypto_box_curve25519xchacha20poly1305_MACBYTES, c, + clen - crypto_box_curve25519xchacha20poly1305_MACBYTES, n, k); +} + +int +crypto_box_curve25519xchacha20poly1305_open_easy( + unsigned char *m, const unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *pk, const unsigned char *sk) +{ + if (clen < crypto_box_curve25519xchacha20poly1305_MACBYTES) { + return -1; + } + return crypto_box_curve25519xchacha20poly1305_open_detached( + m, c + crypto_box_curve25519xchacha20poly1305_MACBYTES, c, + clen - crypto_box_curve25519xchacha20poly1305_MACBYTES, n, pk, sk); +} + +size_t +crypto_box_curve25519xchacha20poly1305_seedbytes(void) +{ + return crypto_box_curve25519xchacha20poly1305_SEEDBYTES; +} + +size_t +crypto_box_curve25519xchacha20poly1305_publickeybytes(void) +{ + return crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES; +} + +size_t +crypto_box_curve25519xchacha20poly1305_secretkeybytes(void) +{ + return crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES; +} + +size_t +crypto_box_curve25519xchacha20poly1305_beforenmbytes(void) +{ + return crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES; +} + +size_t +crypto_box_curve25519xchacha20poly1305_noncebytes(void) +{ + return crypto_box_curve25519xchacha20poly1305_NONCEBYTES; +} + +size_t +crypto_box_curve25519xchacha20poly1305_macbytes(void) +{ + return crypto_box_curve25519xchacha20poly1305_MACBYTES; +} + +size_t +crypto_box_curve25519xchacha20poly1305_messagebytes_max(void) +{ + return crypto_box_curve25519xchacha20poly1305_MESSAGEBYTES_MAX; +} diff --git a/libs/libsodium/src/crypto_box/curve25519xchacha20poly1305/box_seal_curve25519xchacha20poly1305.c b/libs/libsodium/src/crypto_box/curve25519xchacha20poly1305/box_seal_curve25519xchacha20poly1305.c new file mode 100644 index 0000000000..9e73a265aa --- /dev/null +++ b/libs/libsodium/src/crypto_box/curve25519xchacha20poly1305/box_seal_curve25519xchacha20poly1305.c @@ -0,0 +1,79 @@ + +#include + +#include "crypto_box_curve25519xchacha20poly1305.h" +#include "crypto_generichash.h" +#include "private/common.h" +#include "utils.h" + +static int +_crypto_box_curve25519xchacha20poly1305_seal_nonce(unsigned char *nonce, + const unsigned char *pk1, + const unsigned char *pk2) +{ + crypto_generichash_state st; + + crypto_generichash_init(&st, NULL, 0U, + crypto_box_curve25519xchacha20poly1305_NONCEBYTES); + crypto_generichash_update(&st, pk1, + crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES); + crypto_generichash_update(&st, pk2, + crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES); + crypto_generichash_final(&st, nonce, + crypto_box_curve25519xchacha20poly1305_NONCEBYTES); + + return 0; +} + +int +crypto_box_curve25519xchacha20poly1305_seal(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk) +{ + unsigned char nonce[crypto_box_curve25519xchacha20poly1305_NONCEBYTES]; + unsigned char epk[crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES]; + unsigned char esk[crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES]; + int ret; + + if (crypto_box_curve25519xchacha20poly1305_keypair(epk, esk) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + memcpy(c, epk, crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES); + _crypto_box_curve25519xchacha20poly1305_seal_nonce(nonce, epk, pk); + ret = crypto_box_curve25519xchacha20poly1305_easy( + c + crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES, m, mlen, + nonce, pk, esk); + sodium_memzero(esk, sizeof esk); + sodium_memzero(epk, sizeof epk); + sodium_memzero(nonce, sizeof nonce); + + return ret; +} + +int +crypto_box_curve25519xchacha20poly1305_seal_open(unsigned char *m, const unsigned char *c, + unsigned long long clen, + const unsigned char *pk, + const unsigned char *sk) +{ + unsigned char nonce[crypto_box_curve25519xchacha20poly1305_NONCEBYTES]; + + if (clen < crypto_box_curve25519xchacha20poly1305_SEALBYTES) { + return -1; + } + _crypto_box_curve25519xchacha20poly1305_seal_nonce(nonce, c, pk); + + COMPILER_ASSERT(crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES < + crypto_box_curve25519xchacha20poly1305_SEALBYTES); + + return crypto_box_curve25519xchacha20poly1305_open_easy( + m, c + crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES, + clen - crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES, + nonce, c, sk); +} + +size_t +crypto_box_curve25519xchacha20poly1305_sealbytes(void) +{ + return crypto_box_curve25519xchacha20poly1305_SEALBYTES; +} diff --git a/libs/libsodium/src/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c b/libs/libsodium/src/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c new file mode 100644 index 0000000000..4c1d62ed43 --- /dev/null +++ b/libs/libsodium/src/crypto_box/curve25519xsalsa20poly1305/box_curve25519xsalsa20poly1305.c @@ -0,0 +1,156 @@ +#include + +#include "crypto_box_curve25519xsalsa20poly1305.h" +#include "crypto_core_hsalsa20.h" +#include "crypto_hash_sha512.h" +#include "crypto_scalarmult_curve25519.h" +#include "crypto_secretbox_xsalsa20poly1305.h" +#include "randombytes.h" +#include "utils.h" + +int +crypto_box_curve25519xsalsa20poly1305_seed_keypair(unsigned char *pk, + unsigned char *sk, + const unsigned char *seed) +{ + unsigned char hash[64]; + + crypto_hash_sha512(hash, seed, 32); + memcpy(sk, hash, 32); + sodium_memzero(hash, sizeof hash); + + return crypto_scalarmult_curve25519_base(pk, sk); +} + +int +crypto_box_curve25519xsalsa20poly1305_keypair(unsigned char *pk, + unsigned char *sk) +{ + randombytes_buf(sk, 32); + + return crypto_scalarmult_curve25519_base(pk, sk); +} + +int +crypto_box_curve25519xsalsa20poly1305_beforenm(unsigned char *k, + const unsigned char *pk, + const unsigned char *sk) +{ + static const unsigned char zero[16] = { 0 }; + unsigned char s[32]; + + if (crypto_scalarmult_curve25519(s, sk, pk) != 0) { + return -1; + } + return crypto_core_hsalsa20(k, zero, s, NULL); +} + +int +crypto_box_curve25519xsalsa20poly1305_afternm(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k) +{ + return crypto_secretbox_xsalsa20poly1305(c, m, mlen, n, k); +} + +int +crypto_box_curve25519xsalsa20poly1305_open_afternm(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) +{ + return crypto_secretbox_xsalsa20poly1305_open(m, c, clen, n, k); +} + +int +crypto_box_curve25519xsalsa20poly1305(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *pk, + const unsigned char *sk) +{ + unsigned char k[crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES]; + int ret; + + if (crypto_box_curve25519xsalsa20poly1305_beforenm(k, pk, sk) != 0) { + return -1; + } + ret = crypto_box_curve25519xsalsa20poly1305_afternm(c, m, mlen, n, k); + sodium_memzero(k, sizeof k); + + return ret; +} + +int +crypto_box_curve25519xsalsa20poly1305_open( + unsigned char *m, const unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *pk, const unsigned char *sk) +{ + unsigned char k[crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES]; + int ret; + + if (crypto_box_curve25519xsalsa20poly1305_beforenm(k, pk, sk) != 0) { + return -1; + } + ret = crypto_box_curve25519xsalsa20poly1305_open_afternm(m, c, clen, n, k); + sodium_memzero(k, sizeof k); + + return ret; +} + +size_t +crypto_box_curve25519xsalsa20poly1305_seedbytes(void) +{ + return crypto_box_curve25519xsalsa20poly1305_SEEDBYTES; +} + +size_t +crypto_box_curve25519xsalsa20poly1305_publickeybytes(void) +{ + return crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES; +} + +size_t +crypto_box_curve25519xsalsa20poly1305_secretkeybytes(void) +{ + return crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES; +} + +size_t +crypto_box_curve25519xsalsa20poly1305_beforenmbytes(void) +{ + return crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES; +} + +size_t +crypto_box_curve25519xsalsa20poly1305_noncebytes(void) +{ + return crypto_box_curve25519xsalsa20poly1305_NONCEBYTES; +} + +size_t +crypto_box_curve25519xsalsa20poly1305_zerobytes(void) +{ + return crypto_box_curve25519xsalsa20poly1305_ZEROBYTES; +} + +size_t +crypto_box_curve25519xsalsa20poly1305_boxzerobytes(void) +{ + return crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES; +} + +size_t +crypto_box_curve25519xsalsa20poly1305_macbytes(void) +{ + return crypto_box_curve25519xsalsa20poly1305_MACBYTES; +} + +size_t +crypto_box_curve25519xsalsa20poly1305_messagebytes_max(void) +{ + return crypto_box_curve25519xsalsa20poly1305_MESSAGEBYTES_MAX; +} diff --git a/libs/libsodium/src/crypto_core/ed25519/core_ed25519.c b/libs/libsodium/src/crypto_core/ed25519/core_ed25519.c new file mode 100644 index 0000000000..1bcf5022b1 --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/core_ed25519.c @@ -0,0 +1,79 @@ + +#include "crypto_core_ed25519.h" +#include "private/common.h" +#include "private/ed25519_ref10.h" + +int +crypto_core_ed25519_is_valid_point(const unsigned char *p) +{ + ge25519_p3 p_p3; + + if (ge25519_is_canonical(p) == 0 || + ge25519_has_small_order(p) != 0 || + ge25519_frombytes(&p_p3, p) != 0 || + ge25519_is_on_curve(&p_p3) == 0 || + ge25519_is_on_main_subgroup(&p_p3) == 0) { + return 0; + } + return 1; +} + +int +crypto_core_ed25519_add(unsigned char *r, + const unsigned char *p, const unsigned char *q) +{ + ge25519_p3 p_p3, q_p3, r_p3; + ge25519_p1p1 r_p1p1; + ge25519_cached q_cached; + + if (ge25519_frombytes(&p_p3, p) != 0 || ge25519_is_on_curve(&p_p3) == 0 || + ge25519_frombytes(&q_p3, q) != 0 || ge25519_is_on_curve(&q_p3) == 0) { + return -1; + } + ge25519_p3_to_cached(&q_cached, &q_p3); + ge25519_add(&r_p1p1, &p_p3, &q_cached); + ge25519_p1p1_to_p3(&r_p3, &r_p1p1); + ge25519_p3_tobytes(r, &r_p3); + + return 0; +} + +int +crypto_core_ed25519_sub(unsigned char *r, + const unsigned char *p, const unsigned char *q) +{ + ge25519_p3 p_p3, q_p3, r_p3; + ge25519_p1p1 r_p1p1; + ge25519_cached q_cached; + + if (ge25519_frombytes(&p_p3, p) != 0 || ge25519_is_on_curve(&p_p3) == 0 || + ge25519_frombytes(&q_p3, q) != 0 || ge25519_is_on_curve(&q_p3) == 0) { + return -1; + } + ge25519_p3_to_cached(&q_cached, &q_p3); + ge25519_sub(&r_p1p1, &p_p3, &q_cached); + ge25519_p1p1_to_p3(&r_p3, &r_p1p1); + ge25519_p3_tobytes(r, &r_p3); + + return 0; +} + +int +crypto_core_ed25519_from_uniform(unsigned char *p, const unsigned char *r) +{ + ge25519_from_uniform(p, r); + + return - ge25519_has_small_order(p); +} + +size_t +crypto_core_ed25519_bytes(void) +{ + return crypto_core_ed25519_BYTES; +} + +size_t +crypto_core_ed25519_uniformbytes(void) +{ + return crypto_core_ed25519_UNIFORMBYTES; +} diff --git a/libs/libsodium/src/crypto_core/ed25519/ref10/ed25519_ref10.c b/libs/libsodium/src/crypto_core/ed25519/ref10/ed25519_ref10.c new file mode 100644 index 0000000000..f7b8280685 --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/ref10/ed25519_ref10.c @@ -0,0 +1,2031 @@ +#include +#include +#include +#include + +#include "crypto_verify_32.h" +#include "private/common.h" +#include "private/ed25519_ref10.h" +#include "utils.h" + +static inline uint64_t +load_3(const unsigned char *in) +{ + uint64_t result; + + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + + return result; +} + +static inline uint64_t +load_4(const unsigned char *in) +{ + uint64_t result; + + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + result |= ((uint64_t) in[3]) << 24; + + return result; +} + +/* + * Field arithmetic: + * Use 5*51 bit limbs on 64-bit systems with support for 128 bit arithmetic, + * and 10*25.5 bit limbs elsewhere. + * + * Functions used elsewhere that are candidates for inlining are defined + * via "private/curve25519_ref10.h". + */ + +#ifdef HAVE_TI_MODE +# include "fe_51/constants.h" +# include "fe_51/fe.h" +#else +# include "fe_25_5/constants.h" +# include "fe_25_5/fe.h" +#endif + +void +fe25519_invert(fe25519 out, const fe25519 z) +{ + fe25519 t0; + fe25519 t1; + fe25519 t2; + fe25519 t3; + int i; + + fe25519_sq(t0, z); + fe25519_sq(t1, t0); + fe25519_sq(t1, t1); + fe25519_mul(t1, z, t1); + fe25519_mul(t0, t0, t1); + fe25519_sq(t2, t0); + fe25519_mul(t1, t1, t2); + fe25519_sq(t2, t1); + for (i = 1; i < 5; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t2, t1); + for (i = 1; i < 10; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t2, t2, t1); + fe25519_sq(t3, t2); + for (i = 1; i < 20; ++i) { + fe25519_sq(t3, t3); + } + fe25519_mul(t2, t3, t2); + fe25519_sq(t2, t2); + for (i = 1; i < 10; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t2, t1); + for (i = 1; i < 50; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t2, t2, t1); + fe25519_sq(t3, t2); + for (i = 1; i < 100; ++i) { + fe25519_sq(t3, t3); + } + fe25519_mul(t2, t3, t2); + fe25519_sq(t2, t2); + for (i = 1; i < 50; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t1, t1); + for (i = 1; i < 5; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(out, t1, t0); +} + +static void +fe25519_pow22523(fe25519 out, const fe25519 z) +{ + fe25519 t0; + fe25519 t1; + fe25519 t2; + int i; + + fe25519_sq(t0, z); + fe25519_sq(t1, t0); + fe25519_sq(t1, t1); + fe25519_mul(t1, z, t1); + fe25519_mul(t0, t0, t1); + fe25519_sq(t0, t0); + fe25519_mul(t0, t1, t0); + fe25519_sq(t1, t0); + for (i = 1; i < 5; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t0, t1, t0); + fe25519_sq(t1, t0); + for (i = 1; i < 10; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t1, t1, t0); + fe25519_sq(t2, t1); + for (i = 1; i < 20; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t1, t1); + for (i = 1; i < 10; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t0, t1, t0); + fe25519_sq(t1, t0); + for (i = 1; i < 50; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t1, t1, t0); + fe25519_sq(t2, t1); + for (i = 1; i < 100; ++i) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t1, t1); + for (i = 1; i < 50; ++i) { + fe25519_sq(t1, t1); + } + fe25519_mul(t0, t1, t0); + fe25519_sq(t0, t0); + fe25519_sq(t0, t0); + fe25519_mul(out, t0, z); +} + +/* + r = p + q + */ + +void +ge25519_add(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_cached *q) +{ + fe25519 t0; + + fe25519_add(r->X, p->Y, p->X); + fe25519_sub(r->Y, p->Y, p->X); + fe25519_mul(r->Z, r->X, q->YplusX); + fe25519_mul(r->Y, r->Y, q->YminusX); + fe25519_mul(r->T, q->T2d, p->T); + fe25519_mul(r->X, p->Z, q->Z); + fe25519_add(t0, r->X, r->X); + fe25519_sub(r->X, r->Z, r->Y); + fe25519_add(r->Y, r->Z, r->Y); + fe25519_add(r->Z, t0, r->T); + fe25519_sub(r->T, t0, r->T); +} + +static void +slide_vartime(signed char *r, const unsigned char *a) +{ + int i; + int b; + int k; + int ribs; + int cmp; + + for (i = 0; i < 256; ++i) { + r[i] = 1 & (a[i >> 3] >> (i & 7)); + } + for (i = 0; i < 256; ++i) { + if (! r[i]) { + continue; + } + for (b = 1; b <= 6 && i + b < 256; ++b) { + if (! r[i + b]) { + continue; + } + ribs = r[i + b] << b; + cmp = r[i] + ribs; + if (cmp <= 15) { + r[i] = cmp; + r[i + b] = 0; + } else { + cmp = r[i] - ribs; + if (cmp < -15) { + break; + } + r[i] = cmp; + for (k = i + b; k < 256; ++k) { + if (! r[k]) { + r[k] = 1; + break; + } + r[k] = 0; + } + } + } + } +} + +int +ge25519_frombytes(ge25519_p3 *h, const unsigned char *s) +{ + fe25519 u; + fe25519 v; + fe25519 v3; + fe25519 vxx; + fe25519 m_root_check, p_root_check; + fe25519 negx; + fe25519 x_sqrtm1; + int has_m_root, has_p_root; + + fe25519_frombytes(h->Y, s); + fe25519_1(h->Z); + fe25519_sq(u, h->Y); + fe25519_mul(v, u, d); + fe25519_sub(u, u, h->Z); /* u = y^2-1 */ + fe25519_add(v, v, h->Z); /* v = dy^2+1 */ + + fe25519_sq(v3, v); + fe25519_mul(v3, v3, v); /* v3 = v^3 */ + fe25519_sq(h->X, v3); + fe25519_mul(h->X, h->X, v); + fe25519_mul(h->X, h->X, u); /* x = uv^7 */ + + fe25519_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */ + fe25519_mul(h->X, h->X, v3); + fe25519_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */ + + fe25519_sq(vxx, h->X); + fe25519_mul(vxx, vxx, v); + fe25519_sub(m_root_check, vxx, u); /* vx^2-u */ + fe25519_add(p_root_check, vxx, u); /* vx^2+u */ + has_m_root = fe25519_iszero(m_root_check); + has_p_root = fe25519_iszero(p_root_check); + fe25519_mul(x_sqrtm1, h->X, sqrtm1); /* x*sqrt(-1) */ + fe25519_cmov(h->X, x_sqrtm1, 1 - has_m_root); + + fe25519_neg(negx, h->X); + fe25519_cmov(h->X, negx, fe25519_isnegative(h->X) ^ (s[31] >> 7)); + fe25519_mul(h->T, h->X, h->Y); + + return (has_m_root | has_p_root) - 1; +} + +int +ge25519_frombytes_negate_vartime(ge25519_p3 *h, const unsigned char *s) +{ + fe25519 u; + fe25519 v; + fe25519 v3; + fe25519 vxx; + fe25519 m_root_check, p_root_check; + + fe25519_frombytes(h->Y, s); + fe25519_1(h->Z); + fe25519_sq(u, h->Y); + fe25519_mul(v, u, d); + fe25519_sub(u, u, h->Z); /* u = y^2-1 */ + fe25519_add(v, v, h->Z); /* v = dy^2+1 */ + + fe25519_sq(v3, v); + fe25519_mul(v3, v3, v); /* v3 = v^3 */ + fe25519_sq(h->X, v3); + fe25519_mul(h->X, h->X, v); + fe25519_mul(h->X, h->X, u); /* x = uv^7 */ + + fe25519_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */ + fe25519_mul(h->X, h->X, v3); + fe25519_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */ + + fe25519_sq(vxx, h->X); + fe25519_mul(vxx, vxx, v); + fe25519_sub(m_root_check, vxx, u); /* vx^2-u */ + if (fe25519_iszero(m_root_check) == 0) { + fe25519_add(p_root_check, vxx, u); /* vx^2+u */ + if (fe25519_iszero(p_root_check) == 0) { + return -1; + } + fe25519_mul(h->X, h->X, sqrtm1); + } + + if (fe25519_isnegative(h->X) == (s[31] >> 7)) { + fe25519_neg(h->X, h->X); + } + fe25519_mul(h->T, h->X, h->Y); + + return 0; +} + +/* + r = p + q + */ + +static void +ge25519_madd(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_precomp *q) +{ + fe25519 t0; + + fe25519_add(r->X, p->Y, p->X); + fe25519_sub(r->Y, p->Y, p->X); + fe25519_mul(r->Z, r->X, q->yplusx); + fe25519_mul(r->Y, r->Y, q->yminusx); + fe25519_mul(r->T, q->xy2d, p->T); + fe25519_add(t0, p->Z, p->Z); + fe25519_sub(r->X, r->Z, r->Y); + fe25519_add(r->Y, r->Z, r->Y); + fe25519_add(r->Z, t0, r->T); + fe25519_sub(r->T, t0, r->T); +} + +/* + r = p - q + */ + +static void +ge25519_msub(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_precomp *q) +{ + fe25519 t0; + + fe25519_add(r->X, p->Y, p->X); + fe25519_sub(r->Y, p->Y, p->X); + fe25519_mul(r->Z, r->X, q->yminusx); + fe25519_mul(r->Y, r->Y, q->yplusx); + fe25519_mul(r->T, q->xy2d, p->T); + fe25519_add(t0, p->Z, p->Z); + fe25519_sub(r->X, r->Z, r->Y); + fe25519_add(r->Y, r->Z, r->Y); + fe25519_sub(r->Z, t0, r->T); + fe25519_add(r->T, t0, r->T); +} + +/* + r = p + */ + +void +ge25519_p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p) +{ + fe25519_mul(r->X, p->X, p->T); + fe25519_mul(r->Y, p->Y, p->Z); + fe25519_mul(r->Z, p->Z, p->T); +} + +/* + r = p + */ + +void +ge25519_p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p) +{ + fe25519_mul(r->X, p->X, p->T); + fe25519_mul(r->Y, p->Y, p->Z); + fe25519_mul(r->Z, p->Z, p->T); + fe25519_mul(r->T, p->X, p->Y); +} + +static void +ge25519_p2_0(ge25519_p2 *h) +{ + fe25519_0(h->X); + fe25519_1(h->Y); + fe25519_1(h->Z); +} + +/* + r = 2 * p + */ + +static void +ge25519_p2_dbl(ge25519_p1p1 *r, const ge25519_p2 *p) +{ + fe25519 t0; + + fe25519_sq(r->X, p->X); + fe25519_sq(r->Z, p->Y); + fe25519_sq2(r->T, p->Z); + fe25519_add(r->Y, p->X, p->Y); + fe25519_sq(t0, r->Y); + fe25519_add(r->Y, r->Z, r->X); + fe25519_sub(r->Z, r->Z, r->X); + fe25519_sub(r->X, t0, r->Y); + fe25519_sub(r->T, r->T, r->Z); +} + +static void +ge25519_p3_0(ge25519_p3 *h) +{ + fe25519_0(h->X); + fe25519_1(h->Y); + fe25519_1(h->Z); + fe25519_0(h->T); +} + +static void +ge25519_cached_0(ge25519_cached *h) +{ + fe25519_1(h->YplusX); + fe25519_1(h->YminusX); + fe25519_1(h->Z); + fe25519_0(h->T2d); +} + +/* + r = p + */ + +void +ge25519_p3_to_cached(ge25519_cached *r, const ge25519_p3 *p) +{ + fe25519_add(r->YplusX, p->Y, p->X); + fe25519_sub(r->YminusX, p->Y, p->X); + fe25519_copy(r->Z, p->Z); + fe25519_mul(r->T2d, p->T, d2); +} + +static void +ge25519_p3_to_precomp(ge25519_precomp *pi, const ge25519_p3 *p) +{ + fe25519 recip; + fe25519 x; + fe25519 y; + fe25519 xy; + + fe25519_invert(recip, p->Z); + fe25519_mul(x, p->X, recip); + fe25519_mul(y, p->Y, recip); + fe25519_add(pi->yplusx, y, x); + fe25519_sub(pi->yminusx, y, x); + fe25519_mul(xy, x, y); + fe25519_mul(pi->xy2d, xy, d2); +} + +/* + r = p + */ + +static void +ge25519_p3_to_p2(ge25519_p2 *r, const ge25519_p3 *p) +{ + fe25519_copy(r->X, p->X); + fe25519_copy(r->Y, p->Y); + fe25519_copy(r->Z, p->Z); +} + +void +ge25519_p3_tobytes(unsigned char *s, const ge25519_p3 *h) +{ + fe25519 recip; + fe25519 x; + fe25519 y; + + fe25519_invert(recip, h->Z); + fe25519_mul(x, h->X, recip); + fe25519_mul(y, h->Y, recip); + fe25519_tobytes(s, y); + s[31] ^= fe25519_isnegative(x) << 7; +} + +/* + r = 2 * p + */ + +static void +ge25519_p3_dbl(ge25519_p1p1 *r, const ge25519_p3 *p) +{ + ge25519_p2 q; + ge25519_p3_to_p2(&q, p); + ge25519_p2_dbl(r, &q); +} + +static void +ge25519_precomp_0(ge25519_precomp *h) +{ + fe25519_1(h->yplusx); + fe25519_1(h->yminusx); + fe25519_0(h->xy2d); +} + +static unsigned char +equal(signed char b, signed char c) +{ + unsigned char ub = b; + unsigned char uc = c; + unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ + uint32_t y = x; /* 0: yes; 1..255: no */ + + y -= 1; /* 4294967295: yes; 0..254: no */ + y >>= 31; /* 1: yes; 0: no */ + + return y; +} + +static unsigned char +negative(signed char b) +{ + /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + uint64_t x = b; + + x >>= 63; /* 1: yes; 0: no */ + + return x; +} + +static void +ge25519_cmov(ge25519_precomp *t, const ge25519_precomp *u, unsigned char b) +{ + fe25519_cmov(t->yplusx, u->yplusx, b); + fe25519_cmov(t->yminusx, u->yminusx, b); + fe25519_cmov(t->xy2d, u->xy2d, b); +} + +static void +ge25519_cmov_cached(ge25519_cached *t, const ge25519_cached *u, unsigned char b) +{ + fe25519_cmov(t->YplusX, u->YplusX, b); + fe25519_cmov(t->YminusX, u->YminusX, b); + fe25519_cmov(t->Z, u->Z, b); + fe25519_cmov(t->T2d, u->T2d, b); +} + +static void +ge25519_select(ge25519_precomp *t, const ge25519_precomp precomp[8], const signed char b) +{ + ge25519_precomp minust; + const unsigned char bnegative = negative(b); + const unsigned char babs = b - (((-bnegative) & b) * ((signed char) 1 << 1)); + + ge25519_precomp_0(t); + ge25519_cmov(t, &precomp[0], equal(babs, 1)); + ge25519_cmov(t, &precomp[1], equal(babs, 2)); + ge25519_cmov(t, &precomp[2], equal(babs, 3)); + ge25519_cmov(t, &precomp[3], equal(babs, 4)); + ge25519_cmov(t, &precomp[4], equal(babs, 5)); + ge25519_cmov(t, &precomp[5], equal(babs, 6)); + ge25519_cmov(t, &precomp[6], equal(babs, 7)); + ge25519_cmov(t, &precomp[7], equal(babs, 8)); + fe25519_copy(minust.yplusx, t->yminusx); + fe25519_copy(minust.yminusx, t->yplusx); + fe25519_neg(minust.xy2d, t->xy2d); + ge25519_cmov(t, &minust, bnegative); +} + +static void +ge25519_select_base(ge25519_precomp *t, const int pos, const signed char b) +{ + static const ge25519_precomp base[32][8] = { /* base[i][j] = (j+1)*256^i*B */ +#ifdef HAVE_TI_MODE +# include "fe_51/base.h" +#else +# include "fe_25_5/base.h" +#endif + }; + ge25519_select(t, base[pos], b); +} + +static void +ge25519_select_cached(ge25519_cached *t, const ge25519_cached cached[8], const signed char b) +{ + ge25519_cached minust; + const unsigned char bnegative = negative(b); + const unsigned char babs = b - (((-bnegative) & b) * ((signed char) 1 << 1)); + + ge25519_cached_0(t); + ge25519_cmov_cached(t, &cached[0], equal(babs, 1)); + ge25519_cmov_cached(t, &cached[1], equal(babs, 2)); + ge25519_cmov_cached(t, &cached[2], equal(babs, 3)); + ge25519_cmov_cached(t, &cached[3], equal(babs, 4)); + ge25519_cmov_cached(t, &cached[4], equal(babs, 5)); + ge25519_cmov_cached(t, &cached[5], equal(babs, 6)); + ge25519_cmov_cached(t, &cached[6], equal(babs, 7)); + ge25519_cmov_cached(t, &cached[7], equal(babs, 8)); + fe25519_copy(minust.YplusX, t->YminusX); + fe25519_copy(minust.YminusX, t->YplusX); + fe25519_copy(minust.Z, t->Z); + fe25519_neg(minust.T2d, t->T2d); + ge25519_cmov_cached(t, &minust, bnegative); +} + +/* + r = p - q + */ + +void +ge25519_sub(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_cached *q) +{ + fe25519 t0; + + fe25519_add(r->X, p->Y, p->X); + fe25519_sub(r->Y, p->Y, p->X); + fe25519_mul(r->Z, r->X, q->YminusX); + fe25519_mul(r->Y, r->Y, q->YplusX); + fe25519_mul(r->T, q->T2d, p->T); + fe25519_mul(r->X, p->Z, q->Z); + fe25519_add(t0, r->X, r->X); + fe25519_sub(r->X, r->Z, r->Y); + fe25519_add(r->Y, r->Z, r->Y); + fe25519_sub(r->Z, t0, r->T); + fe25519_add(r->T, t0, r->T); +} + +void +ge25519_tobytes(unsigned char *s, const ge25519_p2 *h) +{ + fe25519 recip; + fe25519 x; + fe25519 y; + + fe25519_invert(recip, h->Z); + fe25519_mul(x, h->X, recip); + fe25519_mul(y, h->Y, recip); + fe25519_tobytes(s, y); + s[31] ^= fe25519_isnegative(x) << 7; +} + +/* + r = a * A + b * B + where a = a[0]+256*a[1]+...+256^31 a[31]. + and b = b[0]+256*b[1]+...+256^31 b[31]. + B is the Ed25519 base point (x,4/5) with x positive. + + Only used for signatures verification. + */ + +void +ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a, + const ge25519_p3 *A, const unsigned char *b) +{ + static const ge25519_precomp Bi[8] = { +#ifdef HAVE_TI_MODE +# include "fe_51/base2.h" +#else +# include "fe_25_5/base2.h" +#endif + }; + signed char aslide[256]; + signed char bslide[256]; + ge25519_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ + ge25519_p1p1 t; + ge25519_p3 u; + ge25519_p3 A2; + int i; + + slide_vartime(aslide, a); + slide_vartime(bslide, b); + + ge25519_p3_to_cached(&Ai[0], A); + + ge25519_p3_dbl(&t, A); + ge25519_p1p1_to_p3(&A2, &t); + + ge25519_add(&t, &A2, &Ai[0]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[1], &u); + + ge25519_add(&t, &A2, &Ai[1]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[2], &u); + + ge25519_add(&t, &A2, &Ai[2]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[3], &u); + + ge25519_add(&t, &A2, &Ai[3]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[4], &u); + + ge25519_add(&t, &A2, &Ai[4]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[5], &u); + + ge25519_add(&t, &A2, &Ai[5]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[6], &u); + + ge25519_add(&t, &A2, &Ai[6]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[7], &u); + + ge25519_p2_0(r); + + for (i = 255; i >= 0; --i) { + if (aslide[i] || bslide[i]) { + break; + } + } + + for (; i >= 0; --i) { + ge25519_p2_dbl(&t, r); + + if (aslide[i] > 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_add(&t, &u, &Ai[aslide[i] / 2]); + } else if (aslide[i] < 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_sub(&t, &u, &Ai[(-aslide[i]) / 2]); + } + + if (bslide[i] > 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_madd(&t, &u, &Bi[bslide[i] / 2]); + } else if (bslide[i] < 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_msub(&t, &u, &Bi[(-bslide[i]) / 2]); + } + + ge25519_p1p1_to_p2(r, &t); + } +} + +/* + h = a * p + where a = a[0]+256*a[1]+...+256^31 a[31] + + Preconditions: + a[31] <= 127 + + p is public + */ + +void +ge25519_scalarmult(ge25519_p3 *h, const unsigned char *a, const ge25519_p3 *p) +{ + signed char e[64]; + signed char carry; + ge25519_p1p1 r; + ge25519_p2 s; + ge25519_p1p1 t2, t3, t4, t5, t6, t7, t8; + ge25519_p3 p2, p3, p4, p5, p6, p7, p8; + ge25519_cached pi[8]; + ge25519_cached t; + int i; + + ge25519_p3_to_cached(&pi[1 - 1], p); /* p */ + + ge25519_p3_dbl(&t2, p); + ge25519_p1p1_to_p3(&p2, &t2); + ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */ + + ge25519_add(&t3, p, &pi[2 - 1]); + ge25519_p1p1_to_p3(&p3, &t3); + ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */ + + ge25519_p3_dbl(&t4, &p2); + ge25519_p1p1_to_p3(&p4, &t4); + ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */ + + ge25519_add(&t5, p, &pi[4 - 1]); + ge25519_p1p1_to_p3(&p5, &t5); + ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */ + + ge25519_p3_dbl(&t6, &p3); + ge25519_p1p1_to_p3(&p6, &t6); + ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */ + + ge25519_add(&t7, p, &pi[6 - 1]); + ge25519_p1p1_to_p3(&p7, &t7); + ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */ + + ge25519_p3_dbl(&t8, &p4); + ge25519_p1p1_to_p3(&p8, &t8); + ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */ + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for (i = 0; i < 63; ++i) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry * ((signed char) 1 << 4); + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge25519_p3_0(h); + + for (i = 63; i != 0; i--) { + ge25519_select_cached(&t, pi, e[i]); + ge25519_add(&r, h, &t); + + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + + ge25519_p1p1_to_p3(h, &r); /* *16 */ + } + ge25519_select_cached(&t, pi, e[i]); + ge25519_add(&r, h, &t); + + ge25519_p1p1_to_p3(h, &r); +} + +/* + h = a * B (with precomputation) + where a = a[0]+256*a[1]+...+256^31 a[31] + B is the Ed25519 base point (x,4/5) with x positive + (as bytes: 0x5866666666666666666666666666666666666666666666666666666666666666) + + Preconditions: + a[31] <= 127 + */ + +void +ge25519_scalarmult_base(ge25519_p3 *h, const unsigned char *a) +{ + signed char e[64]; + signed char carry; + ge25519_p1p1 r; + ge25519_p2 s; + ge25519_precomp t; + int i; + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for (i = 0; i < 63; ++i) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry * ((signed char) 1 << 4); + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge25519_p3_0(h); + + for (i = 1; i < 64; i += 2) { + ge25519_select_base(&t, i / 2, e[i]); + ge25519_madd(&r, h, &t); + ge25519_p1p1_to_p3(h, &r); + } + + ge25519_p3_dbl(&r, h); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p2(&s, &r); + ge25519_p2_dbl(&r, &s); + ge25519_p1p1_to_p3(h, &r); + + for (i = 0; i < 64; i += 2) { + ge25519_select_base(&t, i / 2, e[i]); + ge25519_madd(&r, h, &t); + ge25519_p1p1_to_p3(h, &r); + } +} + +/* multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493 */ +static void +ge25519_mul_l(ge25519_p3 *r, const ge25519_p3 *A) +{ + static const signed char aslide[253] = { + 13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + }; + ge25519_cached Ai[8]; + ge25519_p1p1 t; + ge25519_p3 u; + ge25519_p3 A2; + int i; + + ge25519_p3_to_cached(&Ai[0], A); + ge25519_p3_dbl(&t, A); + ge25519_p1p1_to_p3(&A2, &t); + ge25519_add(&t, &A2, &Ai[0]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[1], &u); + ge25519_add(&t, &A2, &Ai[1]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[2], &u); + ge25519_add(&t, &A2, &Ai[2]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[3], &u); + ge25519_add(&t, &A2, &Ai[3]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[4], &u); + ge25519_add(&t, &A2, &Ai[4]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[5], &u); + ge25519_add(&t, &A2, &Ai[5]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[6], &u); + ge25519_add(&t, &A2, &Ai[6]); + ge25519_p1p1_to_p3(&u, &t); + ge25519_p3_to_cached(&Ai[7], &u); + + ge25519_p3_0(r); + + for (i = 252; i >= 0; --i) { + ge25519_p3_dbl(&t, r); + + if (aslide[i] > 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_add(&t, &u, &Ai[aslide[i] / 2]); + } else if (aslide[i] < 0) { + ge25519_p1p1_to_p3(&u, &t); + ge25519_sub(&t, &u, &Ai[(-aslide[i]) / 2]); + } + + ge25519_p1p1_to_p3(r, &t); + } +} + +int +ge25519_is_on_curve(const ge25519_p3 *p) +{ + fe25519 x2; + fe25519 y2; + fe25519 z2; + fe25519 z4; + fe25519 t0; + fe25519 t1; + + fe25519_sq(x2, p->X); + fe25519_sq(y2, p->Y); + fe25519_sq(z2, p->Z); + fe25519_sub(t0, y2, x2); + fe25519_mul(t0, t0, z2); + + fe25519_mul(t1, x2, y2); + fe25519_mul(t1, t1, d); + fe25519_sq(z4, z2); + fe25519_add(t1, t1, z4); + fe25519_sub(t0, t0, t1); + + return fe25519_iszero(t0); +} + +int +ge25519_is_on_main_subgroup(const ge25519_p3 *p) +{ + ge25519_p3 pl; + + ge25519_mul_l(&pl, p); + + return fe25519_iszero(pl.X); +} + +int +ge25519_is_canonical(const unsigned char *s) +{ + unsigned char c; + unsigned char d; + unsigned int i; + + c = (s[31] & 0x7f) ^ 0x7f; + for (i = 30; i > 0; i--) { + c |= s[i] ^ 0xff; + } + c = (((unsigned int) c) - 1U) >> 8; + d = (0xed - 1U - (unsigned int) s[0]) >> 8; + + return 1 - (c & d & 1); +} + +int +ge25519_has_small_order(const unsigned char s[32]) +{ + CRYPTO_ALIGN(16) + static const unsigned char blacklist[][32] = { + /* 0 (order 4) */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 1 (order 1) */ + { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 + (order 8) */ + { 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, + 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, + 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 }, + /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 + (order 8) */ + { 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, + 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, + 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a }, + /* p-1 (order 2) */ + { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p (=0, order 4) */ + { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + /* p+1 (=1, order 1) */ + { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f } + }; + unsigned char c[7] = { 0 }; + unsigned int k; + size_t i, j; + + COMPILER_ASSERT(7 == sizeof blacklist / sizeof blacklist[0]); + for (j = 0; j < 31; j++) { + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= s[j] ^ blacklist[i][j]; + } + } + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= (s[j] & 0x7f) ^ blacklist[i][j]; + } + k = 0; + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + k |= (c[i] - 1); + } + return (int) ((k >> 8) & 1); +} + +/* + Input: + a[0]+256*a[1]+...+256^31*a[31] = a + b[0]+256*b[1]+...+256^31*b[31] = b + c[0]+256*c[1]+...+256^31*c[31] = c + * + Output: + s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l + where l = 2^252 + 27742317777372353535851937790883648493. + */ + +void +sc25519_muladd(unsigned char *s, const unsigned char *a, + const unsigned char *b, const unsigned char *c) +{ + int64_t a0 = 2097151 & load_3(a); + int64_t a1 = 2097151 & (load_4(a + 2) >> 5); + int64_t a2 = 2097151 & (load_3(a + 5) >> 2); + int64_t a3 = 2097151 & (load_4(a + 7) >> 7); + int64_t a4 = 2097151 & (load_4(a + 10) >> 4); + int64_t a5 = 2097151 & (load_3(a + 13) >> 1); + int64_t a6 = 2097151 & (load_4(a + 15) >> 6); + int64_t a7 = 2097151 & (load_3(a + 18) >> 3); + int64_t a8 = 2097151 & load_3(a + 21); + int64_t a9 = 2097151 & (load_4(a + 23) >> 5); + int64_t a10 = 2097151 & (load_3(a + 26) >> 2); + int64_t a11 = (load_4(a + 28) >> 7); + + int64_t b0 = 2097151 & load_3(b); + int64_t b1 = 2097151 & (load_4(b + 2) >> 5); + int64_t b2 = 2097151 & (load_3(b + 5) >> 2); + int64_t b3 = 2097151 & (load_4(b + 7) >> 7); + int64_t b4 = 2097151 & (load_4(b + 10) >> 4); + int64_t b5 = 2097151 & (load_3(b + 13) >> 1); + int64_t b6 = 2097151 & (load_4(b + 15) >> 6); + int64_t b7 = 2097151 & (load_3(b + 18) >> 3); + int64_t b8 = 2097151 & load_3(b + 21); + int64_t b9 = 2097151 & (load_4(b + 23) >> 5); + int64_t b10 = 2097151 & (load_3(b + 26) >> 2); + int64_t b11 = (load_4(b + 28) >> 7); + + int64_t c0 = 2097151 & load_3(c); + int64_t c1 = 2097151 & (load_4(c + 2) >> 5); + int64_t c2 = 2097151 & (load_3(c + 5) >> 2); + int64_t c3 = 2097151 & (load_4(c + 7) >> 7); + int64_t c4 = 2097151 & (load_4(c + 10) >> 4); + int64_t c5 = 2097151 & (load_3(c + 13) >> 1); + int64_t c6 = 2097151 & (load_4(c + 15) >> 6); + int64_t c7 = 2097151 & (load_3(c + 18) >> 3); + int64_t c8 = 2097151 & load_3(c + 21); + int64_t c9 = 2097151 & (load_4(c + 23) >> 5); + int64_t c10 = 2097151 & (load_3(c + 26) >> 2); + int64_t c11 = (load_4(c + 28) >> 7); + + int64_t s0; + int64_t s1; + int64_t s2; + int64_t s3; + int64_t s4; + int64_t s5; + int64_t s6; + int64_t s7; + int64_t s8; + int64_t s9; + int64_t s10; + int64_t s11; + int64_t s12; + int64_t s13; + int64_t s14; + int64_t s15; + int64_t s16; + int64_t s17; + int64_t s18; + int64_t s19; + int64_t s20; + int64_t s21; + int64_t s22; + int64_t s23; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + int64_t carry17; + int64_t carry18; + int64_t carry19; + int64_t carry20; + int64_t carry21; + int64_t carry22; + + s0 = c0 + a0 * b0; + s1 = c1 + a0 * b1 + a1 * b0; + s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0; + s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; + s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; + s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; + s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + + a6 * b0; + s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + + a6 * b1 + a7 * b0; + s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + + a6 * b2 + a7 * b1 + a8 * b0; + s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; + s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0; + s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0; + s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1; + s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2; + s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + + a9 * b5 + a10 * b4 + a11 * b3; + s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + + a10 * b5 + a11 * b4; + s16 = + a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5; + s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6; + s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7; + s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8; + s20 = a9 * b11 + a10 * b10 + a11 * b9; + s21 = a10 * b11 + a11 * b10; + s22 = a11 * b11; + s23 = 0; + + carry0 = (s0 + (int64_t) (1L << 20)) >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry2 = (s2 + (int64_t) (1L << 20)) >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry4 = (s4 + (int64_t) (1L << 20)) >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry12 = (s12 + (int64_t) (1L << 20)) >> 21; + s13 += carry12; + s12 -= carry12 * ((uint64_t) 1L << 21); + carry14 = (s14 + (int64_t) (1L << 20)) >> 21; + s15 += carry14; + s14 -= carry14 * ((uint64_t) 1L << 21); + carry16 = (s16 + (int64_t) (1L << 20)) >> 21; + s17 += carry16; + s16 -= carry16 * ((uint64_t) 1L << 21); + carry18 = (s18 + (int64_t) (1L << 20)) >> 21; + s19 += carry18; + s18 -= carry18 * ((uint64_t) 1L << 21); + carry20 = (s20 + (int64_t) (1L << 20)) >> 21; + s21 += carry20; + s20 -= carry20 * ((uint64_t) 1L << 21); + carry22 = (s22 + (int64_t) (1L << 20)) >> 21; + s23 += carry22; + s22 -= carry22 * ((uint64_t) 1L << 21); + + carry1 = (s1 + (int64_t) (1L << 20)) >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry3 = (s3 + (int64_t) (1L << 20)) >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry5 = (s5 + (int64_t) (1L << 20)) >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + carry13 = (s13 + (int64_t) (1L << 20)) >> 21; + s14 += carry13; + s13 -= carry13 * ((uint64_t) 1L << 21); + carry15 = (s15 + (int64_t) (1L << 20)) >> 21; + s16 += carry15; + s15 -= carry15 * ((uint64_t) 1L << 21); + carry17 = (s17 + (int64_t) (1L << 20)) >> 21; + s18 += carry17; + s17 -= carry17 * ((uint64_t) 1L << 21); + carry19 = (s19 + (int64_t) (1L << 20)) >> 21; + s20 += carry19; + s19 -= carry19 * ((uint64_t) 1L << 21); + carry21 = (s21 + (int64_t) (1L << 20)) >> 21; + s22 += carry21; + s21 -= carry21 * ((uint64_t) 1L << 21); + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry12 = (s12 + (int64_t) (1L << 20)) >> 21; + s13 += carry12; + s12 -= carry12 * ((uint64_t) 1L << 21); + carry14 = (s14 + (int64_t) (1L << 20)) >> 21; + s15 += carry14; + s14 -= carry14 * ((uint64_t) 1L << 21); + carry16 = (s16 + (int64_t) (1L << 20)) >> 21; + s17 += carry16; + s16 -= carry16 * ((uint64_t) 1L << 21); + + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + carry13 = (s13 + (int64_t) (1L << 20)) >> 21; + s14 += carry13; + s13 -= carry13 * ((uint64_t) 1L << 21); + carry15 = (s15 + (int64_t) (1L << 20)) >> 21; + s16 += carry15; + s15 -= carry15 * ((uint64_t) 1L << 21); + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (int64_t) (1L << 20)) >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry2 = (s2 + (int64_t) (1L << 20)) >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry4 = (s4 + (int64_t) (1L << 20)) >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + carry1 = (s1 + (int64_t) (1L << 20)) >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry3 = (s3 + (int64_t) (1L << 20)) >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry5 = (s5 + (int64_t) (1L << 20)) >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry11 = s11 >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5)); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2)); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7)); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4)); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1)); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6)); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3)); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5)); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2)); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7)); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* + Input: + s[0]+256*s[1]+...+256^63*s[63] = s + * + Output: + s[0]+256*s[1]+...+256^31*s[31] = s mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. + */ + +void +sc25519_reduce(unsigned char *s) +{ + int64_t s0 = 2097151 & load_3(s); + int64_t s1 = 2097151 & (load_4(s + 2) >> 5); + int64_t s2 = 2097151 & (load_3(s + 5) >> 2); + int64_t s3 = 2097151 & (load_4(s + 7) >> 7); + int64_t s4 = 2097151 & (load_4(s + 10) >> 4); + int64_t s5 = 2097151 & (load_3(s + 13) >> 1); + int64_t s6 = 2097151 & (load_4(s + 15) >> 6); + int64_t s7 = 2097151 & (load_3(s + 18) >> 3); + int64_t s8 = 2097151 & load_3(s + 21); + int64_t s9 = 2097151 & (load_4(s + 23) >> 5); + int64_t s10 = 2097151 & (load_3(s + 26) >> 2); + int64_t s11 = 2097151 & (load_4(s + 28) >> 7); + int64_t s12 = 2097151 & (load_4(s + 31) >> 4); + int64_t s13 = 2097151 & (load_3(s + 34) >> 1); + int64_t s14 = 2097151 & (load_4(s + 36) >> 6); + int64_t s15 = 2097151 & (load_3(s + 39) >> 3); + int64_t s16 = 2097151 & load_3(s + 42); + int64_t s17 = 2097151 & (load_4(s + 44) >> 5); + int64_t s18 = 2097151 & (load_3(s + 47) >> 2); + int64_t s19 = 2097151 & (load_4(s + 49) >> 7); + int64_t s20 = 2097151 & (load_4(s + 52) >> 4); + int64_t s21 = 2097151 & (load_3(s + 55) >> 1); + int64_t s22 = 2097151 & (load_4(s + 57) >> 6); + int64_t s23 = (load_4(s + 60) >> 3); + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry12 = (s12 + (int64_t) (1L << 20)) >> 21; + s13 += carry12; + s12 -= carry12 * ((uint64_t) 1L << 21); + carry14 = (s14 + (int64_t) (1L << 20)) >> 21; + s15 += carry14; + s14 -= carry14 * ((uint64_t) 1L << 21); + carry16 = (s16 + (int64_t) (1L << 20)) >> 21; + s17 += carry16; + s16 -= carry16 * ((uint64_t) 1L << 21); + + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + carry13 = (s13 + (int64_t) (1L << 20)) >> 21; + s14 += carry13; + s13 -= carry13 * ((uint64_t) 1L << 21); + carry15 = (s15 + (int64_t) (1L << 20)) >> 21; + s16 += carry15; + s15 -= carry15 * ((uint64_t) 1L << 21); + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (int64_t) (1L << 20)) >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry2 = (s2 + (int64_t) (1L << 20)) >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry4 = (s4 + (int64_t) (1L << 20)) >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry6 = (s6 + (int64_t) (1L << 20)) >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry8 = (s8 + (int64_t) (1L << 20)) >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry10 = (s10 + (int64_t) (1L << 20)) >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + carry1 = (s1 + (int64_t) (1L << 20)) >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry3 = (s3 + (int64_t) (1L << 20)) >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry5 = (s5 + (int64_t) (1L << 20)) >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry7 = (s7 + (int64_t) (1L << 20)) >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry9 = (s9 + (int64_t) (1L << 20)) >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry11 = (s11 + (int64_t) (1L << 20)) >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + carry11 = s11 >> 21; + s12 += carry11; + s11 -= carry11 * ((uint64_t) 1L << 21); + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 * ((uint64_t) 1L << 21); + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 * ((uint64_t) 1L << 21); + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 * ((uint64_t) 1L << 21); + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 * ((uint64_t) 1L << 21); + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 * ((uint64_t) 1L << 21); + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 * ((uint64_t) 1L << 21); + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 * ((uint64_t) 1L << 21); + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 * ((uint64_t) 1L << 21); + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 * ((uint64_t) 1L << 21); + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 * ((uint64_t) 1L << 21); + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 * ((uint64_t) 1L << 21); + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5)); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2)); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7)); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4)); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1)); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6)); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3)); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5)); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2)); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7)); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +int +sc25519_is_canonical(const unsigned char *s) +{ + /* 2^252+27742317777372353535851937790883648493 */ + static const unsigned char L[32] = { + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, + 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 + }; + unsigned char c = 0; + unsigned char n = 1; + unsigned int i = 32; + + do { + i--; + c |= ((s[i] - L[i]) >> 8) & n; + n &= ((s[i] ^ L[i]) - 1) >> 8; + } while (i != 0); + + return (c != 0); +} + +static void +chi25519(fe25519 out, const fe25519 z) +{ + fe25519 t0, t1, t2, t3; + int i; + + fe25519_sq(t0, z); + fe25519_mul(t1, t0, z); + fe25519_sq(t0, t1); + fe25519_sq(t2, t0); + fe25519_sq(t2, t2); + fe25519_mul(t2, t2, t0); + fe25519_mul(t1, t2, z); + fe25519_sq(t2, t1); + + for (i = 1; i < 5; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t2, t1); + for (i = 1; i < 10; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t2, t2, t1); + fe25519_sq(t3, t2); + for (i = 1; i < 20; i++) { + fe25519_sq(t3, t3); + } + fe25519_mul(t2, t3, t2); + fe25519_sq(t2, t2); + for (i = 1; i < 10; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t2, t1); + for (i = 1; i < 50; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t2, t2, t1); + fe25519_sq(t3, t2); + for (i = 1; i < 100; i++) { + fe25519_sq(t3, t3); + } + fe25519_mul(t2, t3, t2); + fe25519_sq(t2, t2); + for (i = 1; i < 50; i++) { + fe25519_sq(t2, t2); + } + fe25519_mul(t1, t2, t1); + fe25519_sq(t1, t1); + for (i = 1; i < 4; i++) { + fe25519_sq(t1, t1); + } + fe25519_mul(out, t1, t0); +} + +void +ge25519_from_uniform(unsigned char s[32], const unsigned char r[32]) +{ + fe25519 e; + fe25519 negx; + fe25519 rr2; + fe25519 x, x2, x3; + ge25519_p3 p3; + ge25519_p1p1 p1; + ge25519_p2 p2; + unsigned int e_is_minus_1; + unsigned char x_sign; + + memcpy(s, r, 32); + x_sign = s[31] & 0x80; + s[31] &= 0x7f; + + fe25519_frombytes(rr2, s); + + /* elligator */ + fe25519_sq2(rr2, rr2); + rr2[0]++; + fe25519_invert(rr2, rr2); + fe25519_mul(x, curve25519_A, rr2); + fe25519_neg(x, x); + + fe25519_sq(x2, x); + fe25519_mul(x3, x, x2); + fe25519_add(e, x3, x); + fe25519_mul(x2, x2, curve25519_A); + fe25519_add(e, x2, e); + + chi25519(e, e); + + fe25519_tobytes(s, e); + e_is_minus_1 = s[1] & 1; + fe25519_neg(negx, x); + fe25519_cmov(x, negx, e_is_minus_1); + fe25519_0(x2); + fe25519_cmov(x2, curve25519_A, e_is_minus_1); + fe25519_sub(x, x, x2); + + /* yed = (x-1)/(x+1) */ + { + fe25519 one; + fe25519 x_plus_one; + fe25519 x_plus_one_inv; + fe25519 x_minus_one; + fe25519 yed; + + fe25519_1(one); + fe25519_add(x_plus_one, x, one); + fe25519_sub(x_minus_one, x, one); + fe25519_invert(x_plus_one_inv, x_plus_one); + fe25519_mul(yed, x_minus_one, x_plus_one_inv); + fe25519_tobytes(s, yed); + } + + /* recover x */ + s[31] |= x_sign; + if (ge25519_frombytes(&p3, s) != 0) { + abort(); /* LCOV_EXCL_LINE */ + } + + /* multiply by the cofactor */ + ge25519_p3_dbl(&p1, &p3); + ge25519_p1p1_to_p2(&p2, &p1); + ge25519_p2_dbl(&p1, &p2); + ge25519_p1p1_to_p2(&p2, &p1); + ge25519_p2_dbl(&p1, &p2); + ge25519_p1p1_to_p3(&p3, &p1); + + ge25519_p3_tobytes(s, &p3); +} diff --git a/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/base.h b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/base.h new file mode 100644 index 0000000000..e18530bbb1 --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/base.h @@ -0,0 +1,1344 @@ +{ /* 0/31 */ + { + { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, + { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, + { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 } + }, + { + { -12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303 }, + { -21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081 }, + { 26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697 } + }, + { + { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, + { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, + { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 } + }, + { + { -17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540 }, + { 23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397 }, + { 7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325 } + }, + { + { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, + { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, + { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 } + }, + { + { -15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777 }, + { -8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737 }, + { -18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652 } + }, + { + { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, + { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, + { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 } + }, + { + { 14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726 }, + { -7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955 }, + { 27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425 } + } +}, +{ /* 1/31 */ + { + { -13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171 }, + { 27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510 }, + { 17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660 } + }, + { + { -10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639 }, + { 29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963 }, + { 5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950 } + }, + { + { -27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568 }, + { 12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335 }, + { 25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628 } + }, + { + { -26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007 }, + { -2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772 }, + { -22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653 } + }, + { + { 2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567 }, + { 13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686 }, + { 21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372 } + }, + { + { -13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887 }, + { -23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954 }, + { -29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953 } + }, + { + { 24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833 }, + { -16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532 }, + { -22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876 } + }, + { + { 2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268 }, + { 33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214 }, + { 1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038 } + } +}, +{ /* 2/31 */ + { + { 6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800 }, + { 4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645 }, + { -4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664 } + }, + { + { 1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933 }, + { -25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182 }, + { -17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222 } + }, + { + { -18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991 }, + { 20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880 }, + { 9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092 } + }, + { + { -16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295 }, + { 19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788 }, + { 8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553 } + }, + { + { -15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026 }, + { 11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347 }, + { -18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033 } + }, + { + { -23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395 }, + { -27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278 }, + { 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890 } + }, + { + { 32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995 }, + { -30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596 }, + { -11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891 } + }, + { + { 31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060 }, + { 11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608 }, + { -20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606 } + } +}, +{ /* 3/31 */ + { + { 7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389 }, + { -19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016 }, + { -11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341 } + }, + { + { -22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505 }, + { 14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553 }, + { -28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655 } + }, + { + { 15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220 }, + { 12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631 }, + { -4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099 } + }, + { + { 26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556 }, + { 14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749 }, + { 236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930 } + }, + { + { 1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391 }, + { 5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253 }, + { 20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066 } + }, + { + { 24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958 }, + { -11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082 }, + { -28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383 } + }, + { + { -30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521 }, + { -11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807 }, + { 23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948 } + }, + { + { 9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134 }, + { -32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455 }, + { 27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629 } + } +}, +{ /* 4/31 */ + { + { -8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069 }, + { -32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746 }, + { 24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919 } + }, + { + { 11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837 }, + { 8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906 }, + { -28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771 } + }, + { + { -25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817 }, + { 10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098 }, + { 10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409 } + }, + { + { -12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504 }, + { -26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727 }, + { 28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420 } + }, + { + { -32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003 }, + { -1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605 }, + { -30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384 } + }, + { + { -26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701 }, + { -23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683 }, + { 29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708 } + }, + { + { -3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563 }, + { -19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260 }, + { -5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387 } + }, + { + { -19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672 }, + { 23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686 }, + { -24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665 } + } +}, +{ /* 5/31 */ + { + { 11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182 }, + { -31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277 }, + { 14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628 } + }, + { + { -4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474 }, + { -26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539 }, + { -25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822 } + }, + { + { -10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970 }, + { 19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756 }, + { -24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508 } + }, + { + { -26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683 }, + { -10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655 }, + { -20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158 } + }, + { + { -4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125 }, + { -15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839 }, + { -20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664 } + }, + { + { 27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294 }, + { -18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899 }, + { -11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070 } + }, + { + { 3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294 }, + { -15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949 }, + { -21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083 } + }, + { + { 31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420 }, + { -5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940 }, + { 29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396 } + } +}, +{ /* 6/31 */ + { + { -12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567 }, + { 20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127 }, + { -16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294 } + }, + { + { -12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887 }, + { 22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964 }, + { 16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195 } + }, + { + { 9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244 }, + { 24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999 }, + { -1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762 } + }, + { + { -18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274 }, + { -33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236 }, + { -16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605 } + }, + { + { -13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761 }, + { -22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884 }, + { -6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482 } + }, + { + { -24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638 }, + { -11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490 }, + { -32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170 } + }, + { + { 5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736 }, + { 10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124 }, + { -17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392 } + }, + { + { 8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029 }, + { 6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048 }, + { 28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958 } + } +}, +{ /* 7/31 */ + { + { 24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593 }, + { 26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071 }, + { -11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692 } + }, + { + { 11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687 }, + { -160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441 }, + { -20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001 } + }, + { + { -938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460 }, + { -19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007 }, + { -21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762 } + }, + { + { 15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005 }, + { -9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674 }, + { 4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035 } + }, + { + { 7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590 }, + { -2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957 }, + { -30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812 } + }, + { + { 33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740 }, + { -18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122 }, + { -27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158 } + }, + { + { 8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885 }, + { 26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140 }, + { 19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857 } + }, + { + { 801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155 }, + { 19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260 }, + { 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483 } + } +}, +{ /* 8/31 */ + { + { -3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677 }, + { 32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815 }, + { 22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751 } + }, + { + { -16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203 }, + { -11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208 }, + { 1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230 } + }, + { + { 16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850 }, + { -21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389 }, + { -9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968 } + }, + { + { -11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689 }, + { 14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880 }, + { 5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304 } + }, + { + { 30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632 }, + { -3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412 }, + { 20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566 } + }, + { + { -20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038 }, + { -26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232 }, + { -1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943 } + }, + { + { 17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856 }, + { 23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738 }, + { 15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971 } + }, + { + { -27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718 }, + { -13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697 }, + { -11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883 } + } +}, +{ /* 9/31 */ + { + { 5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912 }, + { -26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358 }, + { 3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849 } + }, + { + { 29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307 }, + { -14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977 }, + { -6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335 } + }, + { + { -29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644 }, + { -22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616 }, + { -27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735 } + }, + { + { -21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099 }, + { 29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341 }, + { -936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336 } + }, + { + { -23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646 }, + { 31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425 }, + { -17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388 } + }, + { + { -31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743 }, + { -16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822 }, + { -8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462 } + }, + { + { 18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985 }, + { 9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702 }, + { -22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797 } + }, + { + { 21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293 }, + { 27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100 }, + { 19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688 } + } +}, +{ /* 10/31 */ + { + { 12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186 }, + { 2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610 }, + { -2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707 } + }, + { + { 7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220 }, + { 915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025 }, + { 32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044 } + }, + { + { 32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992 }, + { -4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027 }, + { 21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197 } + }, + { + { 8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901 }, + { 31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952 }, + { 19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878 } + }, + { + { -28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390 }, + { 32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730 }, + { 2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730 } + }, + { + { -19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180 }, + { -30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272 }, + { -15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715 } + }, + { + { -22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970 }, + { -31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772 }, + { -17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865 } + }, + { + { 15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750 }, + { 20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373 }, + { 32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348 } + } +}, +{ /* 11/31 */ + { + { 9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144 }, + { -22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195 }, + { 5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086 } + }, + { + { -13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684 }, + { -8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518 }, + { -2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233 } + }, + { + { -5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793 }, + { -2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794 }, + { 580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435 } + }, + { + { 23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921 }, + { 13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518 }, + { 2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563 } + }, + { + { 14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278 }, + { -27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024 }, + { 4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030 } + }, + { + { 10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783 }, + { 27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717 }, + { 6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844 } + }, + { + { 14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333 }, + { 16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048 }, + { 22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760 } + }, + { + { -4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760 }, + { -15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757 }, + { -2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112 } + } +}, +{ /* 12/31 */ + { + { -19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468 }, + { 3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184 }, + { 10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289 } + }, + { + { 15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066 }, + { 24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882 }, + { 13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226 } + }, + { + { 16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101 }, + { 29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279 }, + { -6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811 } + }, + { + { 27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709 }, + { 20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714 }, + { -2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121 } + }, + { + { 9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464 }, + { 12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847 }, + { 13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400 } + }, + { + { 4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414 }, + { -15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158 }, + { 17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045 } + }, + { + { -461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415 }, + { -5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459 }, + { -31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079 } + }, + { + { 21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412 }, + { -20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743 }, + { -14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836 } + } +}, +{ /* 13/31 */ + { + { 12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022 }, + { 18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429 }, + { -6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065 } + }, + { + { 30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861 }, + { 10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000 }, + { -33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101 } + }, + { + { 32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815 }, + { 29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642 }, + { 10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966 } + }, + { + { 25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574 }, + { -21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742 }, + { -18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689 } + }, + { + { 12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020 }, + { -10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772 }, + { 3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982 } + }, + { + { -14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953 }, + { -16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218 }, + { -17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265 } + }, + { + { 29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073 }, + { -3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325 }, + { -11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798 } + }, + { + { -4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870 }, + { -7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863 }, + { -13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927 } + } +}, +{ /* 14/31 */ + { + { -2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267 }, + { -9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663 }, + { 22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862 } + }, + { + { -25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673 }, + { 15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943 }, + { 15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020 } + }, + { + { -4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238 }, + { 11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064 }, + { 14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795 } + }, + { + { 15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052 }, + { -10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904 }, + { 29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531 } + }, + { + { -13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979 }, + { -5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841 }, + { 10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431 } + }, + { + { 10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324 }, + { -31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940 }, + { 10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320 } + }, + { + { -15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184 }, + { 14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114 }, + { 30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878 } + }, + { + { 12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784 }, + { -2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091 }, + { -16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585 } + } +}, +{ /* 15/31 */ + { + { -8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208 }, + { 10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864 }, + { 17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661 } + }, + { + { 7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233 }, + { 26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212 }, + { -12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525 } + }, + { + { -24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068 }, + { 9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397 }, + { -8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988 } + }, + { + { 5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889 }, + { 32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038 }, + { 14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697 } + }, + { + { 20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875 }, + { -25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905 }, + { -25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656 } + }, + { + { 11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818 }, + { 27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714 }, + { 10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203 } + }, + { + { 20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931 }, + { -30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024 }, + { -23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084 } + }, + { + { -1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204 }, + { 20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817 }, + { 27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667 } + } +}, +{ /* 16/31 */ + { + { 11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504 }, + { -12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768 }, + { -19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255 } + }, + { + { 6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790 }, + { 1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438 }, + { -22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333 } + }, + { + { 17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971 }, + { 31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905 }, + { 29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409 } + }, + { + { 12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409 }, + { 6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499 }, + { -8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363 } + }, + { + { 28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664 }, + { -11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324 }, + { -21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940 } + }, + { + { 13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990 }, + { -17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914 }, + { -25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290 } + }, + { + { 24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257 }, + { -6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433 }, + { -16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236 } + }, + { + { -12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045 }, + { 11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093 }, + { -1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347 } + } +}, +{ /* 17/31 */ + { + { -28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191 }, + { -15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507 }, + { -12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906 } + }, + { + { 3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018 }, + { -16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109 }, + { -23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926 } + }, + { + { -24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528 }, + { 8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625 }, + { -32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286 } + }, + { + { 2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033 }, + { 27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866 }, + { 21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896 } + }, + { + { 30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075 }, + { 26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347 }, + { -22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437 } + }, + { + { -5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165 }, + { -18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588 }, + { -32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193 } + }, + { + { -19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017 }, + { -28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883 }, + { 21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961 } + }, + { + { 8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043 }, + { 29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663 }, + { -20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362 } + } +}, +{ /* 18/31 */ + { + { -33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860 }, + { 2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466 }, + { -24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063 } + }, + { + { -26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997 }, + { -1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295 }, + { -13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369 } + }, + { + { 9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385 }, + { 18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109 }, + { 2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906 } + }, + { + { 4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424 }, + { -19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185 }, + { 7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962 } + }, + { + { -7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325 }, + { 10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593 }, + { 696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404 } + }, + { + { -11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644 }, + { 17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801 }, + { 26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804 } + }, + { + { -31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884 }, + { -586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577 }, + { -9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849 } + }, + { + { 32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473 }, + { -8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644 }, + { -2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319 } + } +}, +{ /* 19/31 */ + { + { -11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599 }, + { -9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768 }, + { -27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084 } + }, + { + { -27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328 }, + { -15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369 }, + { 20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920 } + }, + { + { 12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815 }, + { -32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025 }, + { -21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397 } + }, + { + { -20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448 }, + { 6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981 }, + { 30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165 } + }, + { + { 32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501 }, + { 17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073 }, + { -1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861 } + }, + { + { 14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845 }, + { -1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211 }, + { 18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870 } + }, + { + { 10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096 }, + { 33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803 }, + { -32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168 } + }, + { + { 30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965 }, + { -14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505 }, + { 18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598 } + } +}, +{ /* 20/31 */ + { + { 5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782 }, + { 5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900 }, + { -31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479 } + }, + { + { -12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208 }, + { 8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232 }, + { 17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719 } + }, + { + { 16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271 }, + { -4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326 }, + { -8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132 } + }, + { + { 14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300 }, + { 8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570 }, + { 15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670 } + }, + { + { -2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994 }, + { -12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913 }, + { 31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317 } + }, + { + { -25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730 }, + { 842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096 }, + { -4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078 } + }, + { + { -15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411 }, + { -19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905 }, + { -9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654 } + }, + { + { -28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870 }, + { -23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498 }, + { 12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579 } + } +}, +{ /* 21/31 */ + { + { 14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677 }, + { 10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647 }, + { -2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743 } + }, + { + { -25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468 }, + { 21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375 }, + { -25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155 } + }, + { + { 6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725 }, + { -12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612 }, + { -10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943 } + }, + { + { -30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944 }, + { 30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928 }, + { 9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406 } + }, + { + { 22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139 }, + { -8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963 }, + { -31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693 } + }, + { + { 1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734 }, + { -448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680 }, + { -24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410 } + }, + { + { -9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931 }, + { -16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654 }, + { 22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710 } + }, + { + { 29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180 }, + { -26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684 }, + { -10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895 } + } +}, +{ /* 22/31 */ + { + { 22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501 }, + { -11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413 }, + { 6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880 } + }, + { + { -8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874 }, + { 22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962 }, + { -7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899 } + }, + { + { 21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152 }, + { 9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063 }, + { 7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080 } + }, + { + { -9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146 }, + { -17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183 }, + { -19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133 } + }, + { + { -32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421 }, + { -3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622 }, + { -4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197 } + }, + { + { 2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663 }, + { 31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753 }, + { 4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755 } + }, + { + { -9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862 }, + { -26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118 }, + { 26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171 } + }, + { + { 15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380 }, + { 16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824 }, + { 28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270 } + } +}, +{ /* 23/31 */ + { + { -817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438 }, + { -31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584 }, + { -594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562 } + }, + { + { 30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471 }, + { 18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610 }, + { 19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269 } + }, + { + { -30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650 }, + { 14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369 }, + { 19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461 } + }, + { + { 30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462 }, + { -5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793 }, + { -2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218 } + }, + { + { -24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226 }, + { 18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019 }, + { -15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037 } + }, + { + { 31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171 }, + { -17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132 }, + { -28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841 } + }, + { + { 21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181 }, + { -33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210 }, + { -1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040 } + }, + { + { 3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935 }, + { 24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105 }, + { -28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814 } + } +}, +{ /* 24/31 */ + { + { 793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852 }, + { 5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581 }, + { -4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646 } + }, + { + { 10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844 }, + { 10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025 }, + { 27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453 } + }, + { + { -23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068 }, + { 4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192 }, + { -17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921 } + }, + { + { -9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259 }, + { -12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426 }, + { -5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072 } + }, + { + { -17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305 }, + { 13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832 }, + { 28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943 } + }, + { + { -16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011 }, + { 24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447 }, + { 17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494 } + }, + { + { -28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245 }, + { -20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859 }, + { 28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915 } + }, + { + { 16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707 }, + { 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848 }, + { -11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224 } + } +}, +{ /* 25/31 */ + { + { -25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391 }, + { 15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215 }, + { -23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101 } + }, + { + { 23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713 }, + { 21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849 }, + { -7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930 } + }, + { + { -29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940 }, + { -21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031 }, + { -17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404 } + }, + { + { -25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243 }, + { -23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116 }, + { -24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525 } + }, + { + { -23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509 }, + { -10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883 }, + { 15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865 } + }, + { + { -3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660 }, + { 4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273 }, + { -28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138 } + }, + { + { -25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560 }, + { -10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135 }, + { 2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941 } + }, + { + { -4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739 }, + { 18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756 }, + { -30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819 } + } +}, +{ /* 26/31 */ + { + { -6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347 }, + { -27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028 }, + { 21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075 } + }, + { + { 16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799 }, + { -2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609 }, + { -25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817 } + }, + { + { -23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989 }, + { -30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523 }, + { 4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278 } + }, + { + { 31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045 }, + { 19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377 }, + { 24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480 } + }, + { + { 17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016 }, + { 510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426 }, + { 18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525 } + }, + { + { 13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396 }, + { 9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080 }, + { 12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892 } + }, + { + { 15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275 }, + { 11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074 }, + { 20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140 } + }, + { + { -16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717 }, + { -1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101 }, + { 24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127 } + } +}, +{ /* 27/31 */ + { + { -12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632 }, + { -26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415 }, + { -31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160 } + }, + { + { 31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876 }, + { 22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625 }, + { -15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478 } + }, + { + { 27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164 }, + { 26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595 }, + { -7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248 } + }, + { + { -16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858 }, + { 15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193 }, + { 8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184 } + }, + { + { -18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942 }, + { -1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635 }, + { 21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948 } + }, + { + { 11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935 }, + { -25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415 }, + { -15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416 } + }, + { + { -7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018 }, + { 4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778 }, + { 366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659 } + }, + { + { -24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385 }, + { 18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503 }, + { 476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329 } + } +}, +{ /* 28/31 */ + { + { 20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056 }, + { -13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838 }, + { 24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948 } + }, + { + { -3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691 }, + { -15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118 }, + { -23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517 } + }, + { + { -20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269 }, + { -6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904 }, + { -23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589 } + }, + { + { -28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193 }, + { -7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910 }, + { -30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930 } + }, + { + { -7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667 }, + { 25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481 }, + { -9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876 } + }, + { + { 22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640 }, + { -8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278 }, + { -21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112 } + }, + { + { 26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272 }, + { 17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012 }, + { -10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221 } + }, + { + { 30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046 }, + { 13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345 }, + { -19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310 } + } +}, +{ /* 29/31 */ + { + { 19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937 }, + { 31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636 }, + { -9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008 } + }, + { + { -2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429 }, + { -15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576 }, + { 31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066 } + }, + { + { -9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490 }, + { -12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104 }, + { 33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053 } + }, + { + { 31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275 }, + { -20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511 }, + { 22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095 } + }, + { + { -28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439 }, + { 23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939 }, + { -23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424 } + }, + { + { 2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310 }, + { 3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608 }, + { -32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079 } + }, + { + { -23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101 }, + { 21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418 }, + { 18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576 } + }, + { + { 30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356 }, + { 9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996 }, + { -26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099 } + } +}, +{ /* 30/31 */ + { + { -26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728 }, + { -13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658 }, + { -10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242 } + }, + { + { -21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001 }, + { -4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766 }, + { 18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373 } + }, + { + { 26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458 }, + { -17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628 }, + { -13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657 } + }, + { + { -23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062 }, + { 25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616 }, + { 31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014 } + }, + { + { 24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383 }, + { -25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814 }, + { -20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718 } + }, + { + { 30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417 }, + { 2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222 }, + { 33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444 } + }, + { + { -20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597 }, + { 23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970 }, + { 1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799 } + }, + { + { -5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647 }, + { 13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511 }, + { -29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032 } + } +}, +{ /* 31/31 */ + { + { 9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834 }, + { -23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461 }, + { 29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062 } + }, + { + { -25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516 }, + { -20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547 }, + { -24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240 } + }, + { + { -17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038 }, + { -33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741 }, + { 16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103 } + }, + { + { -19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747 }, + { -1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323 }, + { 31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016 } + }, + { + { -14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373 }, + { 15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228 }, + { -2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141 } + }, + { + { 16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399 }, + { 11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831 }, + { -185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376 } + }, + { + { -32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313 }, + { -18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958 }, + { -6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577 } + }, + { + { -22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743 }, + { 29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684 }, + { -20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476 } + } +} diff --git a/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/base2.h b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/base2.h new file mode 100644 index 0000000000..90a1457eab --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/base2.h @@ -0,0 +1,40 @@ +{ + { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, + { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, + { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 } +}, +{ + { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, + { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, + { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 } +}, +{ + { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, + { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, + { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 } +}, +{ + { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, + { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, + { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 } +}, +{ + { -22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877 }, + { -6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951 }, + { 4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784 } +}, +{ + { -25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436 }, + { 25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918 }, + { 23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877 } +}, +{ + { -33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800 }, + { -25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305 }, + { -13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300 } +}, +{ + { -3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876 }, + { -24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619 }, + { -3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683 } +} diff --git a/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/constants.h b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/constants.h new file mode 100644 index 0000000000..3dc9156a31 --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/constants.h @@ -0,0 +1,20 @@ +/* 37095705934669439343138083508754565189542113879843219016388785533085940283555 */ +static const fe25519 d = { + -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116 +}; + +/* 2 * d = + * 16295367250680780974490674513165176452449235426866156013048779062215315747161 + */ +static const fe25519 d2 = { + -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199 }; + +/* sqrt(-1) */ +static const fe25519 sqrtm1 = { + -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482 +}; + +/* A = 486662 */ +static const fe25519 curve25519_A = { + 486662, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; diff --git a/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/fe.h b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/fe.h new file mode 100644 index 0000000000..f216669e4e --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_25_5/fe.h @@ -0,0 +1,220 @@ +/* + Ignores top bit of h. + */ + +void +fe25519_frombytes(fe25519 h, const unsigned char *s) +{ + int64_t h0 = load_4(s); + int64_t h1 = load_3(s + 4) << 6; + int64_t h2 = load_3(s + 7) << 5; + int64_t h3 = load_3(s + 10) << 3; + int64_t h4 = load_3(s + 13) << 2; + int64_t h5 = load_4(s + 16); + int64_t h6 = load_3(s + 20) << 7; + int64_t h7 = load_3(s + 23) << 5; + int64_t h8 = load_3(s + 26) << 4; + int64_t h9 = (load_3(s + 29) & 8388607) << 2; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry9 = (h9 + (int64_t)(1L << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((uint64_t) 1L << 25); + carry1 = (h1 + (int64_t)(1L << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((uint64_t) 1L << 25); + carry3 = (h3 + (int64_t)(1L << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((uint64_t) 1L << 25); + carry5 = (h5 + (int64_t)(1L << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((uint64_t) 1L << 25); + carry7 = (h7 + (int64_t)(1L << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((uint64_t) 1L << 25); + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + carry2 = (h2 + (int64_t)(1L << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((uint64_t) 1L << 26); + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + carry6 = (h6 + (int64_t)(1L << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((uint64_t) 1L << 26); + carry8 = (h8 + (int64_t)(1L << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((uint64_t) 1L << 26); + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + +/* + Preconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + + Write p=2^255-19; q=floor(h/p). + Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + + Proof: + Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. + Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + + Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). + Then 0> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + carry0 = h0 >> 26; + h1 += carry0; + h0 -= carry0 * ((uint32_t) 1L << 26); + carry1 = h1 >> 25; + h2 += carry1; + h1 -= carry1 * ((uint32_t) 1L << 25); + carry2 = h2 >> 26; + h3 += carry2; + h2 -= carry2 * ((uint32_t) 1L << 26); + carry3 = h3 >> 25; + h4 += carry3; + h3 -= carry3 * ((uint32_t) 1L << 25); + carry4 = h4 >> 26; + h5 += carry4; + h4 -= carry4 * ((uint32_t) 1L << 26); + carry5 = h5 >> 25; + h6 += carry5; + h5 -= carry5 * ((uint32_t) 1L << 25); + carry6 = h6 >> 26; + h7 += carry6; + h6 -= carry6 * ((uint32_t) 1L << 26); + carry7 = h7 >> 25; + h8 += carry7; + h7 -= carry7 * ((uint32_t) 1L << 25); + carry8 = h8 >> 26; + h9 += carry8; + h8 -= carry8 * ((uint32_t) 1L << 26); + carry9 = h9 >> 25; + h9 -= carry9 * ((uint32_t) 1L << 25); + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* + Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + Have h0+...+2^230 h9 between 0 and 2^255-1; + evidently 2^255 h10-2^255 q = 0. + + Goal: Output h0+...+2^230 h9. + */ + +void +fe25519_tobytes(unsigned char *s, const fe25519 h) +{ + fe25519 t; + + fe25519_reduce(t, h); + s[0] = t[0] >> 0; + s[1] = t[0] >> 8; + s[2] = t[0] >> 16; + s[3] = (t[0] >> 24) | (t[1] * ((uint32_t) 1 << 2)); + s[4] = t[1] >> 6; + s[5] = t[1] >> 14; + s[6] = (t[1] >> 22) | (t[2] * ((uint32_t) 1 << 3)); + s[7] = t[2] >> 5; + s[8] = t[2] >> 13; + s[9] = (t[2] >> 21) | (t[3] * ((uint32_t) 1 << 5)); + s[10] = t[3] >> 3; + s[11] = t[3] >> 11; + s[12] = (t[3] >> 19) | (t[4] * ((uint32_t) 1 << 6)); + s[13] = t[4] >> 2; + s[14] = t[4] >> 10; + s[15] = t[4] >> 18; + s[16] = t[5] >> 0; + s[17] = t[5] >> 8; + s[18] = t[5] >> 16; + s[19] = (t[5] >> 24) | (t[6] * ((uint32_t) 1 << 1)); + s[20] = t[6] >> 7; + s[21] = t[6] >> 15; + s[22] = (t[6] >> 23) | (t[7] * ((uint32_t) 1 << 3)); + s[23] = t[7] >> 5; + s[24] = t[7] >> 13; + s[25] = (t[7] >> 21) | (t[8] * ((uint32_t) 1 << 4)); + s[26] = t[8] >> 4; + s[27] = t[8] >> 12; + s[28] = (t[8] >> 20) | (t[9] * ((uint32_t) 1 << 6)); + s[29] = t[9] >> 2; + s[30] = t[9] >> 10; + s[31] = t[9] >> 18; +} diff --git a/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/base.h b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/base.h new file mode 100644 index 0000000000..6b3b833e7a --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/base.h @@ -0,0 +1,1344 @@ +{ /* 0/31 */ + { + { 1288382639258501, 245678601348599, 269427782077623, 1462984067271730, 137412439391563 }, + { 62697248952638, 204681361388450, 631292143396476, 338455783676468, 1213667448819585 }, + { 301289933810280, 1259582250014073, 1422107436869536, 796239922652654, 1953934009299142 } + }, + { + { 1380971894829527, 790832306631236, 2067202295274102, 1995808275510000, 1566530869037010 }, + { 463307831301544, 432984605774163, 1610641361907204, 750899048855000, 1894842303421586 }, + { 748439484463711, 1033211726465151, 1396005112841647, 1611506220286469, 1972177495910992 } + }, + { + { 1601611775252272, 1720807796594148, 1132070835939856, 1260455018889551, 2147779492816911 }, + { 316559037616741, 2177824224946892, 1459442586438991, 1461528397712656, 751590696113597 }, + { 1850748884277385, 1200145853858453, 1068094770532492, 672251375690438, 1586055907191707 } + }, + { + { 934282339813791, 1846903124198670, 1172395437954843, 1007037127761661, 1830588347719256 }, + { 1694390458783935, 1735906047636159, 705069562067493, 648033061693059, 696214010414170 }, + { 1121406372216585, 192876649532226, 190294192191717, 1994165897297032, 2245000007398739 } + }, + { + { 769950342298419, 132954430919746, 844085933195555, 974092374476333, 726076285546016 }, + { 425251763115706, 608463272472562, 442562545713235, 837766094556764, 374555092627893 }, + { 1086255230780037, 274979815921559, 1960002765731872, 929474102396301, 1190409889297339 } + }, + { + { 1388594989461809, 316767091099457, 394298842192982, 1230079486801005, 1440737038838979 }, + { 7380825640100, 146210432690483, 304903576448906, 1198869323871120, 997689833219095 }, + { 1181317918772081, 114573476638901, 262805072233344, 265712217171332, 294181933805782 } + }, + { + { 665000864555967, 2065379846933859, 370231110385876, 350988370788628, 1233371373142985 }, + { 2019367628972465, 676711900706637, 110710997811333, 1108646842542025, 517791959672113 }, + { 965130719900578, 247011430587952, 526356006571389, 91986625355052, 2157223321444601 } + }, + { + { 2068619540119183, 1966274918058806, 957728544705549, 729906502578991, 159834893065166 }, + { 2073601412052185, 31021124762708, 264500969797082, 248034690651703, 1030252227928288 }, + { 551790716293402, 1989538725166328, 801169423371717, 2052451893578887, 678432056995012 } + } +}, +{ /* 1/31 */ + { + { 1368953770187805, 790347636712921, 437508475667162, 2142576377050580, 1932081720066286 }, + { 953638594433374, 1092333936795051, 1419774766716690, 805677984380077, 859228993502513 }, + { 1200766035879111, 20142053207432, 1465634435977050, 1645256912097844, 295121984874596 } + }, + { + { 1735718747031557, 1248237894295956, 1204753118328107, 976066523550493, 65943769534592 }, + { 1060098822528990, 1586825862073490, 212301317240126, 1975302711403555, 666724059764335 }, + { 1091990273418756, 1572899409348578, 80968014455247, 306009358661350, 1520450739132526 } + }, + { + { 1480517209436112, 1511153322193952, 1244343858991172, 304788150493241, 369136856496443 }, + { 2151330273626164, 762045184746182, 1688074332551515, 823046109005759, 907602769079491 }, + { 2047386910586836, 168470092900250, 1552838872594810, 340951180073789, 360819374702533 } + }, + { + { 1982622644432056, 2014393600336956, 128909208804214, 1617792623929191, 105294281913815 }, + { 980234343912898, 1712256739246056, 588935272190264, 204298813091998, 841798321043288 }, + { 197561292938973, 454817274782871, 1963754960082318, 2113372252160468, 971377527342673 } + }, + { + { 164699448829328, 3127451757672, 1199504971548753, 1766155447043652, 1899238924683527 }, + { 732262946680281, 1674412764227063, 2182456405662809, 1350894754474250, 558458873295247 }, + { 2103305098582922, 1960809151316468, 715134605001343, 1454892949167181, 40827143824949 } + }, + { + { 1239289043050212, 1744654158124578, 758702410031698, 1796762995074688, 1603056663766 }, + { 2232056027107988, 987343914584615, 2115594492994461, 1819598072792159, 1119305654014850 }, + { 320153677847348, 939613871605645, 641883205761567, 1930009789398224, 329165806634126 } + }, + { + { 980930490474130, 1242488692177893, 1251446316964684, 1086618677993530, 1961430968465772 }, + { 276821765317453, 1536835591188030, 1305212741412361, 61473904210175, 2051377036983058 }, + { 833449923882501, 1750270368490475, 1123347002068295, 185477424765687, 278090826653186 } + }, + { + { 794524995833413, 1849907304548286, 53348672473145, 1272368559505217, 1147304168324779 }, + { 1504846112759364, 1203096289004681, 562139421471418, 274333017451844, 1284344053775441 }, + { 483048732424432, 2116063063343382, 30120189902313, 292451576741007, 1156379271702225 } + } +}, +{ /* 2/31 */ + { + { 928372153029038, 2147692869914564, 1455665844462196, 1986737809425946, 185207050258089 }, + { 137732961814206, 706670923917341, 1387038086865771, 1965643813686352, 1384777115696347 }, + { 481144981981577, 2053319313589856, 2065402289827512, 617954271490316, 1106602634668125 } + }, + { + { 696298019648792, 893299659040895, 1148636718636009, 26734077349617, 2203955659340681 }, + { 657390353372855, 998499966885562, 991893336905797, 810470207106761, 343139804608786 }, + { 791736669492960, 934767652997115, 824656780392914, 1759463253018643, 361530362383518 } + }, + { + { 2022541353055597, 2094700262587466, 1551008075025686, 242785517418164, 695985404963562 }, + { 1287487199965223, 2215311941380308, 1552928390931986, 1664859529680196, 1125004975265243 }, + { 677434665154918, 989582503122485, 1817429540898386, 1052904935475344, 1143826298169798 } + }, + { + { 367266328308408, 318431188922404, 695629353755355, 634085657580832, 24581612564426 }, + { 773360688841258, 1815381330538070, 363773437667376, 539629987070205, 783280434248437 }, + { 180820816194166, 168937968377394, 748416242794470, 1227281252254508, 1567587861004268 } + }, + { + { 478775558583645, 2062896624554807, 699391259285399, 358099408427873, 1277310261461761 }, + { 1984740906540026, 1079164179400229, 1056021349262661, 1659958556483663, 1088529069025527 }, + { 580736401511151, 1842931091388998, 1177201471228238, 2075460256527244, 1301133425678027 } + }, + { + { 1515728832059182, 1575261009617579, 1510246567196186, 191078022609704, 116661716289141 }, + { 1295295738269652, 1714742313707026, 545583042462581, 2034411676262552, 1513248090013606 }, + { 230710545179830, 30821514358353, 760704303452229, 390668103790604, 573437871383156 } + }, + { + { 1169380107545646, 263167233745614, 2022901299054448, 819900753251120, 2023898464874585 }, + { 2102254323485823, 1570832666216754, 34696906544624, 1993213739807337, 70638552271463 }, + { 894132856735058, 548675863558441, 845349339503395, 1942269668326667, 1615682209874691 } + }, + { + { 1287670217537834, 1222355136884920, 1846481788678694, 1150426571265110, 1613523400722047 }, + { 793388516527298, 1315457083650035, 1972286999342417, 1901825953052455, 338269477222410 }, + { 550201530671806, 778605267108140, 2063911101902983, 115500557286349, 2041641272971022 } + } +}, +{ /* 3/31 */ + { + { 717255318455100, 519313764361315, 2080406977303708, 541981206705521, 774328150311600 }, + { 261715221532238, 1795354330069993, 1496878026850283, 499739720521052, 389031152673770 }, + { 1997217696294013, 1717306351628065, 1684313917746180, 1644426076011410, 1857378133465451 } + }, + { + { 1475434724792648, 76931896285979, 1116729029771667, 2002544139318042, 725547833803938 }, + { 2022306639183567, 726296063571875, 315345054448644, 1058733329149221, 1448201136060677 }, + { 1710065158525665, 1895094923036397, 123988286168546, 1145519900776355, 1607510767693874 } + }, + { + { 561605375422540, 1071733543815037, 131496498800990, 1946868434569999, 828138133964203 }, + { 1548495173745801, 442310529226540, 998072547000384, 553054358385281, 644824326376171 }, + { 1445526537029440, 2225519789662536, 914628859347385, 1064754194555068, 1660295614401091 } + }, + { + { 1199690223111956, 24028135822341, 66638289244341, 57626156285975, 565093967979607 }, + { 876926774220824, 554618976488214, 1012056309841565, 839961821554611, 1414499340307677 }, + { 703047626104145, 1266841406201770, 165556500219173, 486991595001879, 1011325891650656 } + }, + { + { 1622861044480487, 1156394801573634, 1869132565415504, 327103985777730, 2095342781472284 }, + { 334886927423922, 489511099221528, 129160865966726, 1720809113143481, 619700195649254 }, + { 1646545795166119, 1758370782583567, 714746174550637, 1472693650165135, 898994790308209 } + }, + { + { 333403773039279, 295772542452938, 1693106465353610, 912330357530760, 471235657950362 }, + { 1811196219982022, 1068969825533602, 289602974833439, 1988956043611592, 863562343398367 }, + { 906282429780072, 2108672665779781, 432396390473936, 150625823801893, 1708930497638539 } + }, + { + { 925664675702328, 21416848568684, 1831436641861340, 601157008940113, 371818055044496 }, + { 1479786007267725, 1738881859066675, 68646196476567, 2146507056100328, 1247662817535471 }, + { 52035296774456, 939969390708103, 312023458773250, 59873523517659, 1231345905848899 } + }, + { + { 643355106415761, 290186807495774, 2013561737429023, 319648069511546, 393736678496162 }, + { 129358342392716, 1932811617704777, 1176749390799681, 398040349861790, 1170779668090425 }, + { 2051980782668029, 121859921510665, 2048329875753063, 1235229850149665, 519062146124755 } + } +}, +{ /* 4/31 */ + { + { 1608170971973096, 415809060360428, 1350468408164766, 2038620059057678, 1026904485989112 }, + { 1837656083115103, 1510134048812070, 906263674192061, 1821064197805734, 565375124676301 }, + { 578027192365650, 2034800251375322, 2128954087207123, 478816193810521, 2196171989962750 } + }, + { + { 1633188840273139, 852787172373708, 1548762607215796, 1266275218902681, 1107218203325133 }, + { 462189358480054, 1784816734159228, 1611334301651368, 1303938263943540, 707589560319424 }, + { 1038829280972848, 38176604650029, 753193246598573, 1136076426528122, 595709990562434 } + }, + { + { 1408451820859834, 2194984964010833, 2198361797561729, 1061962440055713, 1645147963442934 }, + { 4701053362120, 1647641066302348, 1047553002242085, 1923635013395977, 206970314902065 }, + { 1750479161778571, 1362553355169293, 1891721260220598, 966109370862782, 1024913988299801 } + }, + { + { 212699049131723, 1117950018299775, 1873945661751056, 1403802921984058, 130896082652698 }, + { 636808533673210, 1262201711667560, 390951380330599, 1663420692697294, 561951321757406 }, + { 520731594438141, 1446301499955692, 273753264629267, 1565101517999256, 1019411827004672 } + }, + { + { 926527492029409, 1191853477411379, 734233225181171, 184038887541270, 1790426146325343 }, + { 1464651961852572, 1483737295721717, 1519450561335517, 1161429831763785, 405914998179977 }, + { 996126634382301, 796204125879525, 127517800546509, 344155944689303, 615279846169038 } + }, + { + { 738724080975276, 2188666632415296, 1961313708559162, 1506545807547587, 1151301638969740 }, + { 622917337413835, 1218989177089035, 1284857712846592, 970502061709359, 351025208117090 }, + { 2067814584765580, 1677855129927492, 2086109782475197, 235286517313238, 1416314046739645 } + }, + { + { 586844262630358, 307444381952195, 458399356043426, 602068024507062, 1028548203415243 }, + { 678489922928203, 2016657584724032, 90977383049628, 1026831907234582, 615271492942522 }, + { 301225714012278, 1094837270268560, 1202288391010439, 644352775178361, 1647055902137983 } + }, + { + { 1210746697896478, 1416608304244708, 686487477217856, 1245131191434135, 1051238336855737 }, + { 1135604073198207, 1683322080485474, 769147804376683, 2086688130589414, 900445683120379 }, + { 1971518477615628, 401909519527336, 448627091057375, 1409486868273821, 1214789035034363 } + } +}, +{ /* 5/31 */ + { + { 1364039144731711, 1897497433586190, 2203097701135459, 145461396811251, 1349844460790699 }, + { 1045230323257973, 818206601145807, 630513189076103, 1672046528998132, 807204017562437 }, + { 439961968385997, 386362664488986, 1382706320807688, 309894000125359, 2207801346498567 } + }, + { + { 1229004686397588, 920643968530863, 123975893911178, 681423993215777, 1400559197080973 }, + { 2003766096898049, 170074059235165, 1141124258967971, 1485419893480973, 1573762821028725 }, + { 729905708611432, 1270323270673202, 123353058984288, 426460209632942, 2195574535456672 } + }, + { + { 1271140255321235, 2044363183174497, 52125387634689, 1445120246694705, 942541986339084 }, + { 1761608437466135, 583360847526804, 1586706389685493, 2157056599579261, 1170692369685772 }, + { 871476219910823, 1878769545097794, 2241832391238412, 548957640601001, 690047440233174 } + }, + { + { 297194732135507, 1366347803776820, 1301185512245601, 561849853336294, 1533554921345731 }, + { 999628998628371, 1132836708493400, 2084741674517453, 469343353015612, 678782988708035 }, + { 2189427607417022, 699801937082607, 412764402319267, 1478091893643349, 2244675696854460 } + }, + { + { 1712292055966563, 204413590624874, 1405738637332841, 408981300829763, 861082219276721 }, + { 508561155940631, 966928475686665, 2236717801150132, 424543858577297, 2089272956986143 }, + { 221245220129925, 1156020201681217, 491145634799213, 542422431960839, 828100817819207 } + }, + { + { 153756971240384, 1299874139923977, 393099165260502, 1058234455773022, 996989038681183 }, + { 559086812798481, 573177704212711, 1629737083816402, 1399819713462595, 1646954378266038 }, + { 1887963056288059, 228507035730124, 1468368348640282, 930557653420194, 613513962454686 } + }, + { + { 1224529808187553, 1577022856702685, 2206946542980843, 625883007765001, 279930793512158 }, + { 1076287717051609, 1114455570543035, 187297059715481, 250446884292121, 1885187512550540 }, + { 902497362940219, 76749815795675, 1657927525633846, 1420238379745202, 1340321636548352 } + }, + { + { 1129576631190784, 1281994010027327, 996844254743018, 257876363489249, 1150850742055018 }, + { 628740660038789, 1943038498527841, 467786347793886, 1093341428303375, 235413859513003 }, + { 237425418909360, 469614029179605, 1512389769174935, 1241726368345357, 441602891065214 } + } +}, +{ /* 6/31 */ + { + { 1736417953058555, 726531315520508, 1833335034432527, 1629442561574747, 624418919286085 }, + { 1960754663920689, 497040957888962, 1909832851283095, 1271432136996826, 2219780368020940 }, + { 1537037379417136, 1358865369268262, 2130838645654099, 828733687040705, 1999987652890901 } + }, + { + { 629042105241814, 1098854999137608, 887281544569320, 1423102019874777, 7911258951561 }, + { 1811562332665373, 1501882019007673, 2213763501088999, 359573079719636, 36370565049116 }, + { 218907117361280, 1209298913016966, 1944312619096112, 1130690631451061, 1342327389191701 } + }, + { + { 1369976867854704, 1396479602419169, 1765656654398856, 2203659200586299, 998327836117241 }, + { 2230701885562825, 1348173180338974, 2172856128624598, 1426538746123771, 444193481326151 }, + { 784210426627951, 918204562375674, 1284546780452985, 1324534636134684, 1872449409642708 } + }, + { + { 319638829540294, 596282656808406, 2037902696412608, 1557219121643918, 341938082688094 }, + { 1901860206695915, 2004489122065736, 1625847061568236, 973529743399879, 2075287685312905 }, + { 1371853944110545, 1042332820512553, 1949855697918254, 1791195775521505, 37487364849293 } + }, + { + { 687200189577855, 1082536651125675, 644224940871546, 340923196057951, 343581346747396 }, + { 2082717129583892, 27829425539422, 145655066671970, 1690527209845512, 1865260509673478 }, + { 1059729620568824, 2163709103470266, 1440302280256872, 1769143160546397, 869830310425069 } + }, + { + { 1609516219779025, 777277757338817, 2101121130363987, 550762194946473, 1905542338659364 }, + { 2024821921041576, 426948675450149, 595133284085473, 471860860885970, 600321679413000 }, + { 598474602406721, 1468128276358244, 1191923149557635, 1501376424093216, 1281662691293476 } + }, + { + { 1721138489890707, 1264336102277790, 433064545421287, 1359988423149466, 1561871293409447 }, + { 719520245587143, 393380711632345, 132350400863381, 1543271270810729, 1819543295798660 }, + { 396397949784152, 1811354474471839, 1362679985304303, 2117033964846756, 498041172552279 } + }, + { + { 1812471844975748, 1856491995543149, 126579494584102, 1036244859282620, 1975108050082550 }, + { 650623932407995, 1137551288410575, 2125223403615539, 1725658013221271, 2134892965117796 }, + { 522584000310195, 1241762481390450, 1743702789495384, 2227404127826575, 1686746002148897 } + } +}, +{ /* 7/31 */ + { + { 427904865186312, 1703211129693455, 1585368107547509, 1436984488744336, 761188534613978 }, + { 318101947455002, 248138407995851, 1481904195303927, 309278454311197, 1258516760217879 }, + { 1275068538599310, 513726919533379, 349926553492294, 688428871968420, 1702400196000666 } + }, + { + { 1061864036265233, 961611260325381, 321859632700838, 1045600629959517, 1985130202504038 }, + { 1558816436882417, 1962896332636523, 1337709822062152, 1501413830776938, 294436165831932 }, + { 818359826554971, 1862173000996177, 626821592884859, 573655738872376, 1749691246745455 } + }, + { + { 1988022651432119, 1082111498586040, 1834020786104821, 1454826876423687, 692929915223122 }, + { 2146513703733331, 584788900394667, 464965657279958, 2183973639356127, 238371159456790 }, + { 1129007025494441, 2197883144413266, 265142755578169, 971864464758890, 1983715884903702 } + }, + { + { 1291366624493075, 381456718189114, 1711482489312444, 1815233647702022, 892279782992467 }, + { 444548969917454, 1452286453853356, 2113731441506810, 645188273895859, 810317625309512 }, + { 2242724082797924, 1373354730327868, 1006520110883049, 2147330369940688, 1151816104883620 } + }, + { + { 1745720200383796, 1911723143175317, 2056329390702074, 355227174309849, 879232794371100 }, + { 163723479936298, 115424889803150, 1156016391581227, 1894942220753364, 1970549419986329 }, + { 681981452362484, 267208874112496, 1374683991933094, 638600984916117, 646178654558546 } + }, + { + { 13378654854251, 106237307029567, 1944412051589651, 1841976767925457, 230702819835573 }, + { 260683893467075, 854060306077237, 913639551980112, 4704576840123, 280254810808712 }, + { 715374893080287, 1173334812210491, 1806524662079626, 1894596008000979, 398905715033393 } + }, + { + { 500026409727661, 1596431288195371, 1420380351989370, 985211561521489, 392444930785633 }, + { 2096421546958141, 1922523000950363, 789831022876840, 427295144688779, 320923973161730 }, + { 1927770723575450, 1485792977512719, 1850996108474547, 551696031508956, 2126047405475647 } + }, + { + { 2112099158080148, 742570803909715, 6484558077432, 1951119898618916, 93090382703416 }, + { 383905201636970, 859946997631870, 855623867637644, 1017125780577795, 794250831877809 }, + { 77571826285752, 999304298101753, 487841111777762, 1038031143212339, 339066367948762 } + } +}, +{ /* 8/31 */ + { + { 674994775520533, 266035846330789, 826951213393478, 1405007746162285, 1781791018620876 }, + { 1001412661522686, 348196197067298, 1666614366723946, 888424995032760, 580747687801357 }, + { 1939560076207777, 1409892634407635, 552574736069277, 383854338280405, 190706709864139 } + }, + { + { 2177087163428741, 1439255351721944, 1208070840382793, 2230616362004769, 1396886392021913 }, + { 676962063230039, 1880275537148808, 2046721011602706, 888463247083003, 1318301552024067 }, + { 1466980508178206, 617045217998949, 652303580573628, 757303753529064, 207583137376902 } + }, + { + { 1511056752906902, 105403126891277, 493434892772846, 1091943425335976, 1802717338077427 }, + { 1853982405405128, 1878664056251147, 1528011020803992, 1019626468153565, 1128438412189035 }, + { 1963939888391106, 293456433791664, 697897559513649, 985882796904380, 796244541237972 } + }, + { + { 416770998629779, 389655552427054, 1314476859406756, 1749382513022778, 1161905598739491 }, + { 1428358296490651, 1027115282420478, 304840698058337, 441410174026628, 1819358356278573 }, + { 204943430200135, 1554861433819175, 216426658514651, 264149070665950, 2047097371738319 } + }, + { + { 1934415182909034, 1393285083565062, 516409331772960, 1157690734993892, 121039666594268 }, + { 662035583584445, 286736105093098, 1131773000510616, 818494214211439, 472943792054479 }, + { 665784778135882, 1893179629898606, 808313193813106, 276797254706413, 1563426179676396 } + }, + { + { 945205108984232, 526277562959295, 1324180513733566, 1666970227868664, 153547609289173 }, + { 2031433403516252, 203996615228162, 170487168837083, 981513604791390, 843573964916831 }, + { 1476570093962618, 838514669399805, 1857930577281364, 2017007352225784, 317085545220047 } + }, + { + { 1461557121912842, 1600674043318359, 2157134900399597, 1670641601940616, 127765583803283 }, + { 1293543509393474, 2143624609202546, 1058361566797508, 214097127393994, 946888515472729 }, + { 357067959932916, 1290876214345711, 521245575443703, 1494975468601005, 800942377643885 } + }, + { + { 566116659100033, 820247422481740, 994464017954148, 327157611686365, 92591318111744 }, + { 617256647603209, 1652107761099439, 1857213046645471, 1085597175214970, 817432759830522 }, + { 771808161440705, 1323510426395069, 680497615846440, 851580615547985, 1320806384849017 } + } +}, +{ /* 9/31 */ + { + { 1219260086131915, 647169006596815, 79601124759706, 2161724213426748, 404861897060198 }, + { 1327968293887866, 1335500852943256, 1401587164534264, 558137311952440, 1551360549268902 }, + { 417621685193956, 1429953819744454, 396157358457099, 1940470778873255, 214000046234152 } + }, + { + { 1268047918491973, 2172375426948536, 1533916099229249, 1761293575457130, 1590622667026765 }, + { 1627072914981959, 2211603081280073, 1912369601616504, 1191770436221309, 2187309757525860 }, + { 1149147819689533, 378692712667677, 828475842424202, 2218619146419342, 70688125792186 } + }, + { + { 1299739417079761, 1438616663452759, 1536729078504412, 2053896748919838, 1008421032591246 }, + { 2040723824657366, 399555637875075, 632543375452995, 872649937008051, 1235394727030233 }, + { 2211311599327900, 2139787259888175, 938706616835350, 12609661139114, 2081897930719789 } + }, + { + { 1324994503390450, 336982330582631, 1183998925654177, 1091654665913274, 48727673971319 }, + { 1845522914617879, 1222198248335542, 150841072760134, 1927029069940982, 1189913404498011 }, + { 1079559557592645, 2215338383666441, 1903569501302605, 49033973033940, 305703433934152 } + }, + { + { 94653405416909, 1386121349852999, 1062130477891762, 36553947479274, 833669648948846 }, + { 1432015813136298, 440364795295369, 1395647062821501, 1976874522764578, 934452372723352 }, + { 1296625309219774, 2068273464883862, 1858621048097805, 1492281814208508, 2235868981918946 } + }, + { + { 1490330266465570, 1858795661361448, 1436241134969763, 294573218899647, 1208140011028933 }, + { 1282462923712748, 741885683986255, 2027754642827561, 518989529541027, 1826610009555945 }, + { 1525827120027511, 723686461809551, 1597702369236987, 244802101764964, 1502833890372311 } + }, + { + { 113622036244513, 1233740067745854, 674109952278496, 2114345180342965, 166764512856263 }, + { 2041668749310338, 2184405322203901, 1633400637611036, 2110682505536899, 2048144390084644 }, + { 503058759232932, 760293024620937, 2027152777219493, 666858468148475, 1539184379870952 } + }, + { + { 1916168475367211, 915626432541343, 883217071712575, 363427871374304, 1976029821251593 }, + { 678039535434506, 570587290189340, 1605302676614120, 2147762562875701, 1706063797091704 }, + { 1439489648586438, 2194580753290951, 832380563557396, 561521973970522, 584497280718389 } + } +}, +{ /* 10/31 */ + { + { 187989455492609, 681223515948275, 1933493571072456, 1872921007304880, 488162364135671 }, + { 1413466089534451, 410844090765630, 1397263346404072, 408227143123410, 1594561803147811 }, + { 2102170800973153, 719462588665004, 1479649438510153, 1097529543970028, 1302363283777685 } + }, + { + { 942065717847195, 1069313679352961, 2007341951411051, 70973416446291, 1419433790163706 }, + { 1146565545556377, 1661971299445212, 406681704748893, 564452436406089, 1109109865829139 }, + { 2214421081775077, 1165671861210569, 1890453018796184, 3556249878661, 442116172656317 } + }, + { + { 753830546620811, 1666955059895019, 1530775289309243, 1119987029104146, 2164156153857580 }, + { 615171919212796, 1523849404854568, 854560460547503, 2067097370290715, 1765325848586042 }, + { 1094538949313667, 1796592198908825, 870221004284388, 2025558921863561, 1699010892802384 } + }, + { + { 1951351290725195, 1916457206844795, 198025184438026, 1909076887557595, 1938542290318919 }, + { 1014323197538413, 869150639940606, 1756009942696599, 1334952557375672, 1544945379082874 }, + { 764055910920305, 1603590757375439, 146805246592357, 1843313433854297, 954279890114939 } + }, + { + { 80113526615750, 764536758732259, 1055139345100233, 469252651759390, 617897512431515 }, + { 74497112547268, 740094153192149, 1745254631717581, 727713886503130, 1283034364416928 }, + { 525892105991110, 1723776830270342, 1476444848991936, 573789489857760, 133864092632978 } + }, + { + { 542611720192581, 1986812262899321, 1162535242465837, 481498966143464, 544600533583622 }, + { 64123227344372, 1239927720647794, 1360722983445904, 222610813654661, 62429487187991 }, + { 1793193323953132, 91096687857833, 70945970938921, 2158587638946380, 1537042406482111 } + }, + { + { 1895854577604609, 1394895708949416, 1728548428495944, 1140864900240149, 563645333603061 }, + { 141358280486863, 91435889572504, 1087208572552643, 1829599652522921, 1193307020643647 }, + { 1611230858525381, 950720175540785, 499589887488610, 2001656988495019, 88977313255908 } + }, + { + { 1189080501479658, 2184348804772597, 1040818725742319, 2018318290311834, 1712060030915354 }, + { 873966876953756, 1090638350350440, 1708559325189137, 672344594801910, 1320437969700239 }, + { 1508590048271766, 1131769479776094, 101550868699323, 428297785557897, 561791648661744 } + } +}, +{ /* 11/31 */ + { + { 756417570499462, 237882279232602, 2136263418594016, 1701968045454886, 703713185137472 }, + { 1781187809325462, 1697624151492346, 1381393690939988, 175194132284669, 1483054666415238 }, + { 2175517777364616, 708781536456029, 955668231122942, 1967557500069555, 2021208005604118 } + }, + { + { 1115135966606887, 224217372950782, 915967306279222, 593866251291540, 561747094208006 }, + { 1443163092879439, 391875531646162, 2180847134654632, 464538543018753, 1594098196837178 }, + { 850858855888869, 319436476624586, 327807784938441, 740785849558761, 17128415486016 } + }, + { + { 2132756334090067, 536247820155645, 48907151276867, 608473197600695, 1261689545022784 }, + { 1525176236978354, 974205476721062, 293436255662638, 148269621098039, 137961998433963 }, + { 1121075518299410, 2071745529082111, 1265567917414828, 1648196578317805, 496232102750820 } + }, + { + { 122321229299801, 1022922077493685, 2001275453369484, 2017441881607947, 993205880778002 }, + { 654925550560074, 1168810995576858, 575655959430926, 905758704861388, 496774564663534 }, + { 1954109525779738, 2117022646152485, 338102630417180, 1194140505732026, 107881734943492 } + }, + { + { 1714785840001267, 2036500018681589, 1876380234251966, 2056717182974196, 1645855254384642 }, + { 106431476499341, 62482972120563, 1513446655109411, 807258751769522, 538491469114 }, + { 2002850762893643, 1243624520538135, 1486040410574605, 2184752338181213, 378495998083531 } + }, + { + { 922510868424903, 1089502620807680, 402544072617374, 1131446598479839, 1290278588136533 }, + { 1867998812076769, 715425053580701, 39968586461416, 2173068014586163, 653822651801304 }, + { 162892278589453, 182585796682149, 75093073137630, 497037941226502, 133871727117371 } + }, + { + { 1914596576579670, 1608999621851578, 1987629837704609, 1519655314857977, 1819193753409464 }, + { 1949315551096831, 1069003344994464, 1939165033499916, 1548227205730856, 1933767655861407 }, + { 1730519386931635, 1393284965610134, 1597143735726030, 416032382447158, 1429665248828629 } + }, + { + { 360275475604565, 547835731063078, 215360904187529, 596646739879007, 332709650425085 }, + { 47602113726801, 1522314509708010, 437706261372925, 814035330438027, 335930650933545 }, + { 1291597595523886, 1058020588994081, 402837842324045, 1363323695882781, 2105763393033193 } + } +}, +{ /* 12/31 */ + { + { 109521982566564, 1715257748585139, 1112231216891516, 2046641005101484, 134249157157013 }, + { 2156991030936798, 2227544497153325, 1869050094431622, 754875860479115, 1754242344267058 }, + { 1846089562873800, 98894784984326, 1412430299204844, 171351226625762, 1100604760929008 } + }, + { + { 84172382130492, 499710970700046, 425749630620778, 1762872794206857, 612842602127960 }, + { 868309334532756, 1703010512741873, 1952690008738057, 4325269926064, 2071083554962116 }, + { 523094549451158, 401938899487815, 1407690589076010, 2022387426254453, 158660516411257 } + }, + { + { 612867287630009, 448212612103814, 571629077419196, 1466796750919376, 1728478129663858 }, + { 1723848973783452, 2208822520534681, 1718748322776940, 1974268454121942, 1194212502258141 }, + { 1254114807944608, 977770684047110, 2010756238954993, 1783628927194099, 1525962994408256 } + }, + { + { 232464058235826, 1948628555342434, 1835348780427694, 1031609499437291, 64472106918373 }, + { 767338676040683, 754089548318405, 1523192045639075, 435746025122062, 512692508440385 }, + { 1255955808701983, 1700487367990941, 1166401238800299, 1175121994891534, 1190934801395380 } + }, + { + { 349144008168292, 1337012557669162, 1475912332999108, 1321618454900458, 47611291904320 }, + { 877519947135419, 2172838026132651, 272304391224129, 1655143327559984, 886229406429814 }, + { 375806028254706, 214463229793940, 572906353144089, 572168269875638, 697556386112979 } + }, + { + { 1168827102357844, 823864273033637, 2071538752104697, 788062026895924, 599578340743362 }, + { 1948116082078088, 2054898304487796, 2204939184983900, 210526805152138, 786593586607626 }, + { 1915320147894736, 156481169009469, 655050471180417, 592917090415421, 2165897438660879 } + }, + { + { 1726336468579724, 1119932070398949, 1929199510967666, 33918788322959, 1836837863503150 }, + { 829996854845988, 217061778005138, 1686565909803640, 1346948817219846, 1723823550730181 }, + { 384301494966394, 687038900403062, 2211195391021739, 254684538421383, 1245698430589680 } + }, + { + { 1247567493562688, 1978182094455847, 183871474792955, 806570235643435, 288461518067916 }, + { 1449077384734201, 38285445457996, 2136537659177832, 2146493000841573, 725161151123125 }, + { 1201928866368855, 800415690605445, 1703146756828343, 997278587541744, 1858284414104014 } + } +}, +{ /* 13/31 */ + { + { 356468809648877, 782373916933152, 1718002439402870, 1392222252219254, 663171266061951 }, + { 759628738230460, 1012693474275852, 353780233086498, 246080061387552, 2030378857679162 }, + { 2040672435071076, 888593182036908, 1298443657189359, 1804780278521327, 354070726137060 } + }, + { + { 1894938527423184, 1463213041477277, 474410505497651, 247294963033299, 877975941029128 }, + { 207937160991127, 12966911039119, 820997788283092, 1010440472205286, 1701372890140810 }, + { 218882774543183, 533427444716285, 1233243976733245, 435054256891319, 1509568989549904 } + }, + { + { 1888838535711826, 1052177758340622, 1213553803324135, 169182009127332, 463374268115872 }, + { 299137589460312, 1594371588983567, 868058494039073, 257771590636681, 1805012993142921 }, + { 1806842755664364, 2098896946025095, 1356630998422878, 1458279806348064, 347755825962072 } + }, + { + { 1402334161391744, 1560083671046299, 1008585416617747, 1147797150908892, 1420416683642459 }, + { 665506704253369, 273770475169863, 799236974202630, 848328990077558, 1811448782807931 }, + { 1468412523962641, 771866649897997, 1931766110147832, 799561180078482, 524837559150077 } + }, + { + { 2223212657821850, 630416247363666, 2144451165500328, 816911130947791, 1024351058410032 }, + { 1266603897524861, 156378408858100, 1275649024228779, 447738405888420, 253186462063095 }, + { 2022215964509735, 136144366993649, 1800716593296582, 1193970603800203, 871675847064218 } + }, + { + { 1862751661970328, 851596246739884, 1519315554814041, 1542798466547449, 1417975335901520 }, + { 1228168094547481, 334133883362894, 587567568420081, 433612590281181, 603390400373205 }, + { 121893973206505, 1843345804916664, 1703118377384911, 497810164760654, 101150811654673 } + }, + { + { 458346255946468, 290909935619344, 1452768413850679, 550922875254215, 1537286854336538 }, + { 584322311184395, 380661238802118, 114839394528060, 655082270500073, 2111856026034852 }, + { 996965581008991, 2148998626477022, 1012273164934654, 1073876063914522, 1688031788934939 } + }, + { + { 923487018849600, 2085106799623355, 528082801620136, 1606206360876188, 735907091712524 }, + { 1697697887804317, 1335343703828273, 831288615207040, 949416685250051, 288760277392022 }, + { 1419122478109648, 1325574567803701, 602393874111094, 2107893372601700, 1314159682671307 } + } +}, +{ /* 14/31 */ + { + { 2201150872731804, 2180241023425241, 97663456423163, 1633405770247824, 848945042443986 }, + { 1173339555550611, 818605084277583, 47521504364289, 924108720564965, 735423405754506 }, + { 830104860549448, 1886653193241086, 1600929509383773, 1475051275443631, 286679780900937 } + }, + { + { 1577111294832995, 1030899169768747, 144900916293530, 1964672592979567, 568390100955250 }, + { 278388655910247, 487143369099838, 927762205508727, 181017540174210, 1616886700741287 }, + { 1191033906638969, 940823957346562, 1606870843663445, 861684761499847, 658674867251089 } + }, + { + { 1875032594195546, 1427106132796197, 724736390962158, 901860512044740, 635268497268760 }, + { 622869792298357, 1903919278950367, 1922588621661629, 1520574711600434, 1087100760174640 }, + { 25465949416618, 1693639527318811, 1526153382657203, 125943137857169, 145276964043999 } + }, + { + { 214739857969358, 920212862967915, 1939901550972269, 1211862791775221, 85097515720120 }, + { 2006245852772938, 734762734836159, 254642929763427, 1406213292755966, 239303749517686 }, + { 1619678837192149, 1919424032779215, 1357391272956794, 1525634040073113, 1310226789796241 } + }, + { + { 1040763709762123, 1704449869235352, 605263070456329, 1998838089036355, 1312142911487502 }, + { 1996723311435669, 1844342766567060, 985455700466044, 1165924681400960, 311508689870129 }, + { 43173156290518, 2202883069785309, 1137787467085917, 1733636061944606, 1394992037553852 } + }, + { + { 670078326344559, 555655025059356, 471959386282438, 2141455487356409, 849015953823125 }, + { 2197214573372804, 794254097241315, 1030190060513737, 267632515541902, 2040478049202624 }, + { 1812516004670529, 1609256702920783, 1706897079364493, 258549904773295, 996051247540686 } + }, + { + { 1540374301420584, 1764656898914615, 1810104162020396, 923808779163088, 664390074196579 }, + { 1323460699404750, 1262690757880991, 871777133477900, 1060078894988977, 1712236889662886 }, + { 1696163952057966, 1391710137550823, 608793846867416, 1034391509472039, 1780770894075012 } + }, + { + { 1367603834210841, 2131988646583224, 890353773628144, 1908908219165595, 270836895252891 }, + { 597536315471731, 40375058742586, 1942256403956049, 1185484645495932, 312666282024145 }, + { 1919411405316294, 1234508526402192, 1066863051997083, 1008444703737597, 1348810787701552 } + } +}, +{ /* 15/31 */ + { + { 2102881477513865, 1570274565945361, 1573617900503708, 18662635732583, 2232324307922098 }, + { 1853931367696942, 8107973870707, 350214504129299, 775206934582587, 1752317649166792 }, + { 1417148368003523, 721357181628282, 505725498207811, 373232277872983, 261634707184480 } + }, + { + { 2186733281493267, 2250694917008620, 1014829812957440, 479998161452389, 83566193876474 }, + { 1268116367301224, 560157088142809, 802626839600444, 2210189936605713, 1129993785579988 }, + { 615183387352312, 917611676109240, 878893615973325, 978940963313282, 938686890583575 } + }, + { + { 522024729211672, 1045059315315808, 1892245413707790, 1907891107684253, 2059998109500714 }, + { 1799679152208884, 912132775900387, 25967768040979, 432130448590461, 274568990261996 }, + { 98698809797682, 2144627600856209, 1907959298569602, 811491302610148, 1262481774981493 } + }, + { + { 1791451399743152, 1713538728337276, 118349997257490, 1882306388849954, 158235232210248 }, + { 1217809823321928, 2173947284933160, 1986927836272325, 1388114931125539, 12686131160169 }, + { 1650875518872272, 1136263858253897, 1732115601395988, 734312880662190, 1252904681142109 } + }, + { + { 372986456113865, 525430915458171, 2116279931702135, 501422713587815, 1907002872974925 }, + { 803147181835288, 868941437997146, 316299302989663, 943495589630550, 571224287904572 }, + { 227742695588364, 1776969298667369, 628602552821802, 457210915378118, 2041906378111140 } + }, + { + { 815000523470260, 913085688728307, 1052060118271173, 1345536665214223, 541623413135555 }, + { 1580216071604333, 1877997504342444, 857147161260913, 703522726778478, 2182763974211603 }, + { 1870080310923419, 71988220958492, 1783225432016732, 615915287105016, 1035570475990230 } + }, + { + { 730987750830150, 857613889540280, 1083813157271766, 1002817255970169, 1719228484436074 }, + { 377616581647602, 1581980403078513, 804044118130621, 2034382823044191, 643844048472185 }, + { 176957326463017, 1573744060478586, 528642225008045, 1816109618372371, 1515140189765006 } + }, + { + { 1888911448245718, 1387110895611080, 1924503794066429, 1731539523700949, 2230378382645454 }, + { 443392177002051, 233793396845137, 2199506622312416, 1011858706515937, 974676837063129 }, + { 1846351103143623, 1949984838808427, 671247021915253, 1946756846184401, 1929296930380217 } + } +}, +{ /* 16/31 */ + { + { 849646212452002, 1410198775302919, 73767886183695, 1641663456615812, 762256272452411 }, + { 692017667358279, 723305578826727, 1638042139863265, 748219305990306, 334589200523901 }, + { 22893968530686, 2235758574399251, 1661465835630252, 925707319443452, 1203475116966621 } + }, + { + { 801299035785166, 1733292596726131, 1664508947088596, 467749120991922, 1647498584535623 }, + { 903105258014366, 427141894933047, 561187017169777, 1884330244401954, 1914145708422219 }, + { 1344191060517578, 1960935031767890, 1518838929955259, 1781502350597190, 1564784025565682 } + }, + { + { 673723351748086, 1979969272514923, 1175287312495508, 1187589090978666, 1881897672213940 }, + { 1917185587363432, 1098342571752737, 5935801044414, 2000527662351839, 1538640296181569 }, + { 2495540013192, 678856913479236, 224998292422872, 219635787698590, 1972465269000940 } + }, + { + { 271413961212179, 1353052061471651, 344711291283483, 2014925838520662, 2006221033113941 }, + { 194583029968109, 514316781467765, 829677956235672, 1676415686873082, 810104584395840 }, + { 1980510813313589, 1948645276483975, 152063780665900, 129968026417582, 256984195613935 } + }, + { + { 1860190562533102, 1936576191345085, 461100292705964, 1811043097042830, 957486749306835 }, + { 796664815624365, 1543160838872951, 1500897791837765, 1667315977988401, 599303877030711 }, + { 1151480509533204, 2136010406720455, 738796060240027, 319298003765044, 1150614464349587 } + }, + { + { 1731069268103150, 735642447616087, 1364750481334268, 417232839982871, 927108269127661 }, + { 1017222050227968, 1987716148359, 2234319589635701, 621282683093392, 2132553131763026 }, + { 1567828528453324, 1017807205202360, 565295260895298, 829541698429100, 307243822276582 } + }, + { + { 249079270936248, 1501514259790706, 947909724204848, 944551802437487, 552658763982480 }, + { 2089966982947227, 1854140343916181, 2151980759220007, 2139781292261749, 158070445864917 }, + { 1338766321464554, 1906702607371284, 1519569445519894, 115384726262267, 1393058953390992 } + }, + { + { 1364621558265400, 1512388234908357, 1926731583198686, 2041482526432505, 920401122333774 }, + { 1884844597333588, 601480070269079, 620203503079537, 1079527400117915, 1202076693132015 }, + { 840922919763324, 727955812569642, 1303406629750194, 522898432152867, 294161410441865 } + } +}, +{ /* 17/31 */ + { + { 353760790835310, 1598361541848743, 1122905698202299, 1922533590158905, 419107700666580 }, + { 359856369838236, 180914355488683, 861726472646627, 218807937262986, 575626773232501 }, + { 755467689082474, 909202735047934, 730078068932500, 936309075711518, 2007798262842972 } + }, + { + { 1609384177904073, 362745185608627, 1335318541768201, 800965770436248, 547877979267412 }, + { 984339177776787, 815727786505884, 1645154585713747, 1659074964378553, 1686601651984156 }, + { 1697863093781930, 599794399429786, 1104556219769607, 830560774794755, 12812858601017 } + }, + { + { 1168737550514982, 897832437380552, 463140296333799, 302564600022547, 2008360505135501 }, + { 1856930662813910, 678090852002597, 1920179140755167, 1259527833759868, 55540971895511 }, + { 1158643631044921, 476554103621892, 178447851439725, 1305025542653569, 103433927680625 } + }, + { + { 2176793111709008, 1576725716350391, 2009350167273523, 2012390194631546, 2125297410909580 }, + { 825403285195098, 2144208587560784, 1925552004644643, 1915177840006985, 1015952128947864 }, + { 1807108316634472, 1534392066433717, 347342975407218, 1153820745616376, 7375003497471 } + }, + { + { 983061001799725, 431211889901241, 2201903782961093, 817393911064341, 2214616493042167 }, + { 228567918409756, 865093958780220, 358083886450556, 159617889659320, 1360637926292598 }, + { 234147501399755, 2229469128637390, 2175289352258889, 1397401514549353, 1885288963089922 } + }, + { + { 1111762412951562, 252849572507389, 1048714233823341, 146111095601446, 1237505378776770 }, + { 1113790697840279, 1051167139966244, 1045930658550944, 2011366241542643, 1686166824620755 }, + { 1054097349305049, 1872495070333352, 182121071220717, 1064378906787311, 100273572924182 } + }, + { + { 1306410853171605, 1627717417672447, 50983221088417, 1109249951172250, 870201789081392 }, + { 104233794644221, 1548919791188248, 2224541913267306, 2054909377116478, 1043803389015153 }, + { 216762189468802, 707284285441622, 190678557969733, 973969342604308, 1403009538434867 } + }, + { + { 1279024291038477, 344776835218310, 273722096017199, 1834200436811442, 634517197663804 }, + { 343805853118335, 1302216857414201, 566872543223541, 2051138939539004, 321428858384280 }, + { 470067171324852, 1618629234173951, 2000092177515639, 7307679772789, 1117521120249968 } + } +}, +{ /* 18/31 */ + { + { 278151578291475, 1810282338562947, 1771599529530998, 1383659409671631, 685373414471841 }, + { 577009397403102, 1791440261786291, 2177643735971638, 174546149911960, 1412505077782326 }, + { 893719721537457, 1201282458018197, 1522349501711173, 58011597740583, 1130406465887139 } + }, + { + { 412607348255453, 1280455764199780, 2233277987330768, 14180080401665, 331584698417165 }, + { 262483770854550, 990511055108216, 526885552771698, 571664396646158, 354086190278723 }, + { 1820352417585487, 24495617171480, 1547899057533253, 10041836186225, 480457105094042 } + }, + { + { 2023310314989233, 637905337525881, 2106474638900687, 557820711084072, 1687858215057826 }, + { 1144168702609745, 604444390410187, 1544541121756138, 1925315550126027, 626401428894002 }, + { 1922168257351784, 2018674099908659, 1776454117494445, 956539191509034, 36031129147635 } + }, + { + { 544644538748041, 1039872944430374, 876750409130610, 710657711326551, 1216952687484972 }, + { 58242421545916, 2035812695641843, 2118491866122923, 1191684463816273, 46921517454099 }, + { 272268252444639, 1374166457774292, 2230115177009552, 1053149803909880, 1354288411641016 } + }, + { + { 1857910905368338, 1754729879288912, 885945464109877, 1516096106802166, 1602902393369811 }, + { 1193437069800958, 901107149704790, 999672920611411, 477584824802207, 364239578697845 }, + { 886299989548838, 1538292895758047, 1590564179491896, 1944527126709657, 837344427345298 } + }, + { + { 754558365378305, 1712186480903618, 1703656826337531, 750310918489786, 518996040250900 }, + { 1309847803895382, 1462151862813074, 211370866671570, 1544595152703681, 1027691798954090 }, + { 803217563745370, 1884799722343599, 1357706345069218, 2244955901722095, 730869460037413 } + }, + { + { 689299471295966, 1831210565161071, 1375187341585438, 1106284977546171, 1893781834054269 }, + { 696351368613042, 1494385251239250, 738037133616932, 636385507851544, 927483222611406 }, + { 1949114198209333, 1104419699537997, 783495707664463, 1747473107602770, 2002634765788641 } + }, + { + { 1607325776830197, 530883941415333, 1451089452727895, 1581691157083423, 496100432831154 }, + { 1068900648804224, 2006891997072550, 1134049269345549, 1638760646180091, 2055396084625778 }, + { 2222475519314561, 1870703901472013, 1884051508440561, 1344072275216753, 1318025677799069 } + } +}, +{ /* 19/31 */ + { + { 155711679280656, 681100400509288, 389811735211209, 2135723811340709, 408733211204125 }, + { 7813206966729, 194444201427550, 2071405409526507, 1065605076176312, 1645486789731291 }, + { 16625790644959, 1647648827778410, 1579910185572704, 436452271048548, 121070048451050 } + }, + { + { 1037263028552531, 568385780377829, 297953104144430, 1558584511931211, 2238221839292471 }, + { 190565267697443, 672855706028058, 338796554369226, 337687268493904, 853246848691734 }, + { 1763863028400139, 766498079432444, 1321118624818005, 69494294452268, 858786744165651 } + }, + { + { 1292056768563024, 1456632109855638, 1100631247050184, 1386133165675321, 1232898350193752 }, + { 366253102478259, 525676242508811, 1449610995265438, 1183300845322183, 185960306491545 }, + { 28315355815982, 460422265558930, 1799675876678724, 1969256312504498, 1051823843138725 } + }, + { + { 156914999361983, 1606148405719949, 1665208410108430, 317643278692271, 1383783705665320 }, + { 54684536365732, 2210010038536222, 1194984798155308, 535239027773705, 1516355079301361 }, + { 1484387703771650, 198537510937949, 2186282186359116, 617687444857508, 647477376402122 } + }, + { + { 2147715541830533, 500032538445817, 646380016884826, 352227855331122, 1488268620408052 }, + { 159386186465542, 1877626593362941, 618737197060512, 1026674284330807, 1158121760792685 }, + { 1744544377739822, 1964054180355661, 1685781755873170, 2169740670377448, 1286112621104591 } + }, + { + { 81977249784993, 1667943117713086, 1668983819634866, 1605016835177615, 1353960708075544 }, + { 1602253788689063, 439542044889886, 2220348297664483, 657877410752869, 157451572512238 }, + { 1029287186166717, 65860128430192, 525298368814832, 1491902500801986, 1461064796385400 } + }, + { + { 408216988729246, 2121095722306989, 913562102267595, 1879708920318308, 241061448436731 }, + { 1185483484383269, 1356339572588553, 584932367316448, 102132779946470, 1792922621116791 }, + { 1966196870701923, 2230044620318636, 1425982460745905, 261167817826569, 46517743394330 } + }, + { + { 107077591595359, 884959942172345, 27306869797400, 2224911448949390, 964352058245223 }, + { 1730194207717538, 431790042319772, 1831515233279467, 1372080552768581, 1074513929381760 }, + { 1450880638731607, 1019861580989005, 1229729455116861, 1174945729836143, 826083146840706 } + } +}, +{ /* 20/31 */ + { + { 1899935429242705, 1602068751520477, 940583196550370, 82431069053859, 1540863155745696 }, + { 2136688454840028, 2099509000964294, 1690800495246475, 1217643678575476, 828720645084218 }, + { 765548025667841, 462473984016099, 998061409979798, 546353034089527, 2212508972466858 } + }, + { + { 46575283771160, 892570971573071, 1281983193144090, 1491520128287375, 75847005908304 }, + { 1801436127943107, 1734436817907890, 1268728090345068, 167003097070711, 2233597765834956 }, + { 1997562060465113, 1048700225534011, 7615603985628, 1855310849546841, 2242557647635213 } + }, + { + { 1161017320376250, 492624580169043, 2169815802355237, 976496781732542, 1770879511019629 }, + { 1357044908364776, 729130645262438, 1762469072918979, 1365633616878458, 181282906404941 }, + { 1080413443139865, 1155205815510486, 1848782073549786, 622566975152580, 124965574467971 } + }, + { + { 1184526762066993, 247622751762817, 692129017206356, 820018689412496, 2188697339828085 }, + { 2020536369003019, 202261491735136, 1053169669150884, 2056531979272544, 778165514694311 }, + { 237404399610207, 1308324858405118, 1229680749538400, 720131409105291, 1958958863624906 } + }, + { + { 515583508038846, 17656978857189, 1717918437373989, 1568052070792483, 46975803123923 }, + { 281527309158085, 36970532401524, 866906920877543, 2222282602952734, 1289598729589882 }, + { 1278207464902042, 494742455008756, 1262082121427081, 1577236621659884, 1888786707293291 } + }, + { + { 353042527954210, 1830056151907359, 1111731275799225, 174960955838824, 404312815582675 }, + { 2064251142068628, 1666421603389706, 1419271365315441, 468767774902855, 191535130366583 }, + { 1716987058588002, 1859366439773457, 1767194234188234, 64476199777924, 1117233614485261 } + }, + { + { 984292135520292, 135138246951259, 2220652137473167, 1722843421165029, 190482558012909 }, + { 298845952651262, 1166086588952562, 1179896526238434, 1347812759398693, 1412945390096208 }, + { 1143239552672925, 906436640714209, 2177000572812152, 2075299936108548, 325186347798433 } + }, + { + { 721024854374772, 684487861263316, 1373438744094159, 2193186935276995, 1387043709851261 }, + { 418098668140962, 715065997721283, 1471916138376055, 2168570337288357, 937812682637044 }, + { 1043584187226485, 2143395746619356, 2209558562919611, 482427979307092, 847556718384018 } + } +}, +{ /* 21/31 */ + { + { 1248731221520759, 1465200936117687, 540803492710140, 52978634680892, 261434490176109 }, + { 1057329623869501, 620334067429122, 461700859268034, 2012481616501857, 297268569108938 }, + { 1055352180870759, 1553151421852298, 1510903185371259, 1470458349428097, 1226259419062731 } + }, + { + { 1492988790301668, 790326625573331, 1190107028409745, 1389394752159193, 1620408196604194 }, + { 47000654413729, 1004754424173864, 1868044813557703, 173236934059409, 588771199737015 }, + { 30498470091663, 1082245510489825, 576771653181956, 806509986132686, 1317634017056939 } + }, + { + { 420308055751555, 1493354863316002, 165206721528088, 1884845694919786, 2065456951573059 }, + { 1115636332012334, 1854340990964155, 83792697369514, 1972177451994021, 457455116057587 }, + { 1698968457310898, 1435137169051090, 1083661677032510, 938363267483709, 340103887207182 } + }, + { + { 1995325341336574, 911500251774648, 164010755403692, 855378419194762, 1573601397528842 }, + { 241719380661528, 310028521317150, 1215881323380194, 1408214976493624, 2141142156467363 }, + { 1315157046163473, 727368447885818, 1363466668108618, 1668921439990361, 1398483384337907 } + }, + { + { 75029678299646, 1015388206460473, 1849729037055212, 1939814616452984, 444404230394954 }, + { 2053597130993710, 2024431685856332, 2233550957004860, 2012407275509545, 872546993104440 }, + { 1217269667678610, 599909351968693, 1390077048548598, 1471879360694802, 739586172317596 } + }, + { + { 1718318639380794, 1560510726633958, 904462881159922, 1418028351780052, 94404349451937 }, + { 2132502667405250, 214379346175414, 1502748313768060, 1960071701057800, 1353971822643138 }, + { 319394212043702, 2127459436033571, 717646691535162, 663366796076914, 318459064945314 } + }, + { + { 405989424923593, 1960452633787083, 667349034401665, 1492674260767112, 1451061489880787 }, + { 947085906234007, 323284730494107, 1485778563977200, 728576821512394, 901584347702286 }, + { 1575783124125742, 2126210792434375, 1569430791264065, 1402582372904727, 1891780248341114 } + }, + { + { 838432205560695, 1997703511451664, 1018791879907867, 1662001808174331, 78328132957753 }, + { 739152638255629, 2074935399403557, 505483666745895, 1611883356514088, 628654635394878 }, + { 1822054032121349, 643057948186973, 7306757352712, 577249257962099, 284735863382083 } + } +}, +{ /* 22/31 */ + { + { 1366558556363930, 1448606567552086, 1478881020944768, 165803179355898, 1115718458123498 }, + { 204146226972102, 1630511199034723, 2215235214174763, 174665910283542, 956127674017216 }, + { 1562934578796716, 1070893489712745, 11324610642270, 958989751581897, 2172552325473805 } + }, + { + { 1770564423056027, 735523631664565, 1326060113795289, 1509650369341127, 65892421582684 }, + { 623682558650637, 1337866509471512, 990313350206649, 1314236615762469, 1164772974270275 }, + { 223256821462517, 723690150104139, 1000261663630601, 933280913953265, 254872671543046 } + }, + { + { 1969087237026041, 624795725447124, 1335555107635969, 2069986355593023, 1712100149341902 }, + { 1236103475266979, 1837885883267218, 1026072585230455, 1025865513954973, 1801964901432134 }, + { 1115241013365517, 1712251818829143, 2148864332502771, 2096001471438138, 2235017246626125 } + }, + { + { 1299268198601632, 2047148477845621, 2165648650132450, 1612539282026145, 514197911628890 }, + { 118352772338543, 1067608711804704, 1434796676193498, 1683240170548391, 230866769907437 }, + { 1850689576796636, 1601590730430274, 1139674615958142, 1954384401440257, 76039205311 } + }, + { + { 1723387471374172, 997301467038410, 533927635123657, 20928644693965, 1756575222802513 }, + { 2146711623855116, 503278928021499, 625853062251406, 1109121378393107, 1033853809911861 }, + { 571005965509422, 2005213373292546, 1016697270349626, 56607856974274, 914438579435146 } + }, + { + { 1346698876211176, 2076651707527589, 1084761571110205, 265334478828406, 1068954492309671 }, + { 1769967932677654, 1695893319756416, 1151863389675920, 1781042784397689, 400287774418285 }, + { 1851867764003121, 403841933237558, 820549523771987, 761292590207581, 1743735048551143 } + }, + { + { 410915148140008, 2107072311871739, 1004367461876503, 99684895396761, 1180818713503224 }, + { 285945406881439, 648174397347453, 1098403762631981, 1366547441102991, 1505876883139217 }, + { 672095903120153, 1675918957959872, 636236529315028, 1569297300327696, 2164144194785875 } + }, + { + { 1902708175321798, 1035343530915438, 1178560808893263, 301095684058146, 1280977479761118 }, + { 1615357281742403, 404257611616381, 2160201349780978, 1160947379188955, 1578038619549541 }, + { 2013087639791217, 822734930507457, 1785668418619014, 1668650702946164, 389450875221715 } + } +}, +{ /* 23/31 */ + { + { 453918449698368, 106406819929001, 2072540975937135, 308588860670238, 1304394580755385 }, + { 1295082798350326, 2091844511495996, 1851348972587817, 3375039684596, 789440738712837 }, + { 2083069137186154, 848523102004566, 993982213589257, 1405313299916317, 1532824818698468 } + }, + { + { 1495961298852430, 1397203457344779, 1774950217066942, 139302743555696, 66603584342787 }, + { 1782411379088302, 1096724939964781, 27593390721418, 542241850291353, 1540337798439873 }, + { 693543956581437, 171507720360750, 1557908942697227, 1074697073443438, 1104093109037196 } + }, + { + { 345288228393419, 1099643569747172, 134881908403743, 1740551994106740, 248212179299770 }, + { 231429562203065, 1526290236421172, 2021375064026423, 1520954495658041, 806337791525116 }, + { 1079623667189886, 872403650198613, 766894200588288, 2163700860774109, 2023464507911816 } + }, + { + { 854645372543796, 1936406001954827, 151460662541253, 825325739271555, 1554306377287556 }, + { 1497138821904622, 1044820250515590, 1742593886423484, 1237204112746837, 849047450816987 }, + { 667962773375330, 1897271816877105, 1399712621683474, 1143302161683099, 2081798441209593 } + }, + { + { 127147851567005, 1936114012888110, 1704424366552046, 856674880716312, 716603621335359 }, + { 1072409664800960, 2146937497077528, 1508780108920651, 935767602384853, 1112800433544068 }, + { 333549023751292, 280219272863308, 2104176666454852, 1036466864875785, 536135186520207 } + }, + { + { 373666279883137, 146457241530109, 304116267127857, 416088749147715, 1258577131183391 }, + { 1186115062588401, 2251609796968486, 1098944457878953, 1153112761201374, 1791625503417267 }, + { 1870078460219737, 2129630962183380, 852283639691142, 292865602592851, 401904317342226 } + }, + { + { 1361070124828035, 815664541425524, 1026798897364671, 1951790935390647, 555874891834790 }, + { 1546301003424277, 459094500062839, 1097668518375311, 1780297770129643, 720763293687608 }, + { 1212405311403990, 1536693382542438, 61028431067459, 1863929423417129, 1223219538638038 } + }, + { + { 1294303766540260, 1183557465955093, 882271357233093, 63854569425375, 2213283684565087 }, + { 339050984211414, 601386726509773, 413735232134068, 966191255137228, 1839475899458159 }, + { 235605972169408, 2174055643032978, 1538335001838863, 1281866796917192, 1815940222628465 } + } +}, +{ /* 24/31 */ + { + { 1632352921721536, 1833328609514701, 2092779091951987, 1923956201873226, 2210068022482919 }, + { 35271216625062, 1712350667021807, 983664255668860, 98571260373038, 1232645608559836 }, + { 1998172393429622, 1798947921427073, 784387737563581, 1589352214827263, 1589861734168180 } + }, + { + { 1733739258725305, 31715717059538, 201969945218860, 992093044556990, 1194308773174556 }, + { 846415389605137, 746163495539180, 829658752826080, 592067705956946, 957242537821393 }, + { 1758148849754419, 619249044817679, 168089007997045, 1371497636330523, 1867101418880350 } + }, + { + { 326633984209635, 261759506071016, 1700682323676193, 1577907266349064, 1217647663383016 }, + { 1714182387328607, 1477856482074168, 574895689942184, 2159118410227270, 1555532449716575 }, + { 853828206885131, 998498946036955, 1835887550391235, 207627336608048, 258363815956050 } + }, + { + { 141141474651677, 1236728744905256, 643101419899887, 1646615130509173, 1208239602291765 }, + { 1501663228068911, 1354879465566912, 1444432675498247, 897812463852601, 855062598754348 }, + { 714380763546606, 1032824444965790, 1774073483745338, 1063840874947367, 1738680636537158 } + }, + { + { 1640635546696252, 633168953192112, 2212651044092396, 30590958583852, 368515260889378 }, + { 1171650314802029, 1567085444565577, 1453660792008405, 757914533009261, 1619511342778196 }, + { 420958967093237, 971103481109486, 2169549185607107, 1301191633558497, 1661514101014240 } + }, + { + { 907123651818302, 1332556122804146, 1824055253424487, 1367614217442959, 1982558335973172 }, + { 1121533090144639, 1021251337022187, 110469995947421, 1511059774758394, 2110035908131662 }, + { 303213233384524, 2061932261128138, 352862124777736, 40828818670255, 249879468482660 } + }, + { + { 856559257852200, 508517664949010, 1378193767894916, 1723459126947129, 1962275756614521 }, + { 1445691340537320, 40614383122127, 402104303144865, 485134269878232, 1659439323587426 }, + { 20057458979482, 1183363722525800, 2140003847237215, 2053873950687614, 2112017736174909 } + }, + { + { 2228654250927986, 1483591363415267, 1368661293910956, 1076511285177291, 526650682059608 }, + { 709481497028540, 531682216165724, 316963769431931, 1814315888453765, 258560242424104 }, + { 1053447823660455, 1955135194248683, 1010900954918985, 1182614026976701, 1240051576966610 } + } +}, +{ /* 25/31 */ + { + { 1957943897155497, 1788667368028035, 137692910029106, 1039519607062, 826404763313028 }, + { 1848942433095597, 1582009882530495, 1849292741020143, 1068498323302788, 2001402229799484 }, + { 1528282417624269, 2142492439828191, 2179662545816034, 362568973150328, 1591374675250271 } + }, + { + { 160026679434388, 232341189218716, 2149181472355545, 598041771119831, 183859001910173 }, + { 2013278155187349, 662660471354454, 793981225706267, 411706605985744, 804490933124791 }, + { 2051892037280204, 488391251096321, 2230187337030708, 930221970662692, 679002758255210 } + }, + { + { 1530723630438670, 875873929577927, 341560134269988, 449903119530753, 1055551308214179 }, + { 1461835919309432, 1955256480136428, 180866187813063, 1551979252664528, 557743861963950 }, + { 359179641731115, 1324915145732949, 902828372691474, 294254275669987, 1887036027752957 } + }, + { + { 2043271609454323, 2038225437857464, 1317528426475850, 1398989128982787, 2027639881006861 }, + { 2072902725256516, 312132452743412, 309930885642209, 996244312618453, 1590501300352303 }, + { 1397254305160710, 695734355138021, 2233992044438756, 1776180593969996, 1085588199351115 } + }, + { + { 440567051331029, 254894786356681, 493869224930222, 1556322069683366, 1567456540319218 }, + { 1950722461391320, 1907845598854797, 1822757481635527, 2121567704750244, 73811931471221 }, + { 387139307395758, 2058036430315676, 1220915649965325, 1794832055328951, 1230009312169328 } + }, + { + { 1765973779329517, 659344059446977, 19821901606666, 1301928341311214, 1116266004075885 }, + { 1127572801181483, 1224743760571696, 1276219889847274, 1529738721702581, 1589819666871853 }, + { 2181229378964934, 2190885205260020, 1511536077659137, 1246504208580490, 668883326494241 } + }, + { + { 437866655573314, 669026411194768, 81896997980338, 523874406393178, 245052060935236 }, + { 1975438052228868, 1071801519999806, 594652299224319, 1877697652668809, 1489635366987285 }, + { 958592545673770, 233048016518599, 851568750216589, 567703851596087, 1740300006094761 } + }, + { + { 2014540178270324, 192672779514432, 213877182641530, 2194819933853411, 1716422829364835 }, + { 1540769606609725, 2148289943846077, 1597804156127445, 1230603716683868, 815423458809453 }, + { 1738560251245018, 1779576754536888, 1783765347671392, 1880170990446751, 1088225159617541 } + } +}, +{ /* 26/31 */ + { + { 659303913929492, 1956447718227573, 1830568515922666, 841069049744408, 1669607124206368 }, + { 1143465490433355, 1532194726196059, 1093276745494697, 481041706116088, 2121405433561163 }, + { 1686424298744462, 1451806974487153, 266296068846582, 1834686947542675, 1720762336132256 } + }, + { + { 889217026388959, 1043290623284660, 856125087551909, 1669272323124636, 1603340330827879 }, + { 1206396181488998, 333158148435054, 1402633492821422, 1120091191722026, 1945474114550509 }, + { 766720088232571, 1512222781191002, 1189719893490790, 2091302129467914, 2141418006894941 } + }, + { + { 419663647306612, 1998875112167987, 1426599870253707, 1154928355379510, 486538532138187 }, + { 938160078005954, 1421776319053174, 1941643234741774, 180002183320818, 1414380336750546 }, + { 398001940109652, 1577721237663248, 1012748649830402, 1540516006905144, 1011684812884559 } + }, + { + { 1653276489969630, 6081825167624, 1921777941170836, 1604139841794531, 861211053640641 }, + { 996661541407379, 1455877387952927, 744312806857277, 139213896196746, 1000282908547789 }, + { 1450817495603008, 1476865707053229, 1030490562252053, 620966950353376, 1744760161539058 } + }, + { + { 559728410002599, 37056661641185, 2038622963352006, 1637244893271723, 1026565352238948 }, + { 962165956135846, 1116599660248791, 182090178006815, 1455605467021751, 196053588803284 }, + { 796863823080135, 1897365583584155, 420466939481601, 2165972651724672, 932177357788289 } + }, + { + { 877047233620632, 1375632631944375, 643773611882121, 660022738847877, 19353932331831 }, + { 2216943882299338, 394841323190322, 2222656898319671, 558186553950529, 1077236877025190 }, + { 801118384953213, 1914330175515892, 574541023311511, 1471123787903705, 1526158900256288 } + }, + { + { 949617889087234, 2207116611267331, 912920039141287, 501158539198789, 62362560771472 }, + { 1474518386765335, 1760793622169197, 1157399790472736, 1622864308058898, 165428294422792 }, + { 1961673048027128, 102619413083113, 1051982726768458, 1603657989805485, 1941613251499678 } + }, + { + { 1401939116319266, 335306339903072, 72046196085786, 862423201496006, 850518754531384 }, + { 1234706593321979, 1083343891215917, 898273974314935, 1640859118399498, 157578398571149 }, + { 1143483057726416, 1992614991758919, 674268662140796, 1773370048077526, 674318359920189 } + } +}, +{ /* 27/31 */ + { + { 1835401379538542, 173900035308392, 818247630716732, 1762100412152786, 1021506399448291 }, + { 1506632088156630, 2127481795522179, 513812919490255, 140643715928370, 442476620300318 }, + { 2056683376856736, 219094741662735, 2193541883188309, 1841182310235800, 556477468664293 } + }, + { + { 1315019427910827, 1049075855992603, 2066573052986543, 266904467185534, 2040482348591520 }, + { 94096246544434, 922482381166992, 24517828745563, 2139430508542503, 2097139044231004 }, + { 537697207950515, 1399352016347350, 1563663552106345, 2148749520888918, 549922092988516 } + }, + { + { 1747985413252434, 680511052635695, 1809559829982725, 594274250930054, 201673170745982 }, + { 323583936109569, 1973572998577657, 1192219029966558, 79354804385273, 1374043025560347 }, + { 213277331329947, 416202017849623, 1950535221091783, 1313441578103244, 2171386783823658 } + }, + { + { 189088804229831, 993969372859110, 895870121536987, 1547301535298256, 1477373024911350 }, + { 1620578418245010, 541035331188469, 2235785724453865, 2154865809088198, 1974627268751826 }, + { 1346805451740245, 1350981335690626, 942744349501813, 2155094562545502, 1012483751693409 } + }, + { + { 2107080134091762, 1132567062788208, 1824935377687210, 769194804343737, 1857941799971888 }, + { 1074666112436467, 249279386739593, 1174337926625354, 1559013532006480, 1472287775519121 }, + { 1872620123779532, 1892932666768992, 1921559078394978, 1270573311796160, 1438913646755037 } + }, + { + { 837390187648199, 1012253300223599, 989780015893987, 1351393287739814, 328627746545550 }, + { 1028328827183114, 1711043289969857, 1350832470374933, 1923164689604327, 1495656368846911 }, + { 1900828492104143, 430212361082163, 687437570852799, 832514536673512, 1685641495940794 } + }, + { + { 842632847936398, 605670026766216, 290836444839585, 163210774892356, 2213815011799645 }, + { 1176336383453996, 1725477294339771, 12700622672454, 678015708818208, 162724078519879 }, + { 1448049969043497, 1789411762943521, 385587766217753, 90201620913498, 832999441066823 } + }, + { + { 516086333293313, 2240508292484616, 1351669528166508, 1223255565316488, 750235824427138 }, + { 1263624896582495, 1102602401673328, 526302183714372, 2152015839128799, 1483839308490010 }, + { 442991718646863, 1599275157036458, 1925389027579192, 899514691371390, 350263251085160 } + } +}, +{ /* 28/31 */ + { + { 1689713572022143, 593854559254373, 978095044791970, 1985127338729499, 1676069120347625 }, + { 1557207018622683, 340631692799603, 1477725909476187, 614735951619419, 2033237123746766 }, + { 968764929340557, 1225534776710944, 662967304013036, 1155521416178595, 791142883466590 } + }, + { + { 1487081286167458, 993039441814934, 1792378982844640, 698652444999874, 2153908693179754 }, + { 1123181311102823, 685575944875442, 507605465509927, 1412590462117473, 568017325228626 }, + { 560258797465417, 2193971151466401, 1824086900849026, 579056363542056, 1690063960036441 } + }, + { + { 1918407319222416, 353767553059963, 1930426334528099, 1564816146005724, 1861342381708096 }, + { 2131325168777276, 1176636658428908, 1756922641512981, 1390243617176012, 1966325177038383 }, + { 2063958120364491, 2140267332393533, 699896251574968, 273268351312140, 375580724713232 } + }, + { + { 2024297515263178, 416959329722687, 1079014235017302, 171612225573183, 1031677520051053 }, + { 2033900009388450, 1744902869870788, 2190580087917640, 1949474984254121, 231049754293748 }, + { 343868674606581, 550155864008088, 1450580864229630, 481603765195050, 896972360018042 } + }, + { + { 2151139328380127, 314745882084928, 59756825775204, 1676664391494651, 2048348075599360 }, + { 1528930066340597, 1605003907059576, 1055061081337675, 1458319101947665, 1234195845213142 }, + { 830430507734812, 1780282976102377, 1425386760709037, 362399353095425, 2168861579799910 } + }, + { + { 1155762232730333, 980662895504006, 2053766700883521, 490966214077606, 510405877041357 }, + { 1683750316716132, 652278688286128, 1221798761193539, 1897360681476669, 319658166027343 }, + { 618808732869972, 72755186759744, 2060379135624181, 1730731526741822, 48862757828238 } + }, + { + { 1463171970593505, 1143040711767452, 614590986558883, 1409210575145591, 1882816996436803 }, + { 2230133264691131, 563950955091024, 2042915975426398, 827314356293472, 672028980152815 }, + { 264204366029760, 1654686424479449, 2185050199932931, 2207056159091748, 506015669043634 } + }, + { + { 1784446333136569, 1973746527984364, 334856327359575, 1156769775884610, 1023950124675478 }, + { 2065270940578383, 31477096270353, 306421879113491, 181958643936686, 1907105536686083 }, + { 1496516440779464, 1748485652986458, 872778352227340, 818358834654919, 97932669284220 } + } +}, +{ /* 29/31 */ + { + { 471636015770351, 672455402793577, 1804995246884103, 1842309243470804, 1501862504981682 }, + { 1013216974933691, 538921919682598, 1915776722521558, 1742822441583877, 1886550687916656 }, + { 2094270000643336, 303971879192276, 40801275554748, 649448917027930, 1818544418535447 } + }, + { + { 2241737709499165, 549397817447461, 838180519319392, 1725686958520781, 1705639080897747 }, + { 1216074541925116, 50120933933509, 1565829004133810, 721728156134580, 349206064666188 }, + { 948617110470858, 346222547451945, 1126511960599975, 1759386906004538, 493053284802266 } + }, + { + { 1454933046815146, 874696014266362, 1467170975468588, 1432316382418897, 2111710746366763 }, + { 2105387117364450, 1996463405126433, 1303008614294500, 851908115948209, 1353742049788635 }, + { 750300956351719, 1487736556065813, 15158817002104, 1511998221598392, 971739901354129 } + }, + { + { 1874648163531693, 2124487685930551, 1810030029384882, 918400043048335, 586348627300650 }, + { 1235084464747900, 1166111146432082, 1745394857881591, 1405516473883040, 4463504151617 }, + { 1663810156463827, 327797390285791, 1341846161759410, 1964121122800605, 1747470312055380 } + }, + { + { 660005247548233, 2071860029952887, 1358748199950107, 911703252219107, 1014379923023831 }, + { 2206641276178231, 1690587809721504, 1600173622825126, 2156096097634421, 1106822408548216 }, + { 1344788193552206, 1949552134239140, 1735915881729557, 675891104100469, 1834220014427292 } + }, + { + { 1920949492387964, 158885288387530, 70308263664033, 626038464897817, 1468081726101009 }, + { 622221042073383, 1210146474039168, 1742246422343683, 1403839361379025, 417189490895736 }, + { 22727256592983, 168471543384997, 1324340989803650, 1839310709638189, 504999476432775 } + }, + { + { 1313240518756327, 1721896294296942, 52263574587266, 2065069734239232, 804910473424630 }, + { 1337466662091884, 1287645354669772, 2018019646776184, 652181229374245, 898011753211715 }, + { 1969792547910734, 779969968247557, 2011350094423418, 1823964252907487, 1058949448296945 } + }, + { + { 207343737062002, 1118176942430253, 758894594548164, 806764629546266, 1157700123092949 }, + { 1273565321399022, 1638509681964574, 759235866488935, 666015124346707, 897983460943405 }, + { 1717263794012298, 1059601762860786, 1837819172257618, 1054130665797229, 680893204263559 } + } +}, +{ /* 30/31 */ + { + { 2237039662793603, 2249022333361206, 2058613546633703, 149454094845279, 2215176649164582 }, + { 79472182719605, 1851130257050174, 1825744808933107, 821667333481068, 781795293511946 }, + { 755822026485370, 152464789723500, 1178207602290608, 410307889503239, 156581253571278 } + }, + { + { 1418185496130297, 484520167728613, 1646737281442950, 1401487684670265, 1349185550126961 }, + { 1495380034400429, 325049476417173, 46346894893933, 1553408840354856, 828980101835683 }, + { 1280337889310282, 2070832742866672, 1640940617225222, 2098284908289951, 450929509534434 } + }, + { + { 407703353998781, 126572141483652, 286039827513621, 1999255076709338, 2030511179441770 }, + { 1254958221100483, 1153235960999843, 942907704968834, 637105404087392, 1149293270147267 }, + { 894249020470196, 400291701616810, 406878712230981, 1599128793487393, 1145868722604026 } + }, + { + { 1497955250203334, 110116344653260, 1128535642171976, 1900106496009660, 129792717460909 }, + { 452487513298665, 1352120549024569, 1173495883910956, 1999111705922009, 367328130454226 }, + { 1717539401269642, 1475188995688487, 891921989653942, 836824441505699, 1885988485608364 } + }, + { + { 1241784121422547, 187337051947583, 1118481812236193, 428747751936362, 30358898927325 }, + { 2022432361201842, 1088816090685051, 1977843398539868, 1854834215890724, 564238862029357 }, + { 938868489100585, 1100285072929025, 1017806255688848, 1957262154788833, 152787950560442 } + }, + { + { 867319417678923, 620471962942542, 226032203305716, 342001443957629, 1761675818237336 }, + { 1295072362439987, 931227904689414, 1355731432641687, 922235735834035, 892227229410209 }, + { 1680989767906154, 535362787031440, 2136691276706570, 1942228485381244, 1267350086882274 } + }, + { + { 366018233770527, 432660629755596, 126409707644535, 1973842949591662, 645627343442376 }, + { 535509430575217, 546885533737322, 1524675609547799, 2138095752851703, 1260738089896827 }, + { 1159906385590467, 2198530004321610, 714559485023225, 81880727882151, 1484020820037082 } + }, + { + { 1377485731340769, 2046328105512000, 1802058637158797, 62146136768173, 1356993908853901 }, + { 2013612215646735, 1830770575920375, 536135310219832, 609272325580394, 270684344495013 }, + { 1237542585982777, 2228682050256790, 1385281931622824, 593183794882890, 493654978552689 } + } +}, +{ /* 31/31 */ + { + { 47341488007760, 1891414891220257, 983894663308928, 176161768286818, 1126261115179708 }, + { 1694030170963455, 502038567066200, 1691160065225467, 949628319562187, 275110186693066 }, + { 1124515748676336, 1661673816593408, 1499640319059718, 1584929449166988, 558148594103306 } + }, + { + { 1784525599998356, 1619698033617383, 2097300287550715, 258265458103756, 1905684794832758 }, + { 1288941072872766, 931787902039402, 190731008859042, 2006859954667190, 1005931482221702 }, + { 1465551264822703, 152905080555927, 680334307368453, 173227184634745, 666407097159852 } + }, + { + { 2111017076203943, 1378760485794347, 1248583954016456, 1352289194864422, 1895180776543896 }, + { 171348223915638, 662766099800389, 462338943760497, 466917763340314, 656911292869115 }, + { 488623681976577, 866497561541722, 1708105560937768, 1673781214218839, 1506146329818807 } + }, + { + { 160425464456957, 950394373239689, 430497123340934, 711676555398832, 320964687779005 }, + { 988979367990485, 1359729327576302, 1301834257246029, 294141160829308, 29348272277475 }, + { 1434382743317910, 100082049942065, 221102347892623, 186982837860588, 1305765053501834 } + }, + { + { 2205916462268190, 499863829790820, 961960554686616, 158062762756985, 1841471168298305 }, + { 1191737341426592, 1847042034978363, 1382213545049056, 1039952395710448, 788812858896859 }, + { 1346965964571152, 1291881610839830, 2142916164336056, 786821641205979, 1571709146321039 } + }, + { + { 787164375951248, 202869205373189, 1356590421032140, 1431233331032510, 786341368775957 }, + { 492448143532951, 304105152670757, 1761767168301056, 233782684697790, 1981295323106089 }, + { 665807507761866, 1343384868355425, 895831046139653, 439338948736892, 1986828765695105 } + }, + { + { 756096210874553, 1721699973539149, 258765301727885, 1390588532210645, 1212530909934781 }, + { 852891097972275, 1816988871354562, 1543772755726524, 1174710635522444, 202129090724628 }, + { 1205281565824323, 22430498399418, 992947814485516, 1392458699738672, 688441466734558 } + }, + { + { 1050627428414972, 1955849529137135, 2171162376368357, 91745868298214, 447733118757826 }, + { 1287181461435438, 622722465530711, 880952150571872, 741035693459198, 311565274989772 }, + { 1003649078149734, 545233927396469, 1849786171789880, 1318943684880434, 280345687170552 } + } +} diff --git a/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/base2.h b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/base2.h new file mode 100644 index 0000000000..d088241657 --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/base2.h @@ -0,0 +1,40 @@ +{ + { 1288382639258501, 245678601348599, 269427782077623, 1462984067271730, 137412439391563 }, + { 62697248952638, 204681361388450, 631292143396476, 338455783676468, 1213667448819585 }, + { 301289933810280, 1259582250014073, 1422107436869536, 796239922652654, 1953934009299142 } +}, +{ + { 1601611775252272, 1720807796594148, 1132070835939856, 1260455018889551, 2147779492816911 }, + { 316559037616741, 2177824224946892, 1459442586438991, 1461528397712656, 751590696113597 }, + { 1850748884277385, 1200145853858453, 1068094770532492, 672251375690438, 1586055907191707 } +}, +{ + { 769950342298419, 132954430919746, 844085933195555, 974092374476333, 726076285546016 }, + { 425251763115706, 608463272472562, 442562545713235, 837766094556764, 374555092627893 }, + { 1086255230780037, 274979815921559, 1960002765731872, 929474102396301, 1190409889297339 } +}, +{ + { 665000864555967, 2065379846933859, 370231110385876, 350988370788628, 1233371373142985 }, + { 2019367628972465, 676711900706637, 110710997811333, 1108646842542025, 517791959672113 }, + { 965130719900578, 247011430587952, 526356006571389, 91986625355052, 2157223321444601 } +}, +{ + { 1802695059465007, 1664899123557221, 593559490740857, 2160434469266659, 927570450755031 }, + { 1725674970513508, 1933645953859181, 1542344539275782, 1767788773573747, 1297447965928905 }, + { 1381809363726107, 1430341051343062, 2061843536018959, 1551778050872521, 2036394857967624 } +}, +{ + { 1970894096313054, 528066325833207, 1619374932191227, 2207306624415883, 1169170329061080 }, + { 2070390218572616, 1458919061857835, 624171843017421, 1055332792707765, 433987520732508 }, + { 893653801273833, 1168026499324677, 1242553501121234, 1306366254304474, 1086752658510815 } +}, +{ + { 213454002618221, 939771523987438, 1159882208056014, 317388369627517, 621213314200687 }, + { 1971678598905747, 338026507889165, 762398079972271, 655096486107477, 42299032696322 }, + { 177130678690680, 1754759263300204, 1864311296286618, 1180675631479880, 1292726903152791 } +}, +{ + { 1913163449625248, 460779200291993, 2193883288642314, 1008900146920800, 1721983679009502 }, + { 1070401523076875, 1272492007800961, 1910153608563310, 2075579521696771, 1191169788841221 }, + { 692896803108118, 500174642072499, 2068223309439677, 1162190621851337, 1426986007309901 } +} diff --git a/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/constants.h b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/constants.h new file mode 100644 index 0000000000..53b75c6b45 --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/constants.h @@ -0,0 +1,21 @@ +/* 37095705934669439343138083508754565189542113879843219016388785533085940283555 */ +static const fe25519 d = { + 929955233495203, 466365720129213, 1662059464998953, 2033849074728123, 1442794654840575 +}; + +/* 2 * d = + * 16295367250680780974490674513165176452449235426866156013048779062215315747161 + */ +static const fe25519 d2 = { + 1859910466990425, 932731440258426, 1072319116312658, 1815898335770999, 633789495995903 +}; + +/* sqrt(-1) */ +static const fe25519 sqrtm1 = { + 1718705420411056, 234908883556509, 2233514472574048, 2117202627021982, 765476049583133 +}; + +/* A = 486662 */ +static const fe25519 curve25519_A = { + 486662, 0, 0, 0, 0 +}; diff --git a/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/fe.h b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/fe.h new file mode 100644 index 0000000000..de876264c8 --- /dev/null +++ b/libs/libsodium/src/crypto_core/ed25519/ref10/fe_51/fe.h @@ -0,0 +1,116 @@ +/* + Ignores top bit of h. + */ + +void +fe25519_frombytes(fe25519 h, const unsigned char *s) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint64_t h0, h1, h2, h3, h4; + + h0 = (LOAD64_LE(s ) ) & mask; + h1 = (LOAD64_LE(s + 6) >> 3) & mask; + h2 = (LOAD64_LE(s + 12) >> 6) & mask; + h3 = (LOAD64_LE(s + 19) >> 1) & mask; + h4 = (LOAD64_LE(s + 24) >> 12) & mask; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; +} + +static void +fe25519_reduce(fe25519 h, const fe25519 f) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t t[5]; + + t[0] = f[0]; + t[1] = f[1]; + t[2] = f[2]; + t[3] = f[3]; + t[4] = f[4]; + + t[1] += t[0] >> 51; + t[0] &= mask; + t[2] += t[1] >> 51; + t[1] &= mask; + t[3] += t[2] >> 51; + t[2] &= mask; + t[4] += t[3] >> 51; + t[3] &= mask; + t[0] += 19 * (t[4] >> 51); + t[4] &= mask; + + t[1] += t[0] >> 51; + t[0] &= mask; + t[2] += t[1] >> 51; + t[1] &= mask; + t[3] += t[2] >> 51; + t[2] &= mask; + t[4] += t[3] >> 51; + t[3] &= mask; + t[0] += 19 * (t[4] >> 51); + t[4] &= mask; + + /* now t is between 0 and 2^255-1, properly carried. */ + /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */ + + t[0] += 19ULL; + + t[1] += t[0] >> 51; + t[0] &= mask; + t[2] += t[1] >> 51; + t[1] &= mask; + t[3] += t[2] >> 51; + t[2] &= mask; + t[4] += t[3] >> 51; + t[3] &= mask; + t[0] += 19ULL * (t[4] >> 51); + t[4] &= mask; + + /* now between 19 and 2^255-1 in both cases, and offset by 19. */ + + t[0] += 0x8000000000000 - 19ULL; + t[1] += 0x8000000000000 - 1ULL; + t[2] += 0x8000000000000 - 1ULL; + t[3] += 0x8000000000000 - 1ULL; + t[4] += 0x8000000000000 - 1ULL; + + /* now between 2^255 and 2^256-20, and offset by 2^255. */ + + t[1] += t[0] >> 51; + t[0] &= mask; + t[2] += t[1] >> 51; + t[1] &= mask; + t[3] += t[2] >> 51; + t[2] &= mask; + t[4] += t[3] >> 51; + t[3] &= mask; + t[4] &= mask; + + h[0] = t[0]; + h[1] = t[1]; + h[2] = t[2]; + h[3] = t[3]; + h[4] = t[4]; +} + +void +fe25519_tobytes(unsigned char *s, const fe25519 h) +{ + fe25519 t; + uint64_t t0, t1, t2, t3; + + fe25519_reduce(t, h); + t0 = t[0] | (t[1] << 51); + t1 = (t[1] >> 13) | (t[2] << 38); + t2 = (t[2] >> 26) | (t[3] << 25); + t3 = (t[3] >> 39) | (t[4] << 12); + STORE64_LE(s + 0, t0); + STORE64_LE(s + 8, t1); + STORE64_LE(s + 16, t2); + STORE64_LE(s + 24, t3); +} diff --git a/libs/libsodium/src/crypto_core/hchacha20/core_hchacha20.c b/libs/libsodium/src/crypto_core/hchacha20/core_hchacha20.c new file mode 100644 index 0000000000..39ab26a6da --- /dev/null +++ b/libs/libsodium/src/crypto_core/hchacha20/core_hchacha20.c @@ -0,0 +1,93 @@ + +#include +#include + +#include "crypto_core_hchacha20.h" +#include "private/common.h" + +#define QUARTERROUND(A, B, C, D) \ + do { \ + A += B; D = ROTL32(D ^ A, 16); \ + C += D; B = ROTL32(B ^ C, 12); \ + A += B; D = ROTL32(D ^ A, 8); \ + C += D; B = ROTL32(B ^ C, 7); \ + } while(0) + +int +crypto_core_hchacha20(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c) +{ + int i; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7; + uint32_t x8, x9, x10, x11, x12, x13, x14, x15; + + if (c == NULL) { + x0 = 0x61707865; + x1 = 0x3320646e; + x2 = 0x79622d32; + x3 = 0x6b206574; + } else { + x0 = LOAD32_LE(c + 0); + x1 = LOAD32_LE(c + 4); + x2 = LOAD32_LE(c + 8); + x3 = LOAD32_LE(c + 12); + } + x4 = LOAD32_LE(k + 0); + x5 = LOAD32_LE(k + 4); + x6 = LOAD32_LE(k + 8); + x7 = LOAD32_LE(k + 12); + x8 = LOAD32_LE(k + 16); + x9 = LOAD32_LE(k + 20); + x10 = LOAD32_LE(k + 24); + x11 = LOAD32_LE(k + 28); + x12 = LOAD32_LE(in + 0); + x13 = LOAD32_LE(in + 4); + x14 = LOAD32_LE(in + 8); + x15 = LOAD32_LE(in + 12); + + for (i = 0; i < 10; i++) { + QUARTERROUND(x0, x4, x8, x12); + QUARTERROUND(x1, x5, x9, x13); + QUARTERROUND(x2, x6, x10, x14); + QUARTERROUND(x3, x7, x11, x15); + QUARTERROUND(x0, x5, x10, x15); + QUARTERROUND(x1, x6, x11, x12); + QUARTERROUND(x2, x7, x8, x13); + QUARTERROUND(x3, x4, x9, x14); + } + + STORE32_LE(out + 0, x0); + STORE32_LE(out + 4, x1); + STORE32_LE(out + 8, x2); + STORE32_LE(out + 12, x3); + STORE32_LE(out + 16, x12); + STORE32_LE(out + 20, x13); + STORE32_LE(out + 24, x14); + STORE32_LE(out + 28, x15); + + return 0; +} + +size_t +crypto_core_hchacha20_outputbytes(void) +{ + return crypto_core_hchacha20_OUTPUTBYTES; +} + +size_t +crypto_core_hchacha20_inputbytes(void) +{ + return crypto_core_hchacha20_INPUTBYTES; +} + +size_t +crypto_core_hchacha20_keybytes(void) +{ + return crypto_core_hchacha20_KEYBYTES; +} + +size_t +crypto_core_hchacha20_constbytes(void) +{ + return crypto_core_hchacha20_CONSTBYTES; +} diff --git a/libs/libsodium/src/crypto_core/hsalsa20/core_hsalsa20.c b/libs/libsodium/src/crypto_core/hsalsa20/core_hsalsa20.c new file mode 100644 index 0000000000..37c4923af6 --- /dev/null +++ b/libs/libsodium/src/crypto_core/hsalsa20/core_hsalsa20.c @@ -0,0 +1,21 @@ +#include "crypto_core_hsalsa20.h" + +size_t +crypto_core_hsalsa20_outputbytes(void) { + return crypto_core_hsalsa20_OUTPUTBYTES; +} + +size_t +crypto_core_hsalsa20_inputbytes(void) { + return crypto_core_hsalsa20_INPUTBYTES; +} + +size_t +crypto_core_hsalsa20_keybytes(void) { + return crypto_core_hsalsa20_KEYBYTES; +} + +size_t +crypto_core_hsalsa20_constbytes(void) { + return crypto_core_hsalsa20_CONSTBYTES; +} diff --git a/libs/libsodium/src/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c b/libs/libsodium/src/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c new file mode 100644 index 0000000000..1d1220fee2 --- /dev/null +++ b/libs/libsodium/src/crypto_core/hsalsa20/ref2/core_hsalsa20_ref2.c @@ -0,0 +1,95 @@ +/* +version 20080912 +D. J. Bernstein +Public domain. +*/ + +#include +#include + +#include "crypto_core_hsalsa20.h" +#include "private/common.h" + +#define ROUNDS 20 +#define U32C(v) (v##U) + +int +crypto_core_hsalsa20(unsigned char *out, + const unsigned char *in, + const unsigned char *k, + const unsigned char *c) +{ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, + x9, x10, x11, x12, x13, x14, x15; + int i; + + if (c == NULL) { + x0 = U32C(0x61707865); + x5 = U32C(0x3320646e); + x10 = U32C(0x79622d32); + x15 = U32C(0x6b206574); + } else { + x0 = LOAD32_LE(c + 0); + x5 = LOAD32_LE(c + 4); + x10 = LOAD32_LE(c + 8); + x15 = LOAD32_LE(c + 12); + } + x1 = LOAD32_LE(k + 0); + x2 = LOAD32_LE(k + 4); + x3 = LOAD32_LE(k + 8); + x4 = LOAD32_LE(k + 12); + x11 = LOAD32_LE(k + 16); + x12 = LOAD32_LE(k + 20); + x13 = LOAD32_LE(k + 24); + x14 = LOAD32_LE(k + 28); + x6 = LOAD32_LE(in + 0); + x7 = LOAD32_LE(in + 4); + x8 = LOAD32_LE(in + 8); + x9 = LOAD32_LE(in + 12); + + for (i = ROUNDS; i > 0; i -= 2) { + x4 ^= ROTL32(x0 + x12, 7); + x8 ^= ROTL32(x4 + x0, 9); + x12 ^= ROTL32(x8 + x4, 13); + x0 ^= ROTL32(x12 + x8, 18); + x9 ^= ROTL32(x5 + x1, 7); + x13 ^= ROTL32(x9 + x5, 9); + x1 ^= ROTL32(x13 + x9, 13); + x5 ^= ROTL32(x1 + x13, 18); + x14 ^= ROTL32(x10 + x6, 7); + x2 ^= ROTL32(x14 + x10, 9); + x6 ^= ROTL32(x2 + x14, 13); + x10 ^= ROTL32(x6 + x2, 18); + x3 ^= ROTL32(x15 + x11, 7); + x7 ^= ROTL32(x3 + x15, 9); + x11 ^= ROTL32(x7 + x3, 13); + x15 ^= ROTL32(x11 + x7, 18); + x1 ^= ROTL32(x0 + x3, 7); + x2 ^= ROTL32(x1 + x0, 9); + x3 ^= ROTL32(x2 + x1, 13); + x0 ^= ROTL32(x3 + x2, 18); + x6 ^= ROTL32(x5 + x4, 7); + x7 ^= ROTL32(x6 + x5, 9); + x4 ^= ROTL32(x7 + x6, 13); + x5 ^= ROTL32(x4 + x7, 18); + x11 ^= ROTL32(x10 + x9, 7); + x8 ^= ROTL32(x11 + x10, 9); + x9 ^= ROTL32(x8 + x11, 13); + x10 ^= ROTL32(x9 + x8, 18); + x12 ^= ROTL32(x15 + x14, 7); + x13 ^= ROTL32(x12 + x15, 9); + x14 ^= ROTL32(x13 + x12, 13); + x15 ^= ROTL32(x14 + x13, 18); + } + + STORE32_LE(out + 0, x0); + STORE32_LE(out + 4, x5); + STORE32_LE(out + 8, x10); + STORE32_LE(out + 12, x15); + STORE32_LE(out + 16, x6); + STORE32_LE(out + 20, x7); + STORE32_LE(out + 24, x8); + STORE32_LE(out + 28, x9); + + return 0; +} diff --git a/libs/libsodium/src/crypto_core/salsa/ref/core_salsa_ref.c b/libs/libsodium/src/crypto_core/salsa/ref/core_salsa_ref.c new file mode 100644 index 0000000000..a077d7f4db --- /dev/null +++ b/libs/libsodium/src/crypto_core/salsa/ref/core_salsa_ref.c @@ -0,0 +1,195 @@ + +#include +#include + +#include "crypto_core_salsa20.h" +#include "crypto_core_salsa2012.h" +#include "crypto_core_salsa208.h" +#include "private/common.h" + +static void +crypto_core_salsa(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c, + const int rounds) +{ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, + x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, + j15; + int i; + + j0 = x0 = 0x61707865; + j5 = x5 = 0x3320646e; + j10 = x10 = 0x79622d32; + j15 = x15 = 0x6b206574; + if (c != NULL) { + j0 = x0 = LOAD32_LE(c + 0); + j5 = x5 = LOAD32_LE(c + 4); + j10 = x10 = LOAD32_LE(c + 8); + j15 = x15 = LOAD32_LE(c + 12); + } + j1 = x1 = LOAD32_LE(k + 0); + j2 = x2 = LOAD32_LE(k + 4); + j3 = x3 = LOAD32_LE(k + 8); + j4 = x4 = LOAD32_LE(k + 12); + j11 = x11 = LOAD32_LE(k + 16); + j12 = x12 = LOAD32_LE(k + 20); + j13 = x13 = LOAD32_LE(k + 24); + j14 = x14 = LOAD32_LE(k + 28); + + j6 = x6 = LOAD32_LE(in + 0); + j7 = x7 = LOAD32_LE(in + 4); + j8 = x8 = LOAD32_LE(in + 8); + j9 = x9 = LOAD32_LE(in + 12); + + for (i = 0; i < rounds; i += 2) { + x4 ^= ROTL32(x0 + x12, 7); + x8 ^= ROTL32(x4 + x0, 9); + x12 ^= ROTL32(x8 + x4, 13); + x0 ^= ROTL32(x12 + x8, 18); + x9 ^= ROTL32(x5 + x1, 7); + x13 ^= ROTL32(x9 + x5, 9); + x1 ^= ROTL32(x13 + x9, 13); + x5 ^= ROTL32(x1 + x13, 18); + x14 ^= ROTL32(x10 + x6, 7); + x2 ^= ROTL32(x14 + x10, 9); + x6 ^= ROTL32(x2 + x14, 13); + x10 ^= ROTL32(x6 + x2, 18); + x3 ^= ROTL32(x15 + x11, 7); + x7 ^= ROTL32(x3 + x15, 9); + x11 ^= ROTL32(x7 + x3, 13); + x15 ^= ROTL32(x11 + x7, 18); + x1 ^= ROTL32(x0 + x3, 7); + x2 ^= ROTL32(x1 + x0, 9); + x3 ^= ROTL32(x2 + x1, 13); + x0 ^= ROTL32(x3 + x2, 18); + x6 ^= ROTL32(x5 + x4, 7); + x7 ^= ROTL32(x6 + x5, 9); + x4 ^= ROTL32(x7 + x6, 13); + x5 ^= ROTL32(x4 + x7, 18); + x11 ^= ROTL32(x10 + x9, 7); + x8 ^= ROTL32(x11 + x10, 9); + x9 ^= ROTL32(x8 + x11, 13); + x10 ^= ROTL32(x9 + x8, 18); + x12 ^= ROTL32(x15 + x14, 7); + x13 ^= ROTL32(x12 + x15, 9); + x14 ^= ROTL32(x13 + x12, 13); + x15 ^= ROTL32(x14 + x13, 18); + } + STORE32_LE(out + 0, x0 + j0); + STORE32_LE(out + 4, x1 + j1); + STORE32_LE(out + 8, x2 + j2); + STORE32_LE(out + 12, x3 + j3); + STORE32_LE(out + 16, x4 + j4); + STORE32_LE(out + 20, x5 + j5); + STORE32_LE(out + 24, x6 + j6); + STORE32_LE(out + 28, x7 + j7); + STORE32_LE(out + 32, x8 + j8); + STORE32_LE(out + 36, x9 + j9); + STORE32_LE(out + 40, x10 + j10); + STORE32_LE(out + 44, x11 + j11); + STORE32_LE(out + 48, x12 + j12); + STORE32_LE(out + 52, x13 + j13); + STORE32_LE(out + 56, x14 + j14); + STORE32_LE(out + 60, x15 + j15); +} + +int +crypto_core_salsa20(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c) +{ + crypto_core_salsa(out, in, k, c, 20); + return 0; +} + +size_t +crypto_core_salsa20_outputbytes(void) +{ + return crypto_core_salsa20_OUTPUTBYTES; +} + +size_t +crypto_core_salsa20_inputbytes(void) +{ + return crypto_core_salsa20_INPUTBYTES; +} + +size_t +crypto_core_salsa20_keybytes(void) +{ + return crypto_core_salsa20_KEYBYTES; +} + +size_t +crypto_core_salsa20_constbytes(void) +{ + return crypto_core_salsa20_CONSTBYTES; +} + +#ifndef MINIMAL + +int +crypto_core_salsa2012(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c) +{ + crypto_core_salsa(out, in, k, c, 12); + return 0; +} + +size_t +crypto_core_salsa2012_outputbytes(void) +{ + return crypto_core_salsa2012_OUTPUTBYTES; +} + +size_t +crypto_core_salsa2012_inputbytes(void) +{ + return crypto_core_salsa2012_INPUTBYTES; +} + +size_t +crypto_core_salsa2012_keybytes(void) +{ + return crypto_core_salsa2012_KEYBYTES; +} + +size_t +crypto_core_salsa2012_constbytes(void) +{ + return crypto_core_salsa2012_CONSTBYTES; +} + +int +crypto_core_salsa208(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c) +{ + crypto_core_salsa(out, in, k, c, 8); + return 0; +} + +size_t +crypto_core_salsa208_outputbytes(void) +{ + return crypto_core_salsa208_OUTPUTBYTES; +} + +size_t +crypto_core_salsa208_inputbytes(void) +{ + return crypto_core_salsa208_INPUTBYTES; +} + +size_t +crypto_core_salsa208_keybytes(void) +{ + return crypto_core_salsa208_KEYBYTES; +} + +size_t +crypto_core_salsa208_constbytes(void) +{ + return crypto_core_salsa208_CONSTBYTES; +} + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/generichash_blake2.c b/libs/libsodium/src/crypto_generichash/blake2b/generichash_blake2.c new file mode 100644 index 0000000000..781d4c584e --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/generichash_blake2.c @@ -0,0 +1,55 @@ +#include "crypto_generichash_blake2b.h" +#include "randombytes.h" + +size_t +crypto_generichash_blake2b_bytes_min(void) { + return crypto_generichash_blake2b_BYTES_MIN; +} + +size_t +crypto_generichash_blake2b_bytes_max(void) { + return crypto_generichash_blake2b_BYTES_MAX; +} + +size_t +crypto_generichash_blake2b_bytes(void) { + return crypto_generichash_blake2b_BYTES; +} + +size_t +crypto_generichash_blake2b_keybytes_min(void) { + return crypto_generichash_blake2b_KEYBYTES_MIN; +} + +size_t +crypto_generichash_blake2b_keybytes_max(void) { + return crypto_generichash_blake2b_KEYBYTES_MAX; +} + +size_t +crypto_generichash_blake2b_keybytes(void) { + return crypto_generichash_blake2b_KEYBYTES; +} + +size_t +crypto_generichash_blake2b_saltbytes(void) { + return crypto_generichash_blake2b_SALTBYTES; +} + +size_t +crypto_generichash_blake2b_personalbytes(void) { + return crypto_generichash_blake2b_PERSONALBYTES; +} + +size_t +crypto_generichash_blake2b_statebytes(void) +{ + return (sizeof(crypto_generichash_blake2b_state) + (size_t) 63U) + & ~(size_t) 63U; +} + +void +crypto_generichash_blake2b_keygen(unsigned char k[crypto_generichash_blake2b_KEYBYTES]) +{ + randombytes_buf(k, crypto_generichash_blake2b_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2.h b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2.h new file mode 100644 index 0000000000..c6c4fccbb7 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2.h @@ -0,0 +1,109 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + All code is triple-licensed under the + [CC0](http://creativecommons.org/publicdomain/zero/1.0), the + [OpenSSL Licence](https://www.openssl.org/source/license.html), or + the [Apache Public License 2.0](http://www.apache.org/licenses/LICENSE-2.0), + at your choosing. + */ + +#ifndef blake2_H +#define blake2_H + +#include +#include + +#include "crypto_generichash_blake2b.h" +#include "export.h" + +#define blake2b_init_param crypto_generichash_blake2b__init_param +#define blake2b_init crypto_generichash_blake2b__init +#define blake2b_init_salt_personal \ + crypto_generichash_blake2b__init_salt_personal +#define blake2b_init_key crypto_generichash_blake2b__init_key +#define blake2b_init_key_salt_personal \ + crypto_generichash_blake2b__init_key_salt_personal +#define blake2b_update crypto_generichash_blake2b__update +#define blake2b_final crypto_generichash_blake2b__final +#define blake2b crypto_generichash_blake2b__blake2b +#define blake2b_salt_personal crypto_generichash_blake2b__blake2b_salt_personal +#define blake2b_pick_best_implementation \ + crypto_generichash_blake2b__pick_best_implementation + +enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 +}; + +#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma pack(1) +#else +#pragma pack(push, 1) +#endif + +typedef struct blake2b_param_ { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint8_t leaf_length[4]; /* 8 */ + uint8_t node_offset[8]; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ +} blake2b_param; + +typedef crypto_generichash_blake2b_state blake2b_state; + +#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma pack() +#else +#pragma pack(pop) +#endif + +/* Streaming API */ +int blake2b_init(blake2b_state *S, const uint8_t outlen); +int blake2b_init_salt_personal(blake2b_state *S, const uint8_t outlen, + const void *salt, const void *personal); +int blake2b_init_key(blake2b_state *S, const uint8_t outlen, const void *key, + const uint8_t keylen); +int blake2b_init_key_salt_personal(blake2b_state *S, const uint8_t outlen, + const void *key, const uint8_t keylen, + const void *salt, const void *personal); +int blake2b_init_param(blake2b_state *S, const blake2b_param *P); +int blake2b_update(blake2b_state *S, const uint8_t *in, uint64_t inlen); +int blake2b_final(blake2b_state *S, uint8_t *out, uint8_t outlen); + +/* Simple API */ +int blake2b(uint8_t *out, const void *in, const void *key, const uint8_t outlen, + const uint64_t inlen, uint8_t keylen); +int blake2b_salt_personal(uint8_t *out, const void *in, const void *key, + const uint8_t outlen, const uint64_t inlen, + uint8_t keylen, const void *salt, + const void *personal); + +typedef int (*blake2b_compress_fn)(blake2b_state *S, + const uint8_t block[BLAKE2B_BLOCKBYTES]); +int blake2b_pick_best_implementation(void); +int blake2b_compress_ref(blake2b_state *S, + const uint8_t block[BLAKE2B_BLOCKBYTES]); +int blake2b_compress_ssse3(blake2b_state *S, + const uint8_t block[BLAKE2B_BLOCKBYTES]); +int blake2b_compress_sse41(blake2b_state *S, + const uint8_t block[BLAKE2B_BLOCKBYTES]); +int blake2b_compress_avx2(blake2b_state *S, + const uint8_t block[BLAKE2B_BLOCKBYTES]); + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c new file mode 100644 index 0000000000..7cb41fb6e7 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-avx2.c @@ -0,0 +1,49 @@ + +#define BLAKE2_USE_SSSE3 +#define BLAKE2_USE_SSE41 +#define BLAKE2_USE_AVX2 + +#include +#include + +#include "blake2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" + +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_EMMINTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# pragma GCC target("sse4.1") +# pragma GCC target("avx2") +# endif + +# include +# include +# include +# include + +# include "blake2b-compress-avx2.h" + +CRYPTO_ALIGN(64) +static const uint64_t blake2b_IV[8] = { + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +int +blake2b_compress_avx2(blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES]) +{ + __m256i a = LOADU(&S->h[0]); + __m256i b = LOADU(&S->h[4]); + BLAKE2B_COMPRESS_V1(a, b, block, S->t[0], S->t[1], S->f[0], S->f[1]); + STOREU(&S->h[0], a); + STOREU(&S->h[4], b); + + return 0; +} + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-avx2.h b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-avx2.h new file mode 100644 index 0000000000..21acb2fa0c --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-avx2.h @@ -0,0 +1,140 @@ + +#ifndef blake2b_compress_avx2_H +#define blake2b_compress_avx2_H + +#define LOAD128(p) _mm_load_si128((__m128i *) (p)) +#define STORE128(p, r) _mm_store_si128((__m128i *) (p), r) + +#define LOADU128(p) _mm_loadu_si128((__m128i *) (p)) +#define STOREU128(p, r) _mm_storeu_si128((__m128i *) (p), r) + +#define LOAD(p) _mm256_load_si256((__m256i *) (p)) +#define STORE(p, r) _mm256_store_si256((__m256i *) (p), r) + +#define LOADU(p) _mm256_loadu_si256((__m256i *) (p)) +#define STOREU(p, r) _mm256_storeu_si256((__m256i *) (p), r) + +static inline uint64_t +LOADU64(const void *p) +{ + uint64_t v; + memcpy(&v, p, sizeof v); + return v; +} + +#define ROTATE16 \ + _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, \ + 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9) + +#define ROTATE24 \ + _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, \ + 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10) + +#define ADD(a, b) _mm256_add_epi64(a, b) +#define SUB(a, b) _mm256_sub_epi64(a, b) + +#define XOR(a, b) _mm256_xor_si256(a, b) +#define AND(a, b) _mm256_and_si256(a, b) +#define OR(a, b) _mm256_or_si256(a, b) + +#define ROT32(x) _mm256_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) +#define ROT24(x) _mm256_shuffle_epi8((x), ROTATE24) +#define ROT16(x) _mm256_shuffle_epi8((x), ROTATE16) +#define ROT63(x) _mm256_or_si256(_mm256_srli_epi64((x), 63), ADD((x), (x))) + +#define BLAKE2B_G1_V1(a, b, c, d, m) \ + do { \ + a = ADD(a, m); \ + a = ADD(a, b); \ + d = XOR(d, a); \ + d = ROT32(d); \ + c = ADD(c, d); \ + b = XOR(b, c); \ + b = ROT24(b); \ + } while (0) + +#define BLAKE2B_G2_V1(a, b, c, d, m) \ + do { \ + a = ADD(a, m); \ + a = ADD(a, b); \ + d = XOR(d, a); \ + d = ROT16(d); \ + c = ADD(c, d); \ + b = XOR(b, c); \ + b = ROT63(b); \ + } while (0) + +#define BLAKE2B_DIAG_V1(a, b, c, d) \ + do { \ + d = _mm256_permute4x64_epi64(d, _MM_SHUFFLE(2, 1, 0, 3)); \ + c = _mm256_permute4x64_epi64(c, _MM_SHUFFLE(1, 0, 3, 2)); \ + b = _mm256_permute4x64_epi64(b, _MM_SHUFFLE(0, 3, 2, 1)); \ + } while (0) + +#define BLAKE2B_UNDIAG_V1(a, b, c, d) \ + do { \ + d = _mm256_permute4x64_epi64(d, _MM_SHUFFLE(0, 3, 2, 1)); \ + c = _mm256_permute4x64_epi64(c, _MM_SHUFFLE(1, 0, 3, 2)); \ + b = _mm256_permute4x64_epi64(b, _MM_SHUFFLE(2, 1, 0, 3)); \ + } while (0) + +#include "blake2b-load-avx2.h" + +#define BLAKE2B_ROUND_V1(a, b, c, d, r, m) \ + do { \ + __m256i b0; \ + BLAKE2B_LOAD_MSG_##r##_1(b0); \ + BLAKE2B_G1_V1(a, b, c, d, b0); \ + BLAKE2B_LOAD_MSG_##r##_2(b0); \ + BLAKE2B_G2_V1(a, b, c, d, b0); \ + BLAKE2B_DIAG_V1(a, b, c, d); \ + BLAKE2B_LOAD_MSG_##r##_3(b0); \ + BLAKE2B_G1_V1(a, b, c, d, b0); \ + BLAKE2B_LOAD_MSG_##r##_4(b0); \ + BLAKE2B_G2_V1(a, b, c, d, b0); \ + BLAKE2B_UNDIAG_V1(a, b, c, d); \ + } while (0) + +#define BLAKE2B_ROUNDS_V1(a, b, c, d, m) \ + do { \ + BLAKE2B_ROUND_V1(a, b, c, d, 0, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 1, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 2, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 3, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 4, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 5, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 6, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 7, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 8, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 9, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 10, (m)); \ + BLAKE2B_ROUND_V1(a, b, c, d, 11, (m)); \ + } while (0) + +#define DECLARE_MESSAGE_WORDS(m) \ + const __m256i m0 = _mm256_broadcastsi128_si256(LOADU128((m) + 0)); \ + const __m256i m1 = _mm256_broadcastsi128_si256(LOADU128((m) + 16)); \ + const __m256i m2 = _mm256_broadcastsi128_si256(LOADU128((m) + 32)); \ + const __m256i m3 = _mm256_broadcastsi128_si256(LOADU128((m) + 48)); \ + const __m256i m4 = _mm256_broadcastsi128_si256(LOADU128((m) + 64)); \ + const __m256i m5 = _mm256_broadcastsi128_si256(LOADU128((m) + 80)); \ + const __m256i m6 = _mm256_broadcastsi128_si256(LOADU128((m) + 96)); \ + const __m256i m7 = _mm256_broadcastsi128_si256(LOADU128((m) + 112)); \ + __m256i t0, t1; + +#define BLAKE2B_COMPRESS_V1(a, b, m, t0, t1, f0, f1) \ + do { \ + DECLARE_MESSAGE_WORDS(m) \ + const __m256i iv0 = a; \ + const __m256i iv1 = b; \ + __m256i c = LOAD(&blake2b_IV[0]); \ + __m256i d = \ + XOR(LOAD(&blake2b_IV[4]), _mm256_set_epi64x(f1, f0, t1, t0)); \ + BLAKE2B_ROUNDS_V1(a, b, c, d, m); \ + a = XOR(a, c); \ + b = XOR(b, d); \ + a = XOR(a, iv0); \ + b = XOR(b, iv1); \ + } while (0) + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ref.c b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ref.c new file mode 100644 index 0000000000..614fa34af7 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ref.c @@ -0,0 +1,93 @@ + +#include +#include + +#include "blake2.h" +#include "private/common.h" + +CRYPTO_ALIGN(64) +static const uint64_t blake2b_IV[8] = { + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const uint8_t blake2b_sigma[12][16] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + +int +blake2b_compress_ref(blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES]) +{ + uint64_t m[16]; + uint64_t v[16]; + int i; + + for (i = 0; i < 16; ++i) + m[i] = LOAD64_LE(block + i * sizeof(m[i])); + + for (i = 0; i < 8; ++i) + v[i] = S->h[i]; + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = S->t[0] ^ blake2b_IV[4]; + v[13] = S->t[1] ^ blake2b_IV[5]; + v[14] = S->f[0] ^ blake2b_IV[6]; + v[15] = S->f[1] ^ blake2b_IV[7]; +#define G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ + d = ROTR64(d ^ a, 32); \ + c = c + d; \ + b = ROTR64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ + d = ROTR64(d ^ a, 16); \ + c = c + d; \ + b = ROTR64(b ^ c, 63); \ + } while (0) +#define ROUND(r) \ + do { \ + G(r, 0, v[0], v[4], v[8], v[12]); \ + G(r, 1, v[1], v[5], v[9], v[13]); \ + G(r, 2, v[2], v[6], v[10], v[14]); \ + G(r, 3, v[3], v[7], v[11], v[15]); \ + G(r, 4, v[0], v[5], v[10], v[15]); \ + G(r, 5, v[1], v[6], v[11], v[12]); \ + G(r, 6, v[2], v[7], v[8], v[13]); \ + G(r, 7, v[3], v[4], v[9], v[14]); \ + } while (0) + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + ROUND(10); + ROUND(11); + + for (i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } + +#undef G +#undef ROUND + return 0; +} diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-sse41.c b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-sse41.c new file mode 100644 index 0000000000..9e5c0c5081 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-sse41.c @@ -0,0 +1,87 @@ + +#define BLAKE2_USE_SSSE3 +#define BLAKE2_USE_SSE41 + +#include +#include + +#include "blake2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" + +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) && \ + defined(HAVE_SMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# pragma GCC target("sse4.1") +# endif + +# include +# include +# include + +# include "blake2b-compress-sse41.h" + +CRYPTO_ALIGN(64) +static const uint64_t blake2b_IV[8] = { + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +int +blake2b_compress_sse41(blake2b_state *S, + const uint8_t block[BLAKE2B_BLOCKBYTES]) +{ + __m128i row1l, row1h; + __m128i row2l, row2h; + __m128i row3l, row3h; + __m128i row4l, row4h; + __m128i b0, b1; + __m128i t0, t1; + const __m128i r16 = + _mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9); + const __m128i r24 = + _mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10); + const __m128i m0 = LOADU(block + 00); + const __m128i m1 = LOADU(block + 16); + const __m128i m2 = LOADU(block + 32); + const __m128i m3 = LOADU(block + 48); + const __m128i m4 = LOADU(block + 64); + const __m128i m5 = LOADU(block + 80); + const __m128i m6 = LOADU(block + 96); + const __m128i m7 = LOADU(block + 112); + row1l = LOADU(&S->h[0]); + row1h = LOADU(&S->h[2]); + row2l = LOADU(&S->h[4]); + row2h = LOADU(&S->h[6]); + row3l = LOADU(&blake2b_IV[0]); + row3h = LOADU(&blake2b_IV[2]); + row4l = _mm_xor_si128(LOADU(&blake2b_IV[4]), LOADU(&S->t[0])); + row4h = _mm_xor_si128(LOADU(&blake2b_IV[6]), LOADU(&S->f[0])); + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + ROUND(10); + ROUND(11); + row1l = _mm_xor_si128(row3l, row1l); + row1h = _mm_xor_si128(row3h, row1h); + STOREU(&S->h[0], _mm_xor_si128(LOADU(&S->h[0]), row1l)); + STOREU(&S->h[2], _mm_xor_si128(LOADU(&S->h[2]), row1h)); + row2l = _mm_xor_si128(row4l, row2l); + row2h = _mm_xor_si128(row4h, row2h); + STOREU(&S->h[4], _mm_xor_si128(LOADU(&S->h[4]), row2l)); + STOREU(&S->h[6], _mm_xor_si128(LOADU(&S->h[6]), row2h)); + return 0; +} + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-sse41.h b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-sse41.h new file mode 100644 index 0000000000..ac78e5bb1e --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-sse41.h @@ -0,0 +1,103 @@ + +#ifndef blake2b_compress_sse41_H +#define blake2b_compress_sse41_H + +#define LOADU(p) _mm_loadu_si128((const __m128i *) (const void *) (p)) +#define STOREU(p, r) _mm_storeu_si128((__m128i *) (void *) (p), r) + +#define _mm_roti_epi64(x, c) \ + (-(c) == 32) \ + ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \ + : (-(c) == 24) \ + ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) \ + ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) \ + ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ + _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ + _mm_slli_epi64((x), 64 - (-(c)))) + +#define G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -32); \ + row4h = _mm_roti_epi64(row4h, -32); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -24); \ + row2h = _mm_roti_epi64(row2h, -24); + +#define G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -16); \ + row4h = _mm_roti_epi64(row4h, -16); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -63); \ + row2h = _mm_roti_epi64(row2h, -63); + +#define DIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h) \ + t0 = _mm_alignr_epi8(row2h, row2l, 8); \ + t1 = _mm_alignr_epi8(row2l, row2h, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4h, row4l, 8); \ + t1 = _mm_alignr_epi8(row4l, row4h, 8); \ + row4l = t1; \ + row4h = t0; + +#define UNDIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h) \ + t0 = _mm_alignr_epi8(row2l, row2h, 8); \ + t1 = _mm_alignr_epi8(row2h, row2l, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4l, row4h, 8); \ + t1 = _mm_alignr_epi8(row4h, row4l, 8); \ + row4l = t1; \ + row4h = t0; + +#include "blake2b-load-sse41.h" + +#define ROUND(r) \ + LOAD_MSG_##r##_1(b0, b1); \ + G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \ + LOAD_MSG_##r##_2(b0, b1); \ + G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \ + DIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + LOAD_MSG_##r##_3(b0, b1); \ + G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \ + LOAD_MSG_##r##_4(b0, b1); \ + G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \ + UNDIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c new file mode 100644 index 0000000000..a207a64d40 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.c @@ -0,0 +1,90 @@ + +#include +#include + +#include "blake2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" + +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# endif + +# include +# include + +# include "blake2b-compress-ssse3.h" + +CRYPTO_ALIGN(64) +static const uint64_t blake2b_IV[8] = { + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +int +blake2b_compress_ssse3(blake2b_state *S, + const uint8_t block[BLAKE2B_BLOCKBYTES]) +{ + __m128i row1l, row1h; + __m128i row2l, row2h; + __m128i row3l, row3h; + __m128i row4l, row4h; + __m128i b0, b1; + __m128i t0, t1; + const __m128i r16 = + _mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9); + const __m128i r24 = + _mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10); + const uint64_t m0 = ((uint64_t *) block)[0]; + const uint64_t m1 = ((uint64_t *) block)[1]; + const uint64_t m2 = ((uint64_t *) block)[2]; + const uint64_t m3 = ((uint64_t *) block)[3]; + const uint64_t m4 = ((uint64_t *) block)[4]; + const uint64_t m5 = ((uint64_t *) block)[5]; + const uint64_t m6 = ((uint64_t *) block)[6]; + const uint64_t m7 = ((uint64_t *) block)[7]; + const uint64_t m8 = ((uint64_t *) block)[8]; + const uint64_t m9 = ((uint64_t *) block)[9]; + const uint64_t m10 = ((uint64_t *) block)[10]; + const uint64_t m11 = ((uint64_t *) block)[11]; + const uint64_t m12 = ((uint64_t *) block)[12]; + const uint64_t m13 = ((uint64_t *) block)[13]; + const uint64_t m14 = ((uint64_t *) block)[14]; + const uint64_t m15 = ((uint64_t *) block)[15]; + + row1l = LOADU(&S->h[0]); + row1h = LOADU(&S->h[2]); + row2l = LOADU(&S->h[4]); + row2h = LOADU(&S->h[6]); + row3l = LOADU(&blake2b_IV[0]); + row3h = LOADU(&blake2b_IV[2]); + row4l = _mm_xor_si128(LOADU(&blake2b_IV[4]), LOADU(&S->t[0])); + row4h = _mm_xor_si128(LOADU(&blake2b_IV[6]), LOADU(&S->f[0])); + ROUND(0); + ROUND(1); + ROUND(2); + ROUND(3); + ROUND(4); + ROUND(5); + ROUND(6); + ROUND(7); + ROUND(8); + ROUND(9); + ROUND(10); + ROUND(11); + row1l = _mm_xor_si128(row3l, row1l); + row1h = _mm_xor_si128(row3h, row1h); + STOREU(&S->h[0], _mm_xor_si128(LOADU(&S->h[0]), row1l)); + STOREU(&S->h[2], _mm_xor_si128(LOADU(&S->h[2]), row1h)); + row2l = _mm_xor_si128(row4l, row2l); + row2h = _mm_xor_si128(row4h, row2h); + STOREU(&S->h[4], _mm_xor_si128(LOADU(&S->h[4]), row2l)); + STOREU(&S->h[6], _mm_xor_si128(LOADU(&S->h[6]), row2h)); + return 0; +} + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.h b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.h new file mode 100644 index 0000000000..9a7164fe25 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-compress-ssse3.h @@ -0,0 +1,103 @@ + +#ifndef blake2b_compress_ssse3_H +#define blake2b_compress_ssse3_H + +#define LOADU(p) _mm_loadu_si128((const __m128i *) (const void *) (p)) +#define STOREU(p, r) _mm_storeu_si128((__m128i *) (void *) (p), r) + +#define _mm_roti_epi64(x, c) \ + (-(c) == 32) \ + ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \ + : (-(c) == 24) \ + ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) \ + ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) \ + ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ + _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ + _mm_slli_epi64((x), 64 - (-(c)))) + +#define G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -32); \ + row4h = _mm_roti_epi64(row4h, -32); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -24); \ + row2h = _mm_roti_epi64(row2h, -24); + +#define G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1) \ + row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \ + row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \ + \ + row4l = _mm_xor_si128(row4l, row1l); \ + row4h = _mm_xor_si128(row4h, row1h); \ + \ + row4l = _mm_roti_epi64(row4l, -16); \ + row4h = _mm_roti_epi64(row4h, -16); \ + \ + row3l = _mm_add_epi64(row3l, row4l); \ + row3h = _mm_add_epi64(row3h, row4h); \ + \ + row2l = _mm_xor_si128(row2l, row3l); \ + row2h = _mm_xor_si128(row2h, row3h); \ + \ + row2l = _mm_roti_epi64(row2l, -63); \ + row2h = _mm_roti_epi64(row2h, -63); + +#define DIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h) \ + t0 = _mm_alignr_epi8(row2h, row2l, 8); \ + t1 = _mm_alignr_epi8(row2l, row2h, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4h, row4l, 8); \ + t1 = _mm_alignr_epi8(row4l, row4h, 8); \ + row4l = t1; \ + row4h = t0; + +#define UNDIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h) \ + t0 = _mm_alignr_epi8(row2l, row2h, 8); \ + t1 = _mm_alignr_epi8(row2h, row2l, 8); \ + row2l = t0; \ + row2h = t1; \ + \ + t0 = row3l; \ + row3l = row3h; \ + row3h = t0; \ + \ + t0 = _mm_alignr_epi8(row4l, row4h, 8); \ + t1 = _mm_alignr_epi8(row4h, row4l, 8); \ + row4l = t1; \ + row4h = t0; + +#include "blake2b-load-sse2.h" + +#define ROUND(r) \ + LOAD_MSG_##r##_1(b0, b1); \ + G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \ + LOAD_MSG_##r##_2(b0, b1); \ + G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \ + DIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); \ + LOAD_MSG_##r##_3(b0, b1); \ + G1(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \ + LOAD_MSG_##r##_4(b0, b1); \ + G2(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h, b0, b1); \ + UNDIAGONALIZE(row1l, row2l, row3l, row4l, row1h, row2h, row3h, row4h); + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-avx2.h b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-avx2.h new file mode 100644 index 0000000000..8c15f177c7 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-avx2.h @@ -0,0 +1,340 @@ +#ifndef blake2b_load_avx2_H +#define blake2b_load_avx2_H + +#define BLAKE2B_LOAD_MSG_0_1(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m0, m1); \ + t1 = _mm256_unpacklo_epi64(m2, m3); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_0_2(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m0, m1); \ + t1 = _mm256_unpackhi_epi64(m2, m3); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_0_3(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m4, m5); \ + t1 = _mm256_unpacklo_epi64(m6, m7); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_0_4(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m4, m5); \ + t1 = _mm256_unpackhi_epi64(m6, m7); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_1_1(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m7, m2); \ + t1 = _mm256_unpackhi_epi64(m4, m6); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_1_2(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m5, m4); \ + t1 = _mm256_alignr_epi8(m3, m7, 8); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_1_3(b0) \ + do { \ + t0 = _mm256_shuffle_epi32(m0, _MM_SHUFFLE(1, 0, 3, 2)); \ + t1 = _mm256_unpackhi_epi64(m5, m2); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_1_4(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m6, m1); \ + t1 = _mm256_unpackhi_epi64(m3, m1); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_2_1(b0) \ + do { \ + t0 = _mm256_alignr_epi8(m6, m5, 8); \ + t1 = _mm256_unpackhi_epi64(m2, m7); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_2_2(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m4, m0); \ + t1 = _mm256_blend_epi32(m6, m1, 0x33); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_2_3(b0) \ + do { \ + t0 = _mm256_blend_epi32(m1, m5, 0x33); \ + t1 = _mm256_unpackhi_epi64(m3, m4); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_2_4(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m7, m3); \ + t1 = _mm256_alignr_epi8(m2, m0, 8); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_3_1(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m3, m1); \ + t1 = _mm256_unpackhi_epi64(m6, m5); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_3_2(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m4, m0); \ + t1 = _mm256_unpacklo_epi64(m6, m7); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_3_3(b0) \ + do { \ + t0 = _mm256_blend_epi32(m2, m1, 0x33); \ + t1 = _mm256_blend_epi32(m7, m2, 0x33); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_3_4(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m3, m5); \ + t1 = _mm256_unpacklo_epi64(m0, m4); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_4_1(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m4, m2); \ + t1 = _mm256_unpacklo_epi64(m1, m5); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_4_2(b0) \ + do { \ + t0 = _mm256_blend_epi32(m3, m0, 0x33); \ + t1 = _mm256_blend_epi32(m7, m2, 0x33); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_4_3(b0) \ + do { \ + t0 = _mm256_blend_epi32(m5, m7, 0x33); \ + t1 = _mm256_blend_epi32(m1, m3, 0x33); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_4_4(b0) \ + do { \ + t0 = _mm256_alignr_epi8(m6, m0, 8); \ + t1 = _mm256_blend_epi32(m6, m4, 0x33); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_5_1(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m1, m3); \ + t1 = _mm256_unpacklo_epi64(m0, m4); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_5_2(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m6, m5); \ + t1 = _mm256_unpackhi_epi64(m5, m1); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_5_3(b0) \ + do { \ + t0 = _mm256_blend_epi32(m3, m2, 0x33); \ + t1 = _mm256_unpackhi_epi64(m7, m0); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_5_4(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m6, m2); \ + t1 = _mm256_blend_epi32(m4, m7, 0x33); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_6_1(b0) \ + do { \ + t0 = _mm256_blend_epi32(m0, m6, 0x33); \ + t1 = _mm256_unpacklo_epi64(m7, m2); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_6_2(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m2, m7); \ + t1 = _mm256_alignr_epi8(m5, m6, 8); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_6_3(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m0, m3); \ + t1 = _mm256_shuffle_epi32(m4, _MM_SHUFFLE(1, 0, 3, 2)); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_6_4(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m3, m1); \ + t1 = _mm256_blend_epi32(m5, m1, 0x33); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_7_1(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m6, m3); \ + t1 = _mm256_blend_epi32(m1, m6, 0x33); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_7_2(b0) \ + do { \ + t0 = _mm256_alignr_epi8(m7, m5, 8); \ + t1 = _mm256_unpackhi_epi64(m0, m4); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_7_3(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m2, m7); \ + t1 = _mm256_unpacklo_epi64(m4, m1); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_7_4(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m0, m2); \ + t1 = _mm256_unpacklo_epi64(m3, m5); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_8_1(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m3, m7); \ + t1 = _mm256_alignr_epi8(m0, m5, 8); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_8_2(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m7, m4); \ + t1 = _mm256_alignr_epi8(m4, m1, 8); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_8_3(b0) \ + do { \ + t0 = m6; \ + t1 = _mm256_alignr_epi8(m5, m0, 8); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_8_4(b0) \ + do { \ + t0 = _mm256_blend_epi32(m3, m1, 0x33); \ + t1 = m2; \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_9_1(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m5, m4); \ + t1 = _mm256_unpackhi_epi64(m3, m0); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_9_2(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m1, m2); \ + t1 = _mm256_blend_epi32(m2, m3, 0x33); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_9_3(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m7, m4); \ + t1 = _mm256_unpackhi_epi64(m1, m6); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_9_4(b0) \ + do { \ + t0 = _mm256_alignr_epi8(m7, m5, 8); \ + t1 = _mm256_unpacklo_epi64(m6, m0); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_10_1(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m0, m1); \ + t1 = _mm256_unpacklo_epi64(m2, m3); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_10_2(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m0, m1); \ + t1 = _mm256_unpackhi_epi64(m2, m3); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_10_3(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m4, m5); \ + t1 = _mm256_unpacklo_epi64(m6, m7); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_10_4(b0) \ + do { \ + t0 = _mm256_unpackhi_epi64(m4, m5); \ + t1 = _mm256_unpackhi_epi64(m6, m7); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_11_1(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m7, m2); \ + t1 = _mm256_unpackhi_epi64(m4, m6); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_11_2(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m5, m4); \ + t1 = _mm256_alignr_epi8(m3, m7, 8); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_11_3(b0) \ + do { \ + t0 = _mm256_shuffle_epi32(m0, _MM_SHUFFLE(1, 0, 3, 2)); \ + t1 = _mm256_unpackhi_epi64(m5, m2); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#define BLAKE2B_LOAD_MSG_11_4(b0) \ + do { \ + t0 = _mm256_unpacklo_epi64(m6, m1); \ + t1 = _mm256_unpackhi_epi64(m3, m1); \ + b0 = _mm256_blend_epi32(t0, t1, 0xF0); \ + } while (0) + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-sse2.h b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-sse2.h new file mode 100644 index 0000000000..8e67421aca --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-sse2.h @@ -0,0 +1,164 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . +*/ + +#ifndef blake2b_load_sse2_H +#define blake2b_load_sse2_H + +#define LOAD_MSG_0_1(b0, b1) \ + b0 = _mm_set_epi64x(m2, m0); \ + b1 = _mm_set_epi64x(m6, m4) +#define LOAD_MSG_0_2(b0, b1) \ + b0 = _mm_set_epi64x(m3, m1); \ + b1 = _mm_set_epi64x(m7, m5) +#define LOAD_MSG_0_3(b0, b1) \ + b0 = _mm_set_epi64x(m10, m8); \ + b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_0_4(b0, b1) \ + b0 = _mm_set_epi64x(m11, m9); \ + b1 = _mm_set_epi64x(m15, m13) +#define LOAD_MSG_1_1(b0, b1) \ + b0 = _mm_set_epi64x(m4, m14); \ + b1 = _mm_set_epi64x(m13, m9) +#define LOAD_MSG_1_2(b0, b1) \ + b0 = _mm_set_epi64x(m8, m10); \ + b1 = _mm_set_epi64x(m6, m15) +#define LOAD_MSG_1_3(b0, b1) \ + b0 = _mm_set_epi64x(m0, m1); \ + b1 = _mm_set_epi64x(m5, m11) +#define LOAD_MSG_1_4(b0, b1) \ + b0 = _mm_set_epi64x(m2, m12); \ + b1 = _mm_set_epi64x(m3, m7) +#define LOAD_MSG_2_1(b0, b1) \ + b0 = _mm_set_epi64x(m12, m11); \ + b1 = _mm_set_epi64x(m15, m5) +#define LOAD_MSG_2_2(b0, b1) \ + b0 = _mm_set_epi64x(m0, m8); \ + b1 = _mm_set_epi64x(m13, m2) +#define LOAD_MSG_2_3(b0, b1) \ + b0 = _mm_set_epi64x(m3, m10); \ + b1 = _mm_set_epi64x(m9, m7) +#define LOAD_MSG_2_4(b0, b1) \ + b0 = _mm_set_epi64x(m6, m14); \ + b1 = _mm_set_epi64x(m4, m1) +#define LOAD_MSG_3_1(b0, b1) \ + b0 = _mm_set_epi64x(m3, m7); \ + b1 = _mm_set_epi64x(m11, m13) +#define LOAD_MSG_3_2(b0, b1) \ + b0 = _mm_set_epi64x(m1, m9); \ + b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_3_3(b0, b1) \ + b0 = _mm_set_epi64x(m5, m2); \ + b1 = _mm_set_epi64x(m15, m4) +#define LOAD_MSG_3_4(b0, b1) \ + b0 = _mm_set_epi64x(m10, m6); \ + b1 = _mm_set_epi64x(m8, m0) +#define LOAD_MSG_4_1(b0, b1) \ + b0 = _mm_set_epi64x(m5, m9); \ + b1 = _mm_set_epi64x(m10, m2) +#define LOAD_MSG_4_2(b0, b1) \ + b0 = _mm_set_epi64x(m7, m0); \ + b1 = _mm_set_epi64x(m15, m4) +#define LOAD_MSG_4_3(b0, b1) \ + b0 = _mm_set_epi64x(m11, m14); \ + b1 = _mm_set_epi64x(m3, m6) +#define LOAD_MSG_4_4(b0, b1) \ + b0 = _mm_set_epi64x(m12, m1); \ + b1 = _mm_set_epi64x(m13, m8) +#define LOAD_MSG_5_1(b0, b1) \ + b0 = _mm_set_epi64x(m6, m2); \ + b1 = _mm_set_epi64x(m8, m0) +#define LOAD_MSG_5_2(b0, b1) \ + b0 = _mm_set_epi64x(m10, m12); \ + b1 = _mm_set_epi64x(m3, m11) +#define LOAD_MSG_5_3(b0, b1) \ + b0 = _mm_set_epi64x(m7, m4); \ + b1 = _mm_set_epi64x(m1, m15) +#define LOAD_MSG_5_4(b0, b1) \ + b0 = _mm_set_epi64x(m5, m13); \ + b1 = _mm_set_epi64x(m9, m14) +#define LOAD_MSG_6_1(b0, b1) \ + b0 = _mm_set_epi64x(m1, m12); \ + b1 = _mm_set_epi64x(m4, m14) +#define LOAD_MSG_6_2(b0, b1) \ + b0 = _mm_set_epi64x(m15, m5); \ + b1 = _mm_set_epi64x(m10, m13) +#define LOAD_MSG_6_3(b0, b1) \ + b0 = _mm_set_epi64x(m6, m0); \ + b1 = _mm_set_epi64x(m8, m9) +#define LOAD_MSG_6_4(b0, b1) \ + b0 = _mm_set_epi64x(m3, m7); \ + b1 = _mm_set_epi64x(m11, m2) +#define LOAD_MSG_7_1(b0, b1) \ + b0 = _mm_set_epi64x(m7, m13); \ + b1 = _mm_set_epi64x(m3, m12) +#define LOAD_MSG_7_2(b0, b1) \ + b0 = _mm_set_epi64x(m14, m11); \ + b1 = _mm_set_epi64x(m9, m1) +#define LOAD_MSG_7_3(b0, b1) \ + b0 = _mm_set_epi64x(m15, m5); \ + b1 = _mm_set_epi64x(m2, m8) +#define LOAD_MSG_7_4(b0, b1) \ + b0 = _mm_set_epi64x(m4, m0); \ + b1 = _mm_set_epi64x(m10, m6) +#define LOAD_MSG_8_1(b0, b1) \ + b0 = _mm_set_epi64x(m14, m6); \ + b1 = _mm_set_epi64x(m0, m11) +#define LOAD_MSG_8_2(b0, b1) \ + b0 = _mm_set_epi64x(m9, m15); \ + b1 = _mm_set_epi64x(m8, m3) +#define LOAD_MSG_8_3(b0, b1) \ + b0 = _mm_set_epi64x(m13, m12); \ + b1 = _mm_set_epi64x(m10, m1) +#define LOAD_MSG_8_4(b0, b1) \ + b0 = _mm_set_epi64x(m7, m2); \ + b1 = _mm_set_epi64x(m5, m4) +#define LOAD_MSG_9_1(b0, b1) \ + b0 = _mm_set_epi64x(m8, m10); \ + b1 = _mm_set_epi64x(m1, m7) +#define LOAD_MSG_9_2(b0, b1) \ + b0 = _mm_set_epi64x(m4, m2); \ + b1 = _mm_set_epi64x(m5, m6) +#define LOAD_MSG_9_3(b0, b1) \ + b0 = _mm_set_epi64x(m9, m15); \ + b1 = _mm_set_epi64x(m13, m3) +#define LOAD_MSG_9_4(b0, b1) \ + b0 = _mm_set_epi64x(m14, m11); \ + b1 = _mm_set_epi64x(m0, m12) +#define LOAD_MSG_10_1(b0, b1) \ + b0 = _mm_set_epi64x(m2, m0); \ + b1 = _mm_set_epi64x(m6, m4) +#define LOAD_MSG_10_2(b0, b1) \ + b0 = _mm_set_epi64x(m3, m1); \ + b1 = _mm_set_epi64x(m7, m5) +#define LOAD_MSG_10_3(b0, b1) \ + b0 = _mm_set_epi64x(m10, m8); \ + b1 = _mm_set_epi64x(m14, m12) +#define LOAD_MSG_10_4(b0, b1) \ + b0 = _mm_set_epi64x(m11, m9); \ + b1 = _mm_set_epi64x(m15, m13) +#define LOAD_MSG_11_1(b0, b1) \ + b0 = _mm_set_epi64x(m4, m14); \ + b1 = _mm_set_epi64x(m13, m9) +#define LOAD_MSG_11_2(b0, b1) \ + b0 = _mm_set_epi64x(m8, m10); \ + b1 = _mm_set_epi64x(m6, m15) +#define LOAD_MSG_11_3(b0, b1) \ + b0 = _mm_set_epi64x(m0, m1); \ + b1 = _mm_set_epi64x(m5, m11) +#define LOAD_MSG_11_4(b0, b1) \ + b0 = _mm_set_epi64x(m2, m12); \ + b1 = _mm_set_epi64x(m3, m7) + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-sse41.h b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-sse41.h new file mode 100644 index 0000000000..31745fc139 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-load-sse41.h @@ -0,0 +1,307 @@ +/* + BLAKE2 reference source code package - optimized C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . +*/ + +#ifndef blake2b_load_sse41_H +#define blake2b_load_sse41_H + +#define LOAD_MSG_0_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m0, m1); \ + b1 = _mm_unpacklo_epi64(m2, m3); \ + } while (0) + +#define LOAD_MSG_0_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m0, m1); \ + b1 = _mm_unpackhi_epi64(m2, m3); \ + } while (0) + +#define LOAD_MSG_0_3(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m4, m5); \ + b1 = _mm_unpacklo_epi64(m6, m7); \ + } while (0) + +#define LOAD_MSG_0_4(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m4, m5); \ + b1 = _mm_unpackhi_epi64(m6, m7); \ + } while (0) + +#define LOAD_MSG_1_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m7, m2); \ + b1 = _mm_unpackhi_epi64(m4, m6); \ + } while (0) + +#define LOAD_MSG_1_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m5, m4); \ + b1 = _mm_alignr_epi8(m3, m7, 8); \ + } while (0) + +#define LOAD_MSG_1_3(b0, b1) \ + do { \ + b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1, 0, 3, 2)); \ + b1 = _mm_unpackhi_epi64(m5, m2); \ + } while (0) + +#define LOAD_MSG_1_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m6, m1); \ + b1 = _mm_unpackhi_epi64(m3, m1); \ + } while (0) + +#define LOAD_MSG_2_1(b0, b1) \ + do { \ + b0 = _mm_alignr_epi8(m6, m5, 8); \ + b1 = _mm_unpackhi_epi64(m2, m7); \ + } while (0) + +#define LOAD_MSG_2_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m4, m0); \ + b1 = _mm_blend_epi16(m1, m6, 0xF0); \ + } while (0) + +#define LOAD_MSG_2_3(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m5, m1, 0xF0); \ + b1 = _mm_unpackhi_epi64(m3, m4); \ + } while (0) + +#define LOAD_MSG_2_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m7, m3); \ + b1 = _mm_alignr_epi8(m2, m0, 8); \ + } while (0) + +#define LOAD_MSG_3_1(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m3, m1); \ + b1 = _mm_unpackhi_epi64(m6, m5); \ + } while (0) + +#define LOAD_MSG_3_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m4, m0); \ + b1 = _mm_unpacklo_epi64(m6, m7); \ + } while (0) + +#define LOAD_MSG_3_3(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m1, m2, 0xF0); \ + b1 = _mm_blend_epi16(m2, m7, 0xF0); \ + } while (0) + +#define LOAD_MSG_3_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m3, m5); \ + b1 = _mm_unpacklo_epi64(m0, m4); \ + } while (0) + +#define LOAD_MSG_4_1(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m4, m2); \ + b1 = _mm_unpacklo_epi64(m1, m5); \ + } while (0) + +#define LOAD_MSG_4_2(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m0, m3, 0xF0); \ + b1 = _mm_blend_epi16(m2, m7, 0xF0); \ + } while (0) + +#define LOAD_MSG_4_3(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m7, m5, 0xF0); \ + b1 = _mm_blend_epi16(m3, m1, 0xF0); \ + } while (0) + +#define LOAD_MSG_4_4(b0, b1) \ + do { \ + b0 = _mm_alignr_epi8(m6, m0, 8); \ + b1 = _mm_blend_epi16(m4, m6, 0xF0); \ + } while (0) + +#define LOAD_MSG_5_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m1, m3); \ + b1 = _mm_unpacklo_epi64(m0, m4); \ + } while (0) + +#define LOAD_MSG_5_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m6, m5); \ + b1 = _mm_unpackhi_epi64(m5, m1); \ + } while (0) + +#define LOAD_MSG_5_3(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m2, m3, 0xF0); \ + b1 = _mm_unpackhi_epi64(m7, m0); \ + } while (0) + +#define LOAD_MSG_5_4(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m6, m2); \ + b1 = _mm_blend_epi16(m7, m4, 0xF0); \ + } while (0) + +#define LOAD_MSG_6_1(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m6, m0, 0xF0); \ + b1 = _mm_unpacklo_epi64(m7, m2); \ + } while (0) + +#define LOAD_MSG_6_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m2, m7); \ + b1 = _mm_alignr_epi8(m5, m6, 8); \ + } while (0) + +#define LOAD_MSG_6_3(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m0, m3); \ + b1 = _mm_shuffle_epi32(m4, _MM_SHUFFLE(1, 0, 3, 2)); \ + } while (0) + +#define LOAD_MSG_6_4(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m3, m1); \ + b1 = _mm_blend_epi16(m1, m5, 0xF0); \ + } while (0) + +#define LOAD_MSG_7_1(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m6, m3); \ + b1 = _mm_blend_epi16(m6, m1, 0xF0); \ + } while (0) + +#define LOAD_MSG_7_2(b0, b1) \ + do { \ + b0 = _mm_alignr_epi8(m7, m5, 8); \ + b1 = _mm_unpackhi_epi64(m0, m4); \ + } while (0) + +#define LOAD_MSG_7_3(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m2, m7); \ + b1 = _mm_unpacklo_epi64(m4, m1); \ + } while (0) + +#define LOAD_MSG_7_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m0, m2); \ + b1 = _mm_unpacklo_epi64(m3, m5); \ + } while (0) + +#define LOAD_MSG_8_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m3, m7); \ + b1 = _mm_alignr_epi8(m0, m5, 8); \ + } while (0) + +#define LOAD_MSG_8_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m7, m4); \ + b1 = _mm_alignr_epi8(m4, m1, 8); \ + } while (0) + +#define LOAD_MSG_8_3(b0, b1) \ + do { \ + b0 = m6; \ + b1 = _mm_alignr_epi8(m5, m0, 8); \ + } while (0) + +#define LOAD_MSG_8_4(b0, b1) \ + do { \ + b0 = _mm_blend_epi16(m1, m3, 0xF0); \ + b1 = m2; \ + } while (0) + +#define LOAD_MSG_9_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m5, m4); \ + b1 = _mm_unpackhi_epi64(m3, m0); \ + } while (0) + +#define LOAD_MSG_9_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m1, m2); \ + b1 = _mm_blend_epi16(m3, m2, 0xF0); \ + } while (0) + +#define LOAD_MSG_9_3(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m7, m4); \ + b1 = _mm_unpackhi_epi64(m1, m6); \ + } while (0) + +#define LOAD_MSG_9_4(b0, b1) \ + do { \ + b0 = _mm_alignr_epi8(m7, m5, 8); \ + b1 = _mm_unpacklo_epi64(m6, m0); \ + } while (0) + +#define LOAD_MSG_10_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m0, m1); \ + b1 = _mm_unpacklo_epi64(m2, m3); \ + } while (0) + +#define LOAD_MSG_10_2(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m0, m1); \ + b1 = _mm_unpackhi_epi64(m2, m3); \ + } while (0) + +#define LOAD_MSG_10_3(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m4, m5); \ + b1 = _mm_unpacklo_epi64(m6, m7); \ + } while (0) + +#define LOAD_MSG_10_4(b0, b1) \ + do { \ + b0 = _mm_unpackhi_epi64(m4, m5); \ + b1 = _mm_unpackhi_epi64(m6, m7); \ + } while (0) + +#define LOAD_MSG_11_1(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m7, m2); \ + b1 = _mm_unpackhi_epi64(m4, m6); \ + } while (0) + +#define LOAD_MSG_11_2(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m5, m4); \ + b1 = _mm_alignr_epi8(m3, m7, 8); \ + } while (0) + +#define LOAD_MSG_11_3(b0, b1) \ + do { \ + b0 = _mm_shuffle_epi32(m0, _MM_SHUFFLE(1, 0, 3, 2)); \ + b1 = _mm_unpackhi_epi64(m5, m2); \ + } while (0) + +#define LOAD_MSG_11_4(b0, b1) \ + do { \ + b0 = _mm_unpacklo_epi64(m6, m1); \ + b1 = _mm_unpackhi_epi64(m3, m1); \ + } while (0) + +#endif diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-ref.c b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-ref.c new file mode 100644 index 0000000000..91435a1b16 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/blake2b-ref.c @@ -0,0 +1,436 @@ +/* + BLAKE2 reference source code package - C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . +*/ + +#include +#include +#include +#include +#include + +#include "blake2.h" +#include "core.h" +#include "private/common.h" +#include "runtime.h" +#include "utils.h" + +static blake2b_compress_fn blake2b_compress = blake2b_compress_ref; + +static const uint64_t blake2b_IV[8] = { + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +/* LCOV_EXCL_START */ +static inline int +blake2b_set_lastnode(blake2b_state *S) +{ + S->f[1] = -1; + return 0; +} +/* LCOV_EXCL_STOP */ + +static inline int +blake2b_is_lastblock(const blake2b_state *S) +{ + return S->f[0] != 0; +} + +static inline int +blake2b_set_lastblock(blake2b_state *S) +{ + if (S->last_node) + blake2b_set_lastnode(S); + + S->f[0] = -1; + return 0; +} + +static inline int +blake2b_increment_counter(blake2b_state *S, const uint64_t inc) +{ +#ifdef HAVE_TI_MODE + uint128_t t = ((uint128_t) S->t[1] << 64) | S->t[0]; + t += inc; + S->t[0] = (uint64_t)(t >> 0); + S->t[1] = (uint64_t)(t >> 64); +#else + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +#endif + return 0; +} + +/* Parameter-related functions */ +static inline int +blake2b_param_set_salt(blake2b_param *P, const uint8_t salt[BLAKE2B_SALTBYTES]) +{ + memcpy(P->salt, salt, BLAKE2B_SALTBYTES); + return 0; +} + +static inline int +blake2b_param_set_personal(blake2b_param *P, + const uint8_t personal[BLAKE2B_PERSONALBYTES]) +{ + memcpy(P->personal, personal, BLAKE2B_PERSONALBYTES); + return 0; +} + +static inline int +blake2b_init0(blake2b_state *S) +{ + int i; + + for (i = 0; i < 8; i++) { + S->h[i] = blake2b_IV[i]; + } + memset(S->t, 0, offsetof(blake2b_state, last_node) + sizeof(S->last_node) + - offsetof(blake2b_state, t)); + return 0; +} + +/* init xors IV with input parameter block */ +int +blake2b_init_param(blake2b_state *S, const blake2b_param *P) +{ + size_t i; + const uint8_t *p; + + COMPILER_ASSERT(sizeof *P == 64); + blake2b_init0(S); + p = (const uint8_t *) (P); + + /* IV XOR ParamBlock */ + for (i = 0; i < 8; i++) { + S->h[i] ^= LOAD64_LE(p + sizeof(S->h[i]) * i); + } + return 0; +} + +int +blake2b_init(blake2b_state *S, const uint8_t outlen) +{ + blake2b_param P[1]; + + if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) { + sodium_misuse(); + } + P->digest_length = outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + STORE32_LE(P->leaf_length, 0); + STORE64_LE(P->node_offset, 0); + P->node_depth = 0; + P->inner_length = 0; + memset(P->reserved, 0, sizeof(P->reserved)); + memset(P->salt, 0, sizeof(P->salt)); + memset(P->personal, 0, sizeof(P->personal)); + return blake2b_init_param(S, P); +} + +int +blake2b_init_salt_personal(blake2b_state *S, const uint8_t outlen, + const void *salt, const void *personal) +{ + blake2b_param P[1]; + + if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) { + sodium_misuse(); + } + P->digest_length = outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + STORE32_LE(P->leaf_length, 0); + STORE64_LE(P->node_offset, 0); + P->node_depth = 0; + P->inner_length = 0; + memset(P->reserved, 0, sizeof(P->reserved)); + if (salt != NULL) { + blake2b_param_set_salt(P, (const uint8_t *) salt); + } else { + memset(P->salt, 0, sizeof(P->salt)); + } + if (personal != NULL) { + blake2b_param_set_personal(P, (const uint8_t *) personal); + } else { + memset(P->personal, 0, sizeof(P->personal)); + } + return blake2b_init_param(S, P); +} + +int +blake2b_init_key(blake2b_state *S, const uint8_t outlen, const void *key, + const uint8_t keylen) +{ + blake2b_param P[1]; + + if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) { + sodium_misuse(); + } + if (!key || !keylen || keylen > BLAKE2B_KEYBYTES) { + sodium_misuse(); + } + P->digest_length = outlen; + P->key_length = keylen; + P->fanout = 1; + P->depth = 1; + STORE32_LE(P->leaf_length, 0); + STORE64_LE(P->node_offset, 0); + P->node_depth = 0; + P->inner_length = 0; + memset(P->reserved, 0, sizeof(P->reserved)); + memset(P->salt, 0, sizeof(P->salt)); + memset(P->personal, 0, sizeof(P->personal)); + + if (blake2b_init_param(S, P) < 0) { + sodium_misuse(); + } + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); /* keylen cannot be 0 */ + blake2b_update(S, block, BLAKE2B_BLOCKBYTES); + sodium_memzero(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ + } + return 0; +} + +int +blake2b_init_key_salt_personal(blake2b_state *S, const uint8_t outlen, + const void *key, const uint8_t keylen, + const void *salt, const void *personal) +{ + blake2b_param P[1]; + + if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) { + sodium_misuse(); + } + if (!key || !keylen || keylen > BLAKE2B_KEYBYTES) { + sodium_misuse(); + } + P->digest_length = outlen; + P->key_length = keylen; + P->fanout = 1; + P->depth = 1; + STORE32_LE(P->leaf_length, 0); + STORE64_LE(P->node_offset, 0); + P->node_depth = 0; + P->inner_length = 0; + memset(P->reserved, 0, sizeof(P->reserved)); + if (salt != NULL) { + blake2b_param_set_salt(P, (const uint8_t *) salt); + } else { + memset(P->salt, 0, sizeof(P->salt)); + } + if (personal != NULL) { + blake2b_param_set_personal(P, (const uint8_t *) personal); + } else { + memset(P->personal, 0, sizeof(P->personal)); + } + + if (blake2b_init_param(S, P) < 0) { + sodium_misuse(); + } + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); /* keylen cannot be 0 */ + blake2b_update(S, block, BLAKE2B_BLOCKBYTES); + sodium_memzero(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ + } + return 0; +} + +/* inlen now in bytes */ +int +blake2b_update(blake2b_state *S, const uint8_t *in, uint64_t inlen) +{ + while (inlen > 0) { + size_t left = S->buflen; + size_t fill = 2 * BLAKE2B_BLOCKBYTES - left; + + if (inlen > fill) { + memcpy(S->buf + left, in, fill); /* Fill buffer */ + S->buflen += fill; + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, S->buf); /* Compress */ + memcpy(S->buf, S->buf + BLAKE2B_BLOCKBYTES, + BLAKE2B_BLOCKBYTES); /* Shift buffer left */ + S->buflen -= BLAKE2B_BLOCKBYTES; + in += fill; + inlen -= fill; + } else /* inlen <= fill */ + { + memcpy(S->buf + left, in, inlen); + S->buflen += inlen; /* Be lazy, do not compress */ + in += inlen; + inlen -= inlen; + } + } + + return 0; +} + +int +blake2b_final(blake2b_state *S, uint8_t *out, uint8_t outlen) +{ + unsigned char buffer[BLAKE2B_OUTBYTES]; + + if (!outlen || outlen > BLAKE2B_OUTBYTES) { + sodium_misuse(); + } + if (blake2b_is_lastblock(S)) { + return -1; + } + if (S->buflen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, S->buf); + S->buflen -= BLAKE2B_BLOCKBYTES; + assert(S->buflen <= BLAKE2B_BLOCKBYTES); + memcpy(S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen); + } + + blake2b_increment_counter(S, S->buflen); + blake2b_set_lastblock(S); + memset(S->buf + S->buflen, 0, + 2 * BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ + blake2b_compress(S, S->buf); + + COMPILER_ASSERT(sizeof buffer == 64U); + STORE64_LE(buffer + 8 * 0, S->h[0]); + STORE64_LE(buffer + 8 * 1, S->h[1]); + STORE64_LE(buffer + 8 * 2, S->h[2]); + STORE64_LE(buffer + 8 * 3, S->h[3]); + STORE64_LE(buffer + 8 * 4, S->h[4]); + STORE64_LE(buffer + 8 * 5, S->h[5]); + STORE64_LE(buffer + 8 * 6, S->h[6]); + STORE64_LE(buffer + 8 * 7, S->h[7]); + memcpy(out, buffer, outlen); /* outlen <= BLAKE2B_OUTBYTES (64) */ + + sodium_memzero(S->h, sizeof S->h); + sodium_memzero(S->buf, sizeof S->buf); + + return 0; +} + +/* inlen, at least, should be uint64_t. Others can be size_t. */ +int +blake2b(uint8_t *out, const void *in, const void *key, const uint8_t outlen, + const uint64_t inlen, uint8_t keylen) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if (NULL == in && inlen > 0) { + sodium_misuse(); + } + if (NULL == out) { + sodium_misuse(); + } + if (!outlen || outlen > BLAKE2B_OUTBYTES) { + sodium_misuse(); + } + if (NULL == key && keylen > 0) { + sodium_misuse(); + } + if (keylen > BLAKE2B_KEYBYTES) { + sodium_misuse(); + } + if (keylen > 0) { + if (blake2b_init_key(S, outlen, key, keylen) < 0) { + sodium_misuse(); + } + } else { + if (blake2b_init(S, outlen) < 0) { + sodium_misuse(); + } + } + + blake2b_update(S, (const uint8_t *) in, inlen); + blake2b_final(S, out, outlen); + return 0; +} + +int +blake2b_salt_personal(uint8_t *out, const void *in, const void *key, + const uint8_t outlen, const uint64_t inlen, + uint8_t keylen, const void *salt, const void *personal) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if (NULL == in && inlen > 0) { + sodium_misuse(); + } + if (NULL == out) { + sodium_misuse(); + } + if (!outlen || outlen > BLAKE2B_OUTBYTES) { + sodium_misuse(); + } + if (NULL == key && keylen > 0) { + sodium_misuse(); + } + if (keylen > BLAKE2B_KEYBYTES) { + sodium_misuse(); + } + if (keylen > 0) { + if (blake2b_init_key_salt_personal(S, outlen, key, keylen, salt, + personal) < 0) { + sodium_misuse(); + } + } else { + if (blake2b_init_salt_personal(S, outlen, salt, personal) < 0) { + sodium_misuse(); + } + } + + blake2b_update(S, (const uint8_t *) in, inlen); + blake2b_final(S, out, outlen); + return 0; +} + +int +blake2b_pick_best_implementation(void) +{ +/* LCOV_EXCL_START */ +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_TMMINTRIN_H) && \ + defined(HAVE_SMMINTRIN_H) + if (sodium_runtime_has_avx2()) { + blake2b_compress = blake2b_compress_avx2; + return 0; + } +#endif +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) && \ + defined(HAVE_SMMINTRIN_H) + if (sodium_runtime_has_sse41()) { + blake2b_compress = blake2b_compress_sse41; + return 0; + } +#endif +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) + if (sodium_runtime_has_ssse3()) { + blake2b_compress = blake2b_compress_ssse3; + return 0; + } +#endif + blake2b_compress = blake2b_compress_ref; + + return 0; + /* LCOV_EXCL_STOP */ +} diff --git a/libs/libsodium/src/crypto_generichash/blake2b/ref/generichash_blake2b.c b/libs/libsodium/src/crypto_generichash/blake2b/ref/generichash_blake2b.c new file mode 100644 index 0000000000..4bd0855006 --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/blake2b/ref/generichash_blake2b.c @@ -0,0 +1,111 @@ + +#include +#include +#include + +#include "blake2.h" +#include "crypto_generichash_blake2b.h" +#include "private/implementations.h" + +int +crypto_generichash_blake2b(unsigned char *out, size_t outlen, + const unsigned char *in, unsigned long long inlen, + const unsigned char *key, size_t keylen) +{ + if (outlen <= 0U || outlen > BLAKE2B_OUTBYTES || + keylen > BLAKE2B_KEYBYTES || inlen > UINT64_MAX) { + return -1; + } + assert(outlen <= UINT8_MAX); + assert(keylen <= UINT8_MAX); + + return blake2b((uint8_t *) out, in, key, (uint8_t) outlen, (uint64_t) inlen, + (uint8_t) keylen); +} + +int +crypto_generichash_blake2b_salt_personal( + unsigned char *out, size_t outlen, const unsigned char *in, + unsigned long long inlen, const unsigned char *key, size_t keylen, + const unsigned char *salt, const unsigned char *personal) +{ + if (outlen <= 0U || outlen > BLAKE2B_OUTBYTES || + keylen > BLAKE2B_KEYBYTES || inlen > UINT64_MAX) { + return -1; + } + assert(outlen <= UINT8_MAX); + assert(keylen <= UINT8_MAX); + + return blake2b_salt_personal((uint8_t *) out, in, key, (uint8_t) outlen, + (uint64_t) inlen, (uint8_t) keylen, salt, + personal); +} + +int +crypto_generichash_blake2b_init(crypto_generichash_blake2b_state *state, + const unsigned char *key, const size_t keylen, + const size_t outlen) +{ + if (outlen <= 0U || outlen > BLAKE2B_OUTBYTES || + keylen > BLAKE2B_KEYBYTES) { + return -1; + } + assert(outlen <= UINT8_MAX); + assert(keylen <= UINT8_MAX); + if (key == NULL || keylen <= 0U) { + if (blake2b_init(state, (uint8_t) outlen) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + } else if (blake2b_init_key(state, (uint8_t) outlen, key, + (uint8_t) keylen) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; +} + +int +crypto_generichash_blake2b_init_salt_personal( + crypto_generichash_blake2b_state *state, const unsigned char *key, + const size_t keylen, const size_t outlen, const unsigned char *salt, + const unsigned char *personal) +{ + if (outlen <= 0U || outlen > BLAKE2B_OUTBYTES || + keylen > BLAKE2B_KEYBYTES) { + return -1; + } + assert(outlen <= UINT8_MAX); + assert(keylen <= UINT8_MAX); + if (key == NULL || keylen <= 0U) { + if (blake2b_init_salt_personal(state, (uint8_t) outlen, salt, + personal) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + } else if (blake2b_init_key_salt_personal(state, (uint8_t) outlen, key, + (uint8_t) keylen, salt, + personal) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; +} + +int +crypto_generichash_blake2b_update(crypto_generichash_blake2b_state *state, + const unsigned char *in, + unsigned long long inlen) +{ + return blake2b_update(state, (const uint8_t *) in, (uint64_t) inlen); +} + +int +crypto_generichash_blake2b_final(crypto_generichash_blake2b_state *state, + unsigned char *out, const size_t outlen) +{ + assert(outlen <= UINT8_MAX); + return blake2b_final(state, (uint8_t *) out, (uint8_t) outlen); +} + +int +_crypto_generichash_blake2b_pick_best_implementation(void) +{ + return blake2b_pick_best_implementation(); +} diff --git a/libs/libsodium/src/crypto_generichash/crypto_generichash.c b/libs/libsodium/src/crypto_generichash/crypto_generichash.c new file mode 100644 index 0000000000..a9a14e999a --- /dev/null +++ b/libs/libsodium/src/crypto_generichash/crypto_generichash.c @@ -0,0 +1,91 @@ + +#include "crypto_generichash.h" +#include "randombytes.h" + +size_t +crypto_generichash_bytes_min(void) +{ + return crypto_generichash_BYTES_MIN; +} + +size_t +crypto_generichash_bytes_max(void) +{ + return crypto_generichash_BYTES_MAX; +} + +size_t +crypto_generichash_bytes(void) +{ + return crypto_generichash_BYTES; +} + +size_t +crypto_generichash_keybytes_min(void) +{ + return crypto_generichash_KEYBYTES_MIN; +} + +size_t +crypto_generichash_keybytes_max(void) +{ + return crypto_generichash_KEYBYTES_MAX; +} + +size_t +crypto_generichash_keybytes(void) +{ + return crypto_generichash_KEYBYTES; +} + +const char * +crypto_generichash_primitive(void) +{ + return crypto_generichash_PRIMITIVE; +} + +size_t +crypto_generichash_statebytes(void) +{ + return (sizeof(crypto_generichash_state) + (size_t) 63U) & ~(size_t) 63U; +} + +int +crypto_generichash(unsigned char *out, size_t outlen, const unsigned char *in, + unsigned long long inlen, const unsigned char *key, + size_t keylen) +{ + return crypto_generichash_blake2b(out, outlen, in, inlen, key, keylen); +} + +int +crypto_generichash_init(crypto_generichash_state *state, + const unsigned char *key, + const size_t keylen, const size_t outlen) +{ + return crypto_generichash_blake2b_init + ((crypto_generichash_blake2b_state *) state, key, keylen, outlen); +} + +int +crypto_generichash_update(crypto_generichash_state *state, + const unsigned char *in, + unsigned long long inlen) +{ + return crypto_generichash_blake2b_update + ((crypto_generichash_blake2b_state *) state, in, inlen); +} + +int +crypto_generichash_final(crypto_generichash_state *state, + unsigned char *out, const size_t outlen) +{ + return crypto_generichash_blake2b_final + ((crypto_generichash_blake2b_state *) state, out, outlen); +} + +void +crypto_generichash_keygen(unsigned char k[crypto_generichash_KEYBYTES]) +{ + randombytes_buf(k, crypto_generichash_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_hash/crypto_hash.c b/libs/libsodium/src/crypto_hash/crypto_hash.c new file mode 100644 index 0000000000..855c560ba5 --- /dev/null +++ b/libs/libsodium/src/crypto_hash/crypto_hash.c @@ -0,0 +1,20 @@ + +#include "crypto_hash.h" + +size_t +crypto_hash_bytes(void) +{ + return crypto_hash_BYTES; +} + +int +crypto_hash(unsigned char *out, const unsigned char *in, + unsigned long long inlen) +{ + return crypto_hash_sha512(out, in, inlen); +} + +const char * +crypto_hash_primitive(void) { + return crypto_hash_PRIMITIVE; +} diff --git a/libs/libsodium/src/crypto_hash/sha256/cp/hash_sha256_cp.c b/libs/libsodium/src/crypto_hash/sha256/cp/hash_sha256_cp.c new file mode 100644 index 0000000000..264054f98b --- /dev/null +++ b/libs/libsodium/src/crypto_hash/sha256/cp/hash_sha256_cp.c @@ -0,0 +1,254 @@ + +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include + +#include "crypto_hash_sha256.h" +#include "private/common.h" +#include "utils.h" + +static void +be32enc_vect(unsigned char *dst, const uint32_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) { + STORE32_BE(dst + i * 4, src[i]); + } +} + +static void +be32dec_vect(uint32_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 4; i++) { + dst[i] = LOAD32_BE(src + i * 4); + } +} + +static const uint32_t Krnd[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ROTR32(x, n) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +#define RND(a, b, c, d, e, f, g, h, k) \ + h += S1(e) + Ch(e, f, g) + k; \ + d += h; \ + h += S0(a) + Maj(a, b, c); + +#define RNDr(S, W, i, ii) \ + RND(S[(64 - i) % 8], S[(65 - i) % 8], S[(66 - i) % 8], S[(67 - i) % 8], \ + S[(68 - i) % 8], S[(69 - i) % 8], S[(70 - i) % 8], S[(71 - i) % 8], \ + W[i + ii] + Krnd[i + ii]) + +#define MSCH(W, ii, i) \ + W[i + ii + 16] = \ + s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii] + +static void +SHA256_Transform(uint32_t state[8], const uint8_t block[64], uint32_t W[64], + uint32_t S[8]) +{ + int i; + + be32dec_vect(W, block, 64); + memcpy(S, state, 32); + for (i = 0; i < 64; i += 16) { + RNDr(S, W, 0, i); + RNDr(S, W, 1, i); + RNDr(S, W, 2, i); + RNDr(S, W, 3, i); + RNDr(S, W, 4, i); + RNDr(S, W, 5, i); + RNDr(S, W, 6, i); + RNDr(S, W, 7, i); + RNDr(S, W, 8, i); + RNDr(S, W, 9, i); + RNDr(S, W, 10, i); + RNDr(S, W, 11, i); + RNDr(S, W, 12, i); + RNDr(S, W, 13, i); + RNDr(S, W, 14, i); + RNDr(S, W, 15, i); + if (i == 48) { + break; + } + MSCH(W, 0, i); + MSCH(W, 1, i); + MSCH(W, 2, i); + MSCH(W, 3, i); + MSCH(W, 4, i); + MSCH(W, 5, i); + MSCH(W, 6, i); + MSCH(W, 7, i); + MSCH(W, 8, i); + MSCH(W, 9, i); + MSCH(W, 10, i); + MSCH(W, 11, i); + MSCH(W, 12, i); + MSCH(W, 13, i); + MSCH(W, 14, i); + MSCH(W, 15, i); + } + for (i = 0; i < 8; i++) { + state[i] += S[i]; + } +} + +static const uint8_t PAD[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +static void +SHA256_Pad(crypto_hash_sha256_state *state, uint32_t tmp32[64 + 8]) +{ + unsigned int r; + unsigned int i; + + r = (unsigned int) ((state->count >> 3) & 0x3f); + if (r < 56) { + for (i = 0; i < 56 - r; i++) { + state->buf[r + i] = PAD[i]; + } + } else { + for (i = 0; i < 64 - r; i++) { + state->buf[r + i] = PAD[i]; + } + SHA256_Transform(state->state, state->buf, &tmp32[0], &tmp32[64]); + memset(&state->buf[0], 0, 56); + } + STORE64_BE(&state->buf[56], state->count); + SHA256_Transform(state->state, state->buf, &tmp32[0], &tmp32[64]); +} + +int +crypto_hash_sha256_init(crypto_hash_sha256_state *state) +{ + static const uint32_t sha256_initial_state[8] = { 0x6a09e667, 0xbb67ae85, + 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, + 0x1f83d9ab, 0x5be0cd19 }; + + state->count = (uint64_t) 0U; + memcpy(state->state, sha256_initial_state, sizeof sha256_initial_state); + + return 0; +} + +int +crypto_hash_sha256_update(crypto_hash_sha256_state *state, + const unsigned char *in, unsigned long long inlen) +{ + uint32_t tmp32[64 + 8]; + unsigned long long i; + unsigned long long r; + + if (inlen <= 0U) { + return 0; + } + r = (unsigned long long) ((state->count >> 3) & 0x3f); + + state->count += ((uint64_t) inlen) << 3; + if (inlen < 64 - r) { + for (i = 0; i < inlen; i++) { + state->buf[r + i] = in[i]; + } + return 0; + } + for (i = 0; i < 64 - r; i++) { + state->buf[r + i] = in[i]; + } + SHA256_Transform(state->state, state->buf, &tmp32[0], &tmp32[64]); + in += 64 - r; + inlen -= 64 - r; + + while (inlen >= 64) { + SHA256_Transform(state->state, in, &tmp32[0], &tmp32[64]); + in += 64; + inlen -= 64; + } + inlen &= 63; + for (i = 0; i < inlen; i++) { + state->buf[i] = in[i]; + } + sodium_memzero((void *) tmp32, sizeof tmp32); + + return 0; +} + +int +crypto_hash_sha256_final(crypto_hash_sha256_state *state, unsigned char *out) +{ + uint32_t tmp32[64 + 8]; + + SHA256_Pad(state, tmp32); + be32enc_vect(out, state->state, 32); + sodium_memzero((void *) tmp32, sizeof tmp32); + sodium_memzero((void *) state, sizeof *state); + + return 0; +} + +int +crypto_hash_sha256(unsigned char *out, const unsigned char *in, + unsigned long long inlen) +{ + crypto_hash_sha256_state state; + + crypto_hash_sha256_init(&state); + crypto_hash_sha256_update(&state, in, inlen); + crypto_hash_sha256_final(&state, out); + + return 0; +} diff --git a/libs/libsodium/src/crypto_hash/sha256/hash_sha256.c b/libs/libsodium/src/crypto_hash/sha256/hash_sha256.c new file mode 100644 index 0000000000..e729c811e6 --- /dev/null +++ b/libs/libsodium/src/crypto_hash/sha256/hash_sha256.c @@ -0,0 +1,13 @@ +#include "crypto_hash_sha256.h" + +size_t +crypto_hash_sha256_bytes(void) +{ + return crypto_hash_sha256_BYTES; +} + +size_t +crypto_hash_sha256_statebytes(void) +{ + return sizeof(crypto_hash_sha256_state); +} diff --git a/libs/libsodium/src/crypto_hash/sha512/cp/hash_sha512_cp.c b/libs/libsodium/src/crypto_hash/sha512/cp/hash_sha512_cp.c new file mode 100644 index 0000000000..8e0f36fb6b --- /dev/null +++ b/libs/libsodium/src/crypto_hash/sha512/cp/hash_sha512_cp.c @@ -0,0 +1,282 @@ + +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include + +#include "crypto_hash_sha512.h" +#include "private/common.h" +#include "utils.h" + +static void +be64enc_vect(unsigned char *dst, const uint64_t *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 8; i++) { + STORE64_BE(dst + i * 8, src[i]); + } +} + +static void +be64dec_vect(uint64_t *dst, const unsigned char *src, size_t len) +{ + size_t i; + + for (i = 0; i < len / 8; i++) { + dst[i] = LOAD64_BE(src + i * 8); + } +} + +static const uint64_t Krnd[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, + 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, + 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, + 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, + 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, + 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, + 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, + 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, + 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, + 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, + 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ROTR64(x, n) +#define S0(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) +#define S1(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) +#define s0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define s1(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHR(x, 6)) + +#define RND(a, b, c, d, e, f, g, h, k) \ + h += S1(e) + Ch(e, f, g) + k; \ + d += h; \ + h += S0(a) + Maj(a, b, c); + +#define RNDr(S, W, i, ii) \ + RND(S[(80 - i) % 8], S[(81 - i) % 8], S[(82 - i) % 8], S[(83 - i) % 8], \ + S[(84 - i) % 8], S[(85 - i) % 8], S[(86 - i) % 8], S[(87 - i) % 8], \ + W[i + ii] + Krnd[i + ii]) + +#define MSCH(W, ii, i) \ + W[i + ii + 16] = \ + s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii] + +static void +SHA512_Transform(uint64_t *state, const uint8_t block[128], uint64_t W[80], + uint64_t S[8]) +{ + int i; + + be64dec_vect(W, block, 128); + memcpy(S, state, 64); + for (i = 0; i < 80; i += 16) { + RNDr(S, W, 0, i); + RNDr(S, W, 1, i); + RNDr(S, W, 2, i); + RNDr(S, W, 3, i); + RNDr(S, W, 4, i); + RNDr(S, W, 5, i); + RNDr(S, W, 6, i); + RNDr(S, W, 7, i); + RNDr(S, W, 8, i); + RNDr(S, W, 9, i); + RNDr(S, W, 10, i); + RNDr(S, W, 11, i); + RNDr(S, W, 12, i); + RNDr(S, W, 13, i); + RNDr(S, W, 14, i); + RNDr(S, W, 15, i); + if (i == 64) { + break; + } + MSCH(W, 0, i); + MSCH(W, 1, i); + MSCH(W, 2, i); + MSCH(W, 3, i); + MSCH(W, 4, i); + MSCH(W, 5, i); + MSCH(W, 6, i); + MSCH(W, 7, i); + MSCH(W, 8, i); + MSCH(W, 9, i); + MSCH(W, 10, i); + MSCH(W, 11, i); + MSCH(W, 12, i); + MSCH(W, 13, i); + MSCH(W, 14, i); + MSCH(W, 15, i); + } + for (i = 0; i < 8; i++) { + state[i] += S[i]; + } +} + +static const uint8_t PAD[128] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void +SHA512_Pad(crypto_hash_sha512_state *state, uint64_t tmp64[80 + 8]) +{ + unsigned int r; + unsigned int i; + + r = (unsigned int) ((state->count[1] >> 3) & 0x7f); + if (r < 112) { + for (i = 0; i < 112 - r; i++) { + state->buf[r + i] = PAD[i]; + } + } else { + for (i = 0; i < 128 - r; i++) { + state->buf[r + i] = PAD[i]; + } + SHA512_Transform(state->state, state->buf, &tmp64[0], &tmp64[80]); + memset(&state->buf[0], 0, 112); + } + be64enc_vect(&state->buf[112], state->count, 16); + SHA512_Transform(state->state, state->buf, &tmp64[0], &tmp64[80]); +} + +int +crypto_hash_sha512_init(crypto_hash_sha512_state *state) +{ + static const uint64_t sha512_initial_state[8] = { + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL + }; + + state->count[0] = state->count[1] = (uint64_t) 0U; + memcpy(state->state, sha512_initial_state, sizeof sha512_initial_state); + + return 0; +} + +int +crypto_hash_sha512_update(crypto_hash_sha512_state *state, + const unsigned char *in, unsigned long long inlen) +{ + uint64_t tmp64[80 + 8]; + uint64_t bitlen[2]; + unsigned long long i; + unsigned long long r; + + if (inlen <= 0U) { + return 0; + } + r = (unsigned long long) ((state->count[1] >> 3) & 0x7f); + + bitlen[1] = ((uint64_t) inlen) << 3; + bitlen[0] = ((uint64_t) inlen) >> 61; + /* LCOV_EXCL_START */ + if ((state->count[1] += bitlen[1]) < bitlen[1]) { + state->count[0]++; + } + /* LCOV_EXCL_STOP */ + state->count[0] += bitlen[0]; + if (inlen < 128 - r) { + for (i = 0; i < inlen; i++) { + state->buf[r + i] = in[i]; + } + return 0; + } + for (i = 0; i < 128 - r; i++) { + state->buf[r + i] = in[i]; + } + SHA512_Transform(state->state, state->buf, &tmp64[0], &tmp64[80]); + in += 128 - r; + inlen -= 128 - r; + + while (inlen >= 128) { + SHA512_Transform(state->state, in, &tmp64[0], &tmp64[80]); + in += 128; + inlen -= 128; + } + inlen &= 127; + for (i = 0; i < inlen; i++) { + state->buf[i] = in[i]; + } + sodium_memzero((void *) tmp64, sizeof tmp64); + + return 0; +} + +int +crypto_hash_sha512_final(crypto_hash_sha512_state *state, unsigned char *out) +{ + uint64_t tmp64[80 + 8]; + + SHA512_Pad(state, tmp64); + be64enc_vect(out, state->state, 64); + sodium_memzero((void *) tmp64, sizeof tmp64); + sodium_memzero((void *) state, sizeof *state); + + return 0; +} + +int +crypto_hash_sha512(unsigned char *out, const unsigned char *in, + unsigned long long inlen) +{ + crypto_hash_sha512_state state; + + crypto_hash_sha512_init(&state); + crypto_hash_sha512_update(&state, in, inlen); + crypto_hash_sha512_final(&state, out); + + return 0; +} diff --git a/libs/libsodium/src/crypto_hash/sha512/hash_sha512.c b/libs/libsodium/src/crypto_hash/sha512/hash_sha512.c new file mode 100644 index 0000000000..ba842b8bd4 --- /dev/null +++ b/libs/libsodium/src/crypto_hash/sha512/hash_sha512.c @@ -0,0 +1,13 @@ +#include "crypto_hash_sha512.h" + +size_t +crypto_hash_sha512_bytes(void) +{ + return crypto_hash_sha512_BYTES; +} + +size_t +crypto_hash_sha512_statebytes(void) +{ + return sizeof(crypto_hash_sha512_state); +} diff --git a/libs/libsodium/src/crypto_kdf/blake2b/kdf_blake2b.c b/libs/libsodium/src/crypto_kdf/blake2b/kdf_blake2b.c new file mode 100644 index 0000000000..2a690c9ac8 --- /dev/null +++ b/libs/libsodium/src/crypto_kdf/blake2b/kdf_blake2b.c @@ -0,0 +1,52 @@ +#include + +#include "crypto_kdf_blake2b.h" +#include "crypto_generichash_blake2b.h" +#include "private/common.h" + +size_t +crypto_kdf_blake2b_bytes_min(void) +{ + return crypto_kdf_blake2b_BYTES_MIN; +} + +size_t +crypto_kdf_blake2b_bytes_max(void) +{ + return crypto_kdf_blake2b_BYTES_MAX; +} + +size_t +crypto_kdf_blake2b_contextbytes(void) +{ + return crypto_kdf_blake2b_CONTEXTBYTES; +} + +size_t +crypto_kdf_blake2b_keybytes(void) +{ + return crypto_kdf_blake2b_KEYBYTES; +} + +int crypto_kdf_blake2b_derive_from_key(unsigned char *subkey, size_t subkey_len, + uint64_t subkey_id, + const char ctx[crypto_kdf_blake2b_CONTEXTBYTES], + const unsigned char key[crypto_kdf_blake2b_KEYBYTES]) +{ + unsigned char ctx_padded[crypto_generichash_blake2b_PERSONALBYTES]; + unsigned char salt[crypto_generichash_blake2b_SALTBYTES]; + + memcpy(ctx_padded, ctx, crypto_kdf_blake2b_CONTEXTBYTES); + memset(ctx_padded + crypto_kdf_blake2b_CONTEXTBYTES, 0, sizeof ctx_padded - crypto_kdf_blake2b_CONTEXTBYTES); + STORE64_LE(salt, subkey_id); + memset(salt + 8, 0, (sizeof salt) - 8); + if (subkey_len < crypto_kdf_blake2b_BYTES_MIN || + subkey_len > crypto_kdf_blake2b_BYTES_MAX) { + errno = EINVAL; + return -1; + } + return crypto_generichash_blake2b_salt_personal(subkey, subkey_len, + NULL, 0, + key, crypto_kdf_blake2b_KEYBYTES, + salt, ctx_padded); +} diff --git a/libs/libsodium/src/crypto_kdf/crypto_kdf.c b/libs/libsodium/src/crypto_kdf/crypto_kdf.c new file mode 100644 index 0000000000..b215d99ae6 --- /dev/null +++ b/libs/libsodium/src/crypto_kdf/crypto_kdf.c @@ -0,0 +1,49 @@ + +#include "crypto_kdf.h" +#include "randombytes.h" + +const char * +crypto_kdf_primitive(void) +{ + return crypto_kdf_PRIMITIVE; +} + +size_t +crypto_kdf_bytes_min(void) +{ + return crypto_kdf_BYTES_MIN; +} + +size_t +crypto_kdf_bytes_max(void) +{ + return crypto_kdf_BYTES_MAX; +} + +size_t +crypto_kdf_contextbytes(void) +{ + return crypto_kdf_CONTEXTBYTES; +} + +size_t +crypto_kdf_keybytes(void) +{ + return crypto_kdf_KEYBYTES; +} + +int +crypto_kdf_derive_from_key(unsigned char *subkey, size_t subkey_len, + uint64_t subkey_id, + const char ctx[crypto_kdf_CONTEXTBYTES], + const unsigned char key[crypto_kdf_KEYBYTES]) +{ + return crypto_kdf_blake2b_derive_from_key(subkey, subkey_len, + subkey_id, ctx, key); +} + +void +crypto_kdf_keygen(unsigned char k[crypto_kdf_KEYBYTES]) +{ + randombytes_buf(k, crypto_kdf_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_kx/crypto_kx.c b/libs/libsodium/src/crypto_kx/crypto_kx.c new file mode 100644 index 0000000000..877ab7ff4a --- /dev/null +++ b/libs/libsodium/src/crypto_kx/crypto_kx.c @@ -0,0 +1,143 @@ + +#include + +#include "core.h" +#include "crypto_generichash.h" +#include "crypto_kx.h" +#include "crypto_scalarmult.h" +#include "private/common.h" +#include "randombytes.h" +#include "utils.h" + +int +crypto_kx_seed_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], + unsigned char sk[crypto_kx_SECRETKEYBYTES], + const unsigned char seed[crypto_kx_SEEDBYTES]) +{ + crypto_generichash(sk, crypto_kx_SECRETKEYBYTES, + seed, crypto_kx_SEEDBYTES, NULL, 0); + return crypto_scalarmult_base(pk, sk); +} + +int +crypto_kx_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], + unsigned char sk[crypto_kx_SECRETKEYBYTES]) +{ + COMPILER_ASSERT(crypto_kx_SECRETKEYBYTES == crypto_scalarmult_SCALARBYTES); + COMPILER_ASSERT(crypto_kx_PUBLICKEYBYTES == crypto_scalarmult_BYTES); + + randombytes_buf(sk, crypto_kx_SECRETKEYBYTES); + return crypto_scalarmult_base(pk, sk); +} + +int +crypto_kx_client_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], + unsigned char tx[crypto_kx_SESSIONKEYBYTES], + const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES], + const unsigned char client_sk[crypto_kx_SECRETKEYBYTES], + const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES]) +{ + crypto_generichash_state h; + unsigned char q[crypto_scalarmult_BYTES]; + unsigned char keys[2 * crypto_kx_SESSIONKEYBYTES]; + int i; + + if (rx == NULL) { + rx = tx; + } + if (tx == NULL) { + tx = rx; + } + if (rx == NULL) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + if (crypto_scalarmult(q, client_sk, server_pk) != 0) { + return -1; + } + COMPILER_ASSERT(sizeof keys <= crypto_generichash_BYTES_MAX); + crypto_generichash_init(&h, NULL, 0U, sizeof keys); + crypto_generichash_update(&h, q, crypto_scalarmult_BYTES); + sodium_memzero(q, sizeof q); + crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES); + crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES); + crypto_generichash_final(&h, keys, sizeof keys); + sodium_memzero(&h, sizeof h); + for (i = 0; i < crypto_kx_SESSIONKEYBYTES; i++) { + rx[i] = keys[i]; + tx[i] = keys[i + crypto_kx_SESSIONKEYBYTES]; + } + sodium_memzero(keys, sizeof keys); + + return 0; +} + +int +crypto_kx_server_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], + unsigned char tx[crypto_kx_SESSIONKEYBYTES], + const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES], + const unsigned char server_sk[crypto_kx_SECRETKEYBYTES], + const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES]) +{ + crypto_generichash_state h; + unsigned char q[crypto_scalarmult_BYTES]; + unsigned char keys[2 * crypto_kx_SESSIONKEYBYTES]; + int i; + + if (rx == NULL) { + rx = tx; + } + if (tx == NULL) { + tx = rx; + } + if (rx == NULL) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + if (crypto_scalarmult(q, server_sk, client_pk) != 0) { + return -1; + } + COMPILER_ASSERT(sizeof keys <= crypto_generichash_BYTES_MAX); + crypto_generichash_init(&h, NULL, 0U, sizeof keys); + crypto_generichash_update(&h, q, crypto_scalarmult_BYTES); + sodium_memzero(q, sizeof q); + crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES); + crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES); + crypto_generichash_final(&h, keys, sizeof keys); + sodium_memzero(&h, sizeof h); + for (i = 0; i < crypto_kx_SESSIONKEYBYTES; i++) { + tx[i] = keys[i]; + rx[i] = keys[i + crypto_kx_SESSIONKEYBYTES]; + } + sodium_memzero(keys, sizeof keys); + + return 0; +} + +size_t +crypto_kx_publickeybytes(void) +{ + return crypto_kx_PUBLICKEYBYTES; +} + +size_t +crypto_kx_secretkeybytes(void) +{ + return crypto_kx_SECRETKEYBYTES; +} + +size_t +crypto_kx_seedbytes(void) +{ + return crypto_kx_SEEDBYTES; +} + +size_t +crypto_kx_sessionkeybytes(void) +{ + return crypto_kx_SESSIONKEYBYTES; +} + +const char * +crypto_kx_primitive(void) +{ + return crypto_kx_PRIMITIVE; +} diff --git a/libs/libsodium/src/crypto_onetimeauth/crypto_onetimeauth.c b/libs/libsodium/src/crypto_onetimeauth/crypto_onetimeauth.c new file mode 100644 index 0000000000..93567aae0b --- /dev/null +++ b/libs/libsodium/src/crypto_onetimeauth/crypto_onetimeauth.c @@ -0,0 +1,71 @@ + +#include "crypto_onetimeauth.h" +#include "randombytes.h" + +size_t +crypto_onetimeauth_statebytes(void) +{ + return sizeof(crypto_onetimeauth_state); +} + +size_t +crypto_onetimeauth_bytes(void) +{ + return crypto_onetimeauth_BYTES; +} + +size_t +crypto_onetimeauth_keybytes(void) +{ + return crypto_onetimeauth_KEYBYTES; +} + +int +crypto_onetimeauth(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + return crypto_onetimeauth_poly1305(out, in, inlen, k); +} + +int +crypto_onetimeauth_verify(const unsigned char *h, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + return crypto_onetimeauth_poly1305_verify(h, in, inlen, k); +} + +int +crypto_onetimeauth_init(crypto_onetimeauth_state *state, + const unsigned char *key) +{ + return crypto_onetimeauth_poly1305_init + ((crypto_onetimeauth_poly1305_state *) state, key); +} + +int +crypto_onetimeauth_update(crypto_onetimeauth_state *state, + const unsigned char *in, + unsigned long long inlen) +{ + return crypto_onetimeauth_poly1305_update + ((crypto_onetimeauth_poly1305_state *) state, in, inlen); +} + +int +crypto_onetimeauth_final(crypto_onetimeauth_state *state, + unsigned char *out) +{ + return crypto_onetimeauth_poly1305_final + ((crypto_onetimeauth_poly1305_state *) state, out); +} + +const char * +crypto_onetimeauth_primitive(void) +{ + return crypto_onetimeauth_PRIMITIVE; +} + +void crypto_onetimeauth_keygen(unsigned char k[crypto_onetimeauth_KEYBYTES]) +{ + randombytes_buf(k, crypto_onetimeauth_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna.c b/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna.c new file mode 100644 index 0000000000..e798072f84 --- /dev/null +++ b/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna.c @@ -0,0 +1,124 @@ + +#include "poly1305_donna.h" +#include "crypto_verify_16.h" +#include "private/common.h" +#include "utils.h" + +#ifdef HAVE_TI_MODE +#include "poly1305_donna64.h" +#else +#include "poly1305_donna32.h" +#endif +#include "../onetimeauth_poly1305.h" + +static void +poly1305_update(poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + unsigned long long i; + + /* handle leftover */ + if (st->leftover) { + unsigned long long want = (poly1305_block_size - st->leftover); + + if (want > bytes) { + want = bytes; + } + for (i = 0; i < want; i++) { + st->buffer[st->leftover + i] = m[i]; + } + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < poly1305_block_size) { + return; + } + poly1305_blocks(st, st->buffer, poly1305_block_size); + st->leftover = 0; + } + + /* process full blocks */ + if (bytes >= poly1305_block_size) { + unsigned long long want = (bytes & ~(poly1305_block_size - 1)); + + poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) { + st->buffer[st->leftover + i] = m[i]; + } + st->leftover += bytes; + } +} + +static int +crypto_onetimeauth_poly1305_donna(unsigned char *out, const unsigned char *m, + unsigned long long inlen, + const unsigned char *key) +{ + CRYPTO_ALIGN(64) poly1305_state_internal_t state; + + poly1305_init(&state, key); + poly1305_update(&state, m, inlen); + poly1305_finish(&state, out); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_donna_init(crypto_onetimeauth_poly1305_state *state, + const unsigned char *key) +{ + COMPILER_ASSERT(sizeof(crypto_onetimeauth_poly1305_state) >= + sizeof(poly1305_state_internal_t)); + poly1305_init((poly1305_state_internal_t *) (void *) state, key); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_donna_update( + crypto_onetimeauth_poly1305_state *state, const unsigned char *in, + unsigned long long inlen) +{ + poly1305_update((poly1305_state_internal_t *) (void *) state, in, inlen); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_donna_final( + crypto_onetimeauth_poly1305_state *state, unsigned char *out) +{ + poly1305_finish((poly1305_state_internal_t *) (void *) state, out); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_donna_verify(const unsigned char *h, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k) +{ + unsigned char correct[16]; + + crypto_onetimeauth_poly1305_donna(correct, in, inlen, k); + + return crypto_verify_16(h, correct); +} + +struct crypto_onetimeauth_poly1305_implementation + crypto_onetimeauth_poly1305_donna_implementation = { + SODIUM_C99(.onetimeauth =) crypto_onetimeauth_poly1305_donna, + SODIUM_C99(.onetimeauth_verify =) + crypto_onetimeauth_poly1305_donna_verify, + SODIUM_C99(.onetimeauth_init =) crypto_onetimeauth_poly1305_donna_init, + SODIUM_C99(.onetimeauth_update =) + crypto_onetimeauth_poly1305_donna_update, + SODIUM_C99(.onetimeauth_final =) crypto_onetimeauth_poly1305_donna_final + }; diff --git a/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna.h b/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna.h new file mode 100644 index 0000000000..d6474b3af4 --- /dev/null +++ b/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna.h @@ -0,0 +1,12 @@ +#ifndef poly1305_donna_H +#define poly1305_donna_H + +#include + +#include "../onetimeauth_poly1305.h" +#include "crypto_onetimeauth_poly1305.h" + +extern struct crypto_onetimeauth_poly1305_implementation + crypto_onetimeauth_poly1305_donna_implementation; + +#endif /* poly1305_donna_H */ diff --git a/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna32.h b/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna32.h new file mode 100644 index 0000000000..bcf447cd7d --- /dev/null +++ b/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna32.h @@ -0,0 +1,235 @@ +/* + poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication + and 64 bit addition +*/ + +#if defined(_MSC_VER) +# define POLY1305_NOINLINE __declspec(noinline) +#elif defined(__GNUC__) +# define POLY1305_NOINLINE __attribute__((noinline)) +#else +# define POLY1305_NOINLINE +#endif + +#include "private/common.h" + +#define poly1305_block_size 16 + +/* 17 + sizeof(unsigned long long) + 14*sizeof(unsigned long) */ +typedef struct poly1305_state_internal_t { + unsigned long r[5]; + unsigned long h[5]; + unsigned long pad[4]; + unsigned long long leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; +} poly1305_state_internal_t; + +static void +poly1305_init(poly1305_state_internal_t *st, const unsigned char key[32]) +{ + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff - wiped after finalization */ + st->r[0] = (LOAD32_LE(&key[0])) & 0x3ffffff; + st->r[1] = (LOAD32_LE(&key[3]) >> 2) & 0x3ffff03; + st->r[2] = (LOAD32_LE(&key[6]) >> 4) & 0x3ffc0ff; + st->r[3] = (LOAD32_LE(&key[9]) >> 6) & 0x3f03fff; + st->r[4] = (LOAD32_LE(&key[12]) >> 8) & 0x00fffff; + + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + + /* save pad for later */ + st->pad[0] = LOAD32_LE(&key[16]); + st->pad[1] = LOAD32_LE(&key[20]); + st->pad[2] = LOAD32_LE(&key[24]); + st->pad[3] = LOAD32_LE(&key[28]); + + st->leftover = 0; + st->final = 0; +} + +static void +poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + const unsigned long hibit = (st->final) ? 0UL : (1UL << 24); /* 1 << 128 */ + unsigned long r0, r1, r2, r3, r4; + unsigned long s1, s2, s3, s4; + unsigned long h0, h1, h2, h3, h4; + unsigned long long d0, d1, d2, d3, d4; + unsigned long c; + + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + r3 = st->r[3]; + r4 = st->r[4]; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + while (bytes >= poly1305_block_size) { + /* h += m[i] */ + h0 += (LOAD32_LE(m + 0)) & 0x3ffffff; + h1 += (LOAD32_LE(m + 3) >> 2) & 0x3ffffff; + h2 += (LOAD32_LE(m + 6) >> 4) & 0x3ffffff; + h3 += (LOAD32_LE(m + 9) >> 6) & 0x3ffffff; + h4 += (LOAD32_LE(m + 12) >> 8) | hibit; + + /* h *= r */ + d0 = ((unsigned long long) h0 * r0) + ((unsigned long long) h1 * s4) + + ((unsigned long long) h2 * s3) + ((unsigned long long) h3 * s2) + + ((unsigned long long) h4 * s1); + d1 = ((unsigned long long) h0 * r1) + ((unsigned long long) h1 * r0) + + ((unsigned long long) h2 * s4) + ((unsigned long long) h3 * s3) + + ((unsigned long long) h4 * s2); + d2 = ((unsigned long long) h0 * r2) + ((unsigned long long) h1 * r1) + + ((unsigned long long) h2 * r0) + ((unsigned long long) h3 * s4) + + ((unsigned long long) h4 * s3); + d3 = ((unsigned long long) h0 * r3) + ((unsigned long long) h1 * r2) + + ((unsigned long long) h2 * r1) + ((unsigned long long) h3 * r0) + + ((unsigned long long) h4 * s4); + d4 = ((unsigned long long) h0 * r4) + ((unsigned long long) h1 * r3) + + ((unsigned long long) h2 * r2) + ((unsigned long long) h3 * r1) + + ((unsigned long long) h4 * r0); + + /* (partial) h %= p */ + c = (unsigned long) (d0 >> 26); + h0 = (unsigned long) d0 & 0x3ffffff; + d1 += c; + c = (unsigned long) (d1 >> 26); + h1 = (unsigned long) d1 & 0x3ffffff; + d2 += c; + c = (unsigned long) (d2 >> 26); + h2 = (unsigned long) d2 & 0x3ffffff; + d3 += c; + c = (unsigned long) (d3 >> 26); + h3 = (unsigned long) d3 & 0x3ffffff; + d4 += c; + c = (unsigned long) (d4 >> 26); + h4 = (unsigned long) d4 & 0x3ffffff; + h0 += c * 5; + c = (h0 >> 26); + h0 = h0 & 0x3ffffff; + h1 += c; + + m += poly1305_block_size; + bytes -= poly1305_block_size; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; + st->h[3] = h3; + st->h[4] = h4; +} + +static POLY1305_NOINLINE void +poly1305_finish(poly1305_state_internal_t *st, unsigned char mac[16]) +{ + unsigned long h0, h1, h2, h3, h4, c; + unsigned long g0, g1, g2, g3, g4; + unsigned long long f; + unsigned long mask; + + /* process the remaining block */ + if (st->leftover) { + unsigned long long i = st->leftover; + + st->buffer[i++] = 1; + for (; i < poly1305_block_size; i++) { + st->buffer[i] = 0; + } + st->final = 1; + poly1305_blocks(st, st->buffer, poly1305_block_size); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + c = h1 >> 26; + h1 = h1 & 0x3ffffff; + h2 += c; + c = h2 >> 26; + h2 = h2 & 0x3ffffff; + h3 += c; + c = h3 >> 26; + h3 = h3 & 0x3ffffff; + h4 += c; + c = h4 >> 26; + h4 = h4 & 0x3ffffff; + h0 += c * 5; + c = h0 >> 26; + h0 = h0 & 0x3ffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; + c = g0 >> 26; + g0 &= 0x3ffffff; + g1 = h1 + c; + c = g1 >> 26; + g1 &= 0x3ffffff; + g2 = h2 + c; + c = g2 >> 26; + g2 &= 0x3ffffff; + g3 = h3 + c; + c = g3 >> 26; + g3 &= 0x3ffffff; + g4 = h4 + c - (1UL << 26); + + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; + + /* h = h % (2^128) */ + h0 = ((h0) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + f = (unsigned long long) h0 + st->pad[0]; + h0 = (unsigned long) f; + f = (unsigned long long) h1 + st->pad[1] + (f >> 32); + h1 = (unsigned long) f; + f = (unsigned long long) h2 + st->pad[2] + (f >> 32); + h2 = (unsigned long) f; + f = (unsigned long long) h3 + st->pad[3] + (f >> 32); + h3 = (unsigned long) f; + + STORE32_LE(mac + 0, (uint32_t) h0); + STORE32_LE(mac + 4, (uint32_t) h1); + STORE32_LE(mac + 8, (uint32_t) h2); + STORE32_LE(mac + 12, (uint32_t) h3); + + /* zero out the state */ + sodium_memzero((void *) st, sizeof *st); +} diff --git a/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna64.h b/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna64.h new file mode 100644 index 0000000000..e0ed754779 --- /dev/null +++ b/libs/libsodium/src/crypto_onetimeauth/poly1305/donna/poly1305_donna64.h @@ -0,0 +1,220 @@ +/* + poly1305 implementation using 64 bit * 64 bit = 128 bit multiplication + and 128 bit addition +*/ + +#include "private/common.h" + +#define MUL(out, x, y) out = ((uint128_t) x * y) +#define ADD(out, in) out += in +#define ADDLO(out, in) out += in +#define SHR(in, shift) (unsigned long long) (in >> (shift)) +#define LO(in) (unsigned long long) (in) + +#if defined(_MSC_VER) +# define POLY1305_NOINLINE __declspec(noinline) +#elif defined(__GNUC__) +# define POLY1305_NOINLINE __attribute__((noinline)) +#else +# define POLY1305_NOINLINE +#endif + +#define poly1305_block_size 16 + +/* 17 + sizeof(unsigned long long) + 8*sizeof(unsigned long long) */ +typedef struct poly1305_state_internal_t { + unsigned long long r[3]; + unsigned long long h[3]; + unsigned long long pad[2]; + unsigned long long leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; +} poly1305_state_internal_t; + +static void +poly1305_init(poly1305_state_internal_t *st, const unsigned char key[32]) +{ + unsigned long long t0, t1; + + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + t0 = LOAD64_LE(&key[0]); + t1 = LOAD64_LE(&key[8]); + + /* wiped after finalization */ + st->r[0] = (t0) &0xffc0fffffff; + st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; + st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f; + + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + + /* save pad for later */ + st->pad[0] = LOAD64_LE(&key[16]); + st->pad[1] = LOAD64_LE(&key[24]); + + st->leftover = 0; + st->final = 0; +} + +static void +poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + const unsigned long long hibit = + (st->final) ? 0ULL : (1ULL << 40); /* 1 << 128 */ + unsigned long long r0, r1, r2; + unsigned long long s1, s2; + unsigned long long h0, h1, h2; + unsigned long long c; + uint128_t d0, d1, d2, d; + + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + + s1 = r1 * (5 << 2); + s2 = r2 * (5 << 2); + + while (bytes >= poly1305_block_size) { + unsigned long long t0, t1; + + /* h += m[i] */ + t0 = LOAD64_LE(&m[0]); + t1 = LOAD64_LE(&m[8]); + + h0 += ((t0) &0xfffffffffff); + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); + h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit; + + /* h *= r */ + MUL(d0, h0, r0); + MUL(d, h1, s2); + ADD(d0, d); + MUL(d, h2, s1); + ADD(d0, d); + MUL(d1, h0, r1); + MUL(d, h1, r0); + ADD(d1, d); + MUL(d, h2, s2); + ADD(d1, d); + MUL(d2, h0, r2); + MUL(d, h1, r1); + ADD(d2, d); + MUL(d, h2, r0); + ADD(d2, d); + + /* (partial) h %= p */ + c = SHR(d0, 44); + h0 = LO(d0) & 0xfffffffffff; + ADDLO(d1, c); + c = SHR(d1, 44); + h1 = LO(d1) & 0xfffffffffff; + ADDLO(d2, c); + c = SHR(d2, 42); + h2 = LO(d2) & 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 = h0 & 0xfffffffffff; + h1 += c; + + m += poly1305_block_size; + bytes -= poly1305_block_size; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; +} + +static POLY1305_NOINLINE void +poly1305_finish(poly1305_state_internal_t *st, unsigned char mac[16]) +{ + unsigned long long h0, h1, h2, c; + unsigned long long g0, g1, g2; + unsigned long long t0, t1; + + /* process the remaining block */ + if (st->leftover) { + unsigned long long i = st->leftover; + + st->buffer[i] = 1; + + for (i = i + 1; i < poly1305_block_size; i++) { + st->buffer[i] = 0; + } + st->final = 1; + poly1305_blocks(st, st->buffer, poly1305_block_size); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + + /* compute h + -p */ + g0 = h0 + 5; + c = (g0 >> 44); + g0 &= 0xfffffffffff; + g1 = h1 + c; + c = (g1 >> 44); + g1 &= 0xfffffffffff; + g2 = h2 + c - (1ULL << 42); + + /* select h if h < p, or h + -p if h >= p */ + c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1; + g0 &= c; + g1 &= c; + g2 &= c; + c = ~c; + h0 = (h0 & c) | g0; + h1 = (h1 & c) | g1; + h2 = (h2 & c) | g2; + + /* h = (h + pad) */ + t0 = st->pad[0]; + t1 = st->pad[1]; + + h0 += ((t0) &0xfffffffffff); + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += (((t1 >> 24)) & 0x3ffffffffff) + c; + h2 &= 0x3ffffffffff; + + /* mac = h % (2^128) */ + h0 = ((h0) | (h1 << 44)); + h1 = ((h1 >> 20) | (h2 << 24)); + + STORE64_LE(&mac[0], h0); + STORE64_LE(&mac[8], h1); + + /* zero out the state */ + sodium_memzero((void *) st, sizeof *st); +} diff --git a/libs/libsodium/src/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c b/libs/libsodium/src/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c new file mode 100644 index 0000000000..d5e2efa297 --- /dev/null +++ b/libs/libsodium/src/crypto_onetimeauth/poly1305/onetimeauth_poly1305.c @@ -0,0 +1,90 @@ + +#include "onetimeauth_poly1305.h" +#include "crypto_onetimeauth_poly1305.h" +#include "private/common.h" +#include "private/implementations.h" +#include "randombytes.h" +#include "runtime.h" + +#include "donna/poly1305_donna.h" +#if defined(HAVE_TI_MODE) && defined(HAVE_EMMINTRIN_H) +# include "sse2/poly1305_sse2.h" +#endif + +static const crypto_onetimeauth_poly1305_implementation *implementation = + &crypto_onetimeauth_poly1305_donna_implementation; + +int +crypto_onetimeauth_poly1305(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + return implementation->onetimeauth(out, in, inlen, k); +} + +int +crypto_onetimeauth_poly1305_verify(const unsigned char *h, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k) +{ + return implementation->onetimeauth_verify(h, in, inlen, k); +} + +int +crypto_onetimeauth_poly1305_init(crypto_onetimeauth_poly1305_state *state, + const unsigned char *key) +{ + return implementation->onetimeauth_init(state, key); +} + +int +crypto_onetimeauth_poly1305_update(crypto_onetimeauth_poly1305_state *state, + const unsigned char *in, + unsigned long long inlen) +{ + return implementation->onetimeauth_update(state, in, inlen); +} + +int +crypto_onetimeauth_poly1305_final(crypto_onetimeauth_poly1305_state *state, + unsigned char *out) +{ + return implementation->onetimeauth_final(state, out); +} + +size_t +crypto_onetimeauth_poly1305_bytes(void) +{ + return crypto_onetimeauth_poly1305_BYTES; +} + +size_t +crypto_onetimeauth_poly1305_keybytes(void) +{ + return crypto_onetimeauth_poly1305_KEYBYTES; +} + +size_t +crypto_onetimeauth_poly1305_statebytes(void) +{ + return sizeof(crypto_onetimeauth_poly1305_state); +} + +void +crypto_onetimeauth_poly1305_keygen( + unsigned char k[crypto_onetimeauth_poly1305_KEYBYTES]) +{ + randombytes_buf(k, crypto_onetimeauth_poly1305_KEYBYTES); +} + +int +_crypto_onetimeauth_poly1305_pick_best_implementation(void) +{ + implementation = &crypto_onetimeauth_poly1305_donna_implementation; +#if defined(HAVE_TI_MODE) && defined(HAVE_EMMINTRIN_H) + if (sodium_runtime_has_sse2()) { + implementation = &crypto_onetimeauth_poly1305_sse2_implementation; + } +#endif + return 0; +} diff --git a/libs/libsodium/src/crypto_onetimeauth/poly1305/onetimeauth_poly1305.h b/libs/libsodium/src/crypto_onetimeauth/poly1305/onetimeauth_poly1305.h new file mode 100644 index 0000000000..243eadd50b --- /dev/null +++ b/libs/libsodium/src/crypto_onetimeauth/poly1305/onetimeauth_poly1305.h @@ -0,0 +1,21 @@ + +#ifndef onetimeauth_poly1305_H +#define onetimeauth_poly1305_H + +#include "crypto_onetimeauth_poly1305.h" + +typedef struct crypto_onetimeauth_poly1305_implementation { + int (*onetimeauth)(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k); + int (*onetimeauth_verify)(const unsigned char *h, const unsigned char *in, + unsigned long long inlen, const unsigned char *k); + int (*onetimeauth_init)(crypto_onetimeauth_poly1305_state *state, + const unsigned char * key); + int (*onetimeauth_update)(crypto_onetimeauth_poly1305_state *state, + const unsigned char * in, + unsigned long long inlen); + int (*onetimeauth_final)(crypto_onetimeauth_poly1305_state *state, + unsigned char * out); +} crypto_onetimeauth_poly1305_implementation; + +#endif diff --git a/libs/libsodium/src/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.c b/libs/libsodium/src/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.c new file mode 100644 index 0000000000..022f15249b --- /dev/null +++ b/libs/libsodium/src/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.c @@ -0,0 +1,949 @@ + +#include +#include + +#include "../onetimeauth_poly1305.h" +#include "crypto_verify_16.h" +#include "poly1305_sse2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" +#include "utils.h" + +#if defined(HAVE_TI_MODE) && defined(HAVE_EMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# endif + +# include + +typedef __m128i xmmi; + +# if defined(_MSC_VER) +# define POLY1305_NOINLINE __declspec(noinline) +# elif defined(__GNUC__) +# define POLY1305_NOINLINE __attribute__((noinline)) +# else +# define POLY1305_NOINLINE +# endif + +# define poly1305_block_size 32 + +enum poly1305_state_flags_t { + poly1305_started = 1, + poly1305_final_shift8 = 4, + poly1305_final_shift16 = 8, + poly1305_final_r2_r = 16, /* use [r^2,r] for the final block */ + poly1305_final_r_1 = 32 /* use [r,1] for the final block */ +}; + +typedef struct poly1305_state_internal_t { + union { + uint64_t h[3]; + uint32_t hh[10]; + } H; /* 40 bytes */ + uint32_t R[5]; /* 20 bytes */ + uint32_t R2[5]; /* 20 bytes */ + uint32_t R4[5]; /* 20 bytes */ + uint64_t pad[2]; /* 16 bytes */ + uint64_t flags; /* 8 bytes */ + unsigned long long leftover; /* 8 bytes */ + unsigned char buffer[poly1305_block_size]; /* 32 bytes */ +} poly1305_state_internal_t; /* 164 bytes total */ + +/* + * _mm_loadl_epi64() is turned into a simple MOVQ. So, unaligned accesses are + * totally fine, even though this intrinsic requires a __m128i* input. + * This confuses dynamic analysis, so force alignment, only in debug mode. + */ +# ifdef DEBUG +static xmmi +_fakealign_mm_loadl_epi64(const void *m) +{ + xmmi tmp; + memcpy(&tmp, m, 8); + + return _mm_loadl_epi64(&tmp); +} +# define _mm_loadl_epi64(X) _fakealign_mm_loadl_epi64(X) +#endif + +/* copy 0-31 bytes */ +static inline void +poly1305_block_copy31(unsigned char *dst, const unsigned char *src, + unsigned long long bytes) +{ + if (bytes & 16) { + _mm_store_si128((xmmi *) (void *) dst, + _mm_loadu_si128((const xmmi *) (const void *) src)); + src += 16; + dst += 16; + } + if (bytes & 8) { + memcpy(dst, src, 8); + src += 8; + dst += 8; + } + if (bytes & 4) { + memcpy(dst, src, 4); + src += 4; + dst += 4; + } + if (bytes & 2) { + memcpy(dst, src, 2); + src += 2; + dst += 2; + } + if (bytes & 1) { + *dst = *src; + } +} + +static POLY1305_NOINLINE void +poly1305_init_ext(poly1305_state_internal_t *st, const unsigned char key[32], + unsigned long long bytes) +{ + uint32_t *R; + uint128_t d[3]; + uint64_t r0, r1, r2; + uint64_t rt0, rt1, rt2, st2, c; + uint64_t t0, t1; + unsigned long long i; + + if (!bytes) { + bytes = ~(unsigned long long) 0; + } + /* H = 0 */ + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[0], _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[4], _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[8], _mm_setzero_si128()); + + /* clamp key */ + memcpy(&t0, key, 8); + memcpy(&t1, key + 8, 8); + r0 = t0 & 0xffc0fffffff; + t0 >>= 44; + t0 |= t1 << 20; + r1 = t0 & 0xfffffc0ffff; + t1 >>= 24; + r2 = t1 & 0x00ffffffc0f; + + /* r^1 */ + R = st->R; + R[0] = (uint32_t)(r0) &0x3ffffff; + R[1] = (uint32_t)((r0 >> 26) | (r1 << 18)) & 0x3ffffff; + R[2] = (uint32_t)((r1 >> 8)) & 0x3ffffff; + R[3] = (uint32_t)((r1 >> 34) | (r2 << 10)) & 0x3ffffff; + R[4] = (uint32_t)((r2 >> 16)); + + /* save pad */ + memcpy(&st->pad[0], key + 16, 8); + memcpy(&st->pad[1], key + 24, 8); + + rt0 = r0; + rt1 = r1; + rt2 = r2; + + /* r^2, r^4 */ + for (i = 0; i < 2; i++) { + if (i == 0) { + R = st->R2; + if (bytes <= 16) { + break; + } + } else if (i == 1) { + R = st->R4; + if (bytes < 96) { + break; + } + } + st2 = rt2 * (5 << 2); + + d[0] = ((uint128_t) rt0 * rt0) + ((uint128_t)(rt1 * 2) * st2); + d[1] = ((uint128_t) rt2 * st2) + ((uint128_t)(rt0 * 2) * rt1); + d[2] = ((uint128_t) rt1 * rt1) + ((uint128_t)(rt2 * 2) * rt0); + + rt0 = (uint64_t) d[0] & 0xfffffffffff; + c = (uint64_t)(d[0] >> 44); + d[1] += c; + + rt1 = (uint64_t) d[1] & 0xfffffffffff; + c = (uint64_t)(d[1] >> 44); + d[2] += c; + + rt2 = (uint64_t) d[2] & 0x3ffffffffff; + c = (uint64_t)(d[2] >> 42); + rt0 += c * 5; + c = (rt0 >> 44); + rt0 = rt0 & 0xfffffffffff; + rt1 += c; + c = (rt1 >> 44); + rt1 = rt1 & 0xfffffffffff; + rt2 += c; /* even if rt2 overflows, it will still fit in rp4 safely, and + is safe to multiply with */ + + R[0] = (uint32_t)(rt0) &0x3ffffff; + R[1] = (uint32_t)((rt0 >> 26) | (rt1 << 18)) & 0x3ffffff; + R[2] = (uint32_t)((rt1 >> 8)) & 0x3ffffff; + R[3] = (uint32_t)((rt1 >> 34) | (rt2 << 10)) & 0x3ffffff; + R[4] = (uint32_t)((rt2 >> 16)); + } + st->flags = 0; + st->leftover = 0U; +} + +static POLY1305_NOINLINE void +poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + CRYPTO_ALIGN(64) + xmmi HIBIT = + _mm_shuffle_epi32(_mm_cvtsi32_si128(1 << 24), _MM_SHUFFLE(1, 0, 1, 0)); + const xmmi MMASK = _mm_shuffle_epi32(_mm_cvtsi32_si128((1 << 26) - 1), + _MM_SHUFFLE(1, 0, 1, 0)); + const xmmi FIVE = + _mm_shuffle_epi32(_mm_cvtsi32_si128(5), _MM_SHUFFLE(1, 0, 1, 0)); + xmmi H0, H1, H2, H3, H4; + xmmi T0, T1, T2, T3, T4, T5, T6, T7, T8; + xmmi M0, M1, M2, M3, M4; + xmmi M5, M6, M7, M8; + xmmi C1, C2; + xmmi R20, R21, R22, R23, R24, S21, S22, S23, S24; + xmmi R40, R41, R42, R43, R44, S41, S42, S43, S44; + + if (st->flags & poly1305_final_shift8) { + HIBIT = _mm_srli_si128(HIBIT, 8); + } + if (st->flags & poly1305_final_shift16) { + HIBIT = _mm_setzero_si128(); + } + if (!(st->flags & poly1305_started)) { + /* H = [Mx,My] */ + T5 = _mm_unpacklo_epi64( + _mm_loadl_epi64((const xmmi *) (const void *) (m + 0)), + _mm_loadl_epi64((const xmmi *) (const void *) (m + 16))); + T6 = _mm_unpacklo_epi64( + _mm_loadl_epi64((const xmmi *) (const void *) (m + 8)), + _mm_loadl_epi64((const xmmi *) (const void *) (m + 24))); + H0 = _mm_and_si128(MMASK, T5); + H1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + H2 = _mm_and_si128(MMASK, T5); + H3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + H4 = _mm_srli_epi64(T6, 40); + H4 = _mm_or_si128(H4, HIBIT); + m += 32; + bytes -= 32; + st->flags |= poly1305_started; + } else { + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->H.hh[0]); + T1 = _mm_loadu_si128((const xmmi *) (const void *) &st->H.hh[4]); + T2 = _mm_loadu_si128((const xmmi *) (const void *) &st->H.hh[8]); + H0 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(1, 1, 0, 0)); + H1 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 3, 2, 2)); + H2 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(1, 1, 0, 0)); + H3 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(3, 3, 2, 2)); + H4 = _mm_shuffle_epi32(T2, _MM_SHUFFLE(1, 1, 0, 0)); + } + if (st->flags & (poly1305_final_r2_r | poly1305_final_r_1)) { + if (st->flags & poly1305_final_r2_r) { + /* use [r^2, r] */ + T2 = _mm_loadu_si128((const xmmi *) (const void *) &st->R[0]); + T3 = _mm_cvtsi32_si128(st->R[4]); + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->R2[0]); + T1 = _mm_cvtsi32_si128(st->R2[4]); + T4 = _mm_unpacklo_epi32(T0, T2); + T5 = _mm_unpackhi_epi32(T0, T2); + R24 = _mm_unpacklo_epi64(T1, T3); + } else { + /* use [r^1, 1] */ + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->R[0]); + T1 = _mm_cvtsi32_si128(st->R[4]); + T2 = _mm_cvtsi32_si128(1); + T4 = _mm_unpacklo_epi32(T0, T2); + T5 = _mm_unpackhi_epi32(T0, T2); + R24 = T1; + } + R20 = _mm_shuffle_epi32(T4, _MM_SHUFFLE(1, 1, 0, 0)); + R21 = _mm_shuffle_epi32(T4, _MM_SHUFFLE(3, 3, 2, 2)); + R22 = _mm_shuffle_epi32(T5, _MM_SHUFFLE(1, 1, 0, 0)); + R23 = _mm_shuffle_epi32(T5, _MM_SHUFFLE(3, 3, 2, 2)); + } else { + /* use [r^2, r^2] */ + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->R2[0]); + T1 = _mm_cvtsi32_si128(st->R2[4]); + R20 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(0, 0, 0, 0)); + R21 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(1, 1, 1, 1)); + R22 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(2, 2, 2, 2)); + R23 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 3, 3, 3)); + R24 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(0, 0, 0, 0)); + } + S21 = _mm_mul_epu32(R21, FIVE); + S22 = _mm_mul_epu32(R22, FIVE); + S23 = _mm_mul_epu32(R23, FIVE); + S24 = _mm_mul_epu32(R24, FIVE); + + if (bytes >= 64) { + T0 = _mm_loadu_si128((const xmmi *) (const void *) &st->R4[0]); + T1 = _mm_cvtsi32_si128(st->R4[4]); + R40 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(0, 0, 0, 0)); + R41 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(1, 1, 1, 1)); + R42 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(2, 2, 2, 2)); + R43 = _mm_shuffle_epi32(T0, _MM_SHUFFLE(3, 3, 3, 3)); + R44 = _mm_shuffle_epi32(T1, _MM_SHUFFLE(0, 0, 0, 0)); + S41 = _mm_mul_epu32(R41, FIVE); + S42 = _mm_mul_epu32(R42, FIVE); + S43 = _mm_mul_epu32(R43, FIVE); + S44 = _mm_mul_epu32(R44, FIVE); + + while (bytes >= 64) { + xmmi v00, v01, v02, v03, v04; + xmmi v10, v11, v12, v13, v14; + xmmi v20, v21, v22, v23, v24; + xmmi v30, v31, v32, v33, v34; + xmmi v40, v41, v42, v43, v44; + xmmi T14, T15; + + /* H *= [r^4,r^4], preload [Mx,My] */ + T15 = S42; + T0 = H4; + T0 = _mm_mul_epu32(T0, S41); + v01 = H3; + v01 = _mm_mul_epu32(v01, T15); + T14 = S43; + T1 = H4; + T1 = _mm_mul_epu32(T1, T15); + v11 = H3; + v11 = _mm_mul_epu32(v11, T14); + T2 = H4; + T2 = _mm_mul_epu32(T2, T14); + T0 = _mm_add_epi64(T0, v01); + T15 = S44; + v02 = H2; + v02 = _mm_mul_epu32(v02, T14); + T3 = H4; + T3 = _mm_mul_epu32(T3, T15); + T1 = _mm_add_epi64(T1, v11); + v03 = H1; + v03 = _mm_mul_epu32(v03, T15); + v12 = H2; + v12 = _mm_mul_epu32(v12, T15); + T0 = _mm_add_epi64(T0, v02); + T14 = R40; + v21 = H3; + v21 = _mm_mul_epu32(v21, T15); + v31 = H3; + v31 = _mm_mul_epu32(v31, T14); + T0 = _mm_add_epi64(T0, v03); + T4 = H4; + T4 = _mm_mul_epu32(T4, T14); + T1 = _mm_add_epi64(T1, v12); + v04 = H0; + v04 = _mm_mul_epu32(v04, T14); + T2 = _mm_add_epi64(T2, v21); + v13 = H1; + v13 = _mm_mul_epu32(v13, T14); + T3 = _mm_add_epi64(T3, v31); + T15 = R41; + v22 = H2; + v22 = _mm_mul_epu32(v22, T14); + v32 = H2; + v32 = _mm_mul_epu32(v32, T15); + T0 = _mm_add_epi64(T0, v04); + v41 = H3; + v41 = _mm_mul_epu32(v41, T15); + T1 = _mm_add_epi64(T1, v13); + v14 = H0; + v14 = _mm_mul_epu32(v14, T15); + T2 = _mm_add_epi64(T2, v22); + T14 = R42; + T5 = _mm_unpacklo_epi64( + _mm_loadl_epi64((const xmmi *) (const void *) (m + 0)), + _mm_loadl_epi64((const xmmi *) (const void *) (m + 16))); + v23 = H1; + v23 = _mm_mul_epu32(v23, T15); + T3 = _mm_add_epi64(T3, v32); + v33 = H1; + v33 = _mm_mul_epu32(v33, T14); + T4 = _mm_add_epi64(T4, v41); + v42 = H2; + v42 = _mm_mul_epu32(v42, T14); + T1 = _mm_add_epi64(T1, v14); + T15 = R43; + T6 = _mm_unpacklo_epi64( + _mm_loadl_epi64((const xmmi *) (const void *) (m + 8)), + _mm_loadl_epi64((const xmmi *) (const void *) (m + 24))); + v24 = H0; + v24 = _mm_mul_epu32(v24, T14); + T2 = _mm_add_epi64(T2, v23); + v34 = H0; + v34 = _mm_mul_epu32(v34, T15); + T3 = _mm_add_epi64(T3, v33); + M0 = _mm_and_si128(MMASK, T5); + v43 = H1; + v43 = _mm_mul_epu32(v43, T15); + T4 = _mm_add_epi64(T4, v42); + M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + v44 = H0; + v44 = _mm_mul_epu32(v44, R44); + T2 = _mm_add_epi64(T2, v24); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + T3 = _mm_add_epi64(T3, v34); + M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T6, 14)); + T4 = _mm_add_epi64(T4, v43); + M2 = _mm_and_si128(MMASK, T5); + T4 = _mm_add_epi64(T4, v44); + M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT); + + /* H += [Mx',My'] */ + T5 = _mm_loadu_si128((const xmmi *) (const void *) (m + 32)); + T6 = _mm_loadu_si128((const xmmi *) (const void *) (m + 48)); + T7 = _mm_unpacklo_epi32(T5, T6); + T8 = _mm_unpackhi_epi32(T5, T6); + M5 = _mm_unpacklo_epi32(T7, _mm_setzero_si128()); + M6 = _mm_unpackhi_epi32(T7, _mm_setzero_si128()); + M7 = _mm_unpacklo_epi32(T8, _mm_setzero_si128()); + M8 = _mm_unpackhi_epi32(T8, _mm_setzero_si128()); + M6 = _mm_slli_epi64(M6, 6); + M7 = _mm_slli_epi64(M7, 12); + M8 = _mm_slli_epi64(M8, 18); + T0 = _mm_add_epi64(T0, M5); + T1 = _mm_add_epi64(T1, M6); + T2 = _mm_add_epi64(T2, M7); + T3 = _mm_add_epi64(T3, M8); + T4 = _mm_add_epi64(T4, HIBIT); + + /* H += [Mx,My]*[r^2,r^2] */ + T15 = S22; + v00 = M4; + v00 = _mm_mul_epu32(v00, S21); + v01 = M3; + v01 = _mm_mul_epu32(v01, T15); + T14 = S23; + v10 = M4; + v10 = _mm_mul_epu32(v10, T15); + v11 = M3; + v11 = _mm_mul_epu32(v11, T14); + T0 = _mm_add_epi64(T0, v00); + v20 = M4; + v20 = _mm_mul_epu32(v20, T14); + T0 = _mm_add_epi64(T0, v01); + T15 = S24; + v02 = M2; + v02 = _mm_mul_epu32(v02, T14); + T1 = _mm_add_epi64(T1, v10); + v30 = M4; + v30 = _mm_mul_epu32(v30, T15); + T1 = _mm_add_epi64(T1, v11); + v03 = M1; + v03 = _mm_mul_epu32(v03, T15); + T2 = _mm_add_epi64(T2, v20); + v12 = M2; + v12 = _mm_mul_epu32(v12, T15); + T0 = _mm_add_epi64(T0, v02); + T14 = R20; + v21 = M3; + v21 = _mm_mul_epu32(v21, T15); + T3 = _mm_add_epi64(T3, v30); + v31 = M3; + v31 = _mm_mul_epu32(v31, T14); + T0 = _mm_add_epi64(T0, v03); + v40 = M4; + v40 = _mm_mul_epu32(v40, T14); + T1 = _mm_add_epi64(T1, v12); + v04 = M0; + v04 = _mm_mul_epu32(v04, T14); + T2 = _mm_add_epi64(T2, v21); + v13 = M1; + v13 = _mm_mul_epu32(v13, T14); + T3 = _mm_add_epi64(T3, v31); + T15 = R21; + v22 = M2; + v22 = _mm_mul_epu32(v22, T14); + T4 = _mm_add_epi64(T4, v40); + v32 = M2; + v32 = _mm_mul_epu32(v32, T15); + T0 = _mm_add_epi64(T0, v04); + v41 = M3; + v41 = _mm_mul_epu32(v41, T15); + T1 = _mm_add_epi64(T1, v13); + v14 = M0; + v14 = _mm_mul_epu32(v14, T15); + T2 = _mm_add_epi64(T2, v22); + T14 = R22; + v23 = M1; + v23 = _mm_mul_epu32(v23, T15); + T3 = _mm_add_epi64(T3, v32); + v33 = M1; + v33 = _mm_mul_epu32(v33, T14); + T4 = _mm_add_epi64(T4, v41); + v42 = M2; + v42 = _mm_mul_epu32(v42, T14); + T1 = _mm_add_epi64(T1, v14); + T15 = R23; + v24 = M0; + v24 = _mm_mul_epu32(v24, T14); + T2 = _mm_add_epi64(T2, v23); + v34 = M0; + v34 = _mm_mul_epu32(v34, T15); + T3 = _mm_add_epi64(T3, v33); + v43 = M1; + v43 = _mm_mul_epu32(v43, T15); + T4 = _mm_add_epi64(T4, v42); + v44 = M0; + v44 = _mm_mul_epu32(v44, R24); + T2 = _mm_add_epi64(T2, v24); + T3 = _mm_add_epi64(T3, v34); + T4 = _mm_add_epi64(T4, v43); + T4 = _mm_add_epi64(T4, v44); + + /* reduce */ + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_and_si128(T3, MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, MMASK); + T4 = _mm_and_si128(T4, MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, MMASK); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* Final: H = (H*[r^4,r^4] + [Mx,My]*[r^2,r^2] + [Mx',My']) */ + H0 = T0; + H1 = T1; + H2 = T2; + H3 = T3; + H4 = T4; + + m += 64; + bytes -= 64; + } + } + + if (bytes >= 32) { + xmmi v01, v02, v03, v04; + xmmi v11, v12, v13, v14; + xmmi v21, v22, v23, v24; + xmmi v31, v32, v33, v34; + xmmi v41, v42, v43, v44; + xmmi T14, T15; + + /* H *= [r^2,r^2] */ + T15 = S22; + T0 = H4; + T0 = _mm_mul_epu32(T0, S21); + v01 = H3; + v01 = _mm_mul_epu32(v01, T15); + T14 = S23; + T1 = H4; + T1 = _mm_mul_epu32(T1, T15); + v11 = H3; + v11 = _mm_mul_epu32(v11, T14); + T2 = H4; + T2 = _mm_mul_epu32(T2, T14); + T0 = _mm_add_epi64(T0, v01); + T15 = S24; + v02 = H2; + v02 = _mm_mul_epu32(v02, T14); + T3 = H4; + T3 = _mm_mul_epu32(T3, T15); + T1 = _mm_add_epi64(T1, v11); + v03 = H1; + v03 = _mm_mul_epu32(v03, T15); + v12 = H2; + v12 = _mm_mul_epu32(v12, T15); + T0 = _mm_add_epi64(T0, v02); + T14 = R20; + v21 = H3; + v21 = _mm_mul_epu32(v21, T15); + v31 = H3; + v31 = _mm_mul_epu32(v31, T14); + T0 = _mm_add_epi64(T0, v03); + T4 = H4; + T4 = _mm_mul_epu32(T4, T14); + T1 = _mm_add_epi64(T1, v12); + v04 = H0; + v04 = _mm_mul_epu32(v04, T14); + T2 = _mm_add_epi64(T2, v21); + v13 = H1; + v13 = _mm_mul_epu32(v13, T14); + T3 = _mm_add_epi64(T3, v31); + T15 = R21; + v22 = H2; + v22 = _mm_mul_epu32(v22, T14); + v32 = H2; + v32 = _mm_mul_epu32(v32, T15); + T0 = _mm_add_epi64(T0, v04); + v41 = H3; + v41 = _mm_mul_epu32(v41, T15); + T1 = _mm_add_epi64(T1, v13); + v14 = H0; + v14 = _mm_mul_epu32(v14, T15); + T2 = _mm_add_epi64(T2, v22); + T14 = R22; + v23 = H1; + v23 = _mm_mul_epu32(v23, T15); + T3 = _mm_add_epi64(T3, v32); + v33 = H1; + v33 = _mm_mul_epu32(v33, T14); + T4 = _mm_add_epi64(T4, v41); + v42 = H2; + v42 = _mm_mul_epu32(v42, T14); + T1 = _mm_add_epi64(T1, v14); + T15 = R23; + v24 = H0; + v24 = _mm_mul_epu32(v24, T14); + T2 = _mm_add_epi64(T2, v23); + v34 = H0; + v34 = _mm_mul_epu32(v34, T15); + T3 = _mm_add_epi64(T3, v33); + v43 = H1; + v43 = _mm_mul_epu32(v43, T15); + T4 = _mm_add_epi64(T4, v42); + v44 = H0; + v44 = _mm_mul_epu32(v44, R24); + T2 = _mm_add_epi64(T2, v24); + T3 = _mm_add_epi64(T3, v34); + T4 = _mm_add_epi64(T4, v43); + T4 = _mm_add_epi64(T4, v44); + + /* H += [Mx,My] */ + if (m) { + T5 = _mm_loadu_si128((const xmmi *) (const void *) (m + 0)); + T6 = _mm_loadu_si128((const xmmi *) (const void *) (m + 16)); + T7 = _mm_unpacklo_epi32(T5, T6); + T8 = _mm_unpackhi_epi32(T5, T6); + M0 = _mm_unpacklo_epi32(T7, _mm_setzero_si128()); + M1 = _mm_unpackhi_epi32(T7, _mm_setzero_si128()); + M2 = _mm_unpacklo_epi32(T8, _mm_setzero_si128()); + M3 = _mm_unpackhi_epi32(T8, _mm_setzero_si128()); + M1 = _mm_slli_epi64(M1, 6); + M2 = _mm_slli_epi64(M2, 12); + M3 = _mm_slli_epi64(M3, 18); + T0 = _mm_add_epi64(T0, M0); + T1 = _mm_add_epi64(T1, M1); + T2 = _mm_add_epi64(T2, M2); + T3 = _mm_add_epi64(T3, M3); + T4 = _mm_add_epi64(T4, HIBIT); + } + + /* reduce */ + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_and_si128(T3, MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, MMASK); + T4 = _mm_and_si128(T4, MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, MMASK); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* H = (H*[r^2,r^2] + [Mx,My]) */ + H0 = T0; + H1 = T1; + H2 = T2; + H3 = T3; + H4 = T4; + } + + if (m) { + T0 = _mm_shuffle_epi32(H0, _MM_SHUFFLE(0, 0, 2, 0)); + T1 = _mm_shuffle_epi32(H1, _MM_SHUFFLE(0, 0, 2, 0)); + T2 = _mm_shuffle_epi32(H2, _MM_SHUFFLE(0, 0, 2, 0)); + T3 = _mm_shuffle_epi32(H3, _MM_SHUFFLE(0, 0, 2, 0)); + T4 = _mm_shuffle_epi32(H4, _MM_SHUFFLE(0, 0, 2, 0)); + T0 = _mm_unpacklo_epi64(T0, T1); + T1 = _mm_unpacklo_epi64(T2, T3); + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[0], T0); + _mm_storeu_si128((xmmi *) (void *) &st->H.hh[4], T1); + _mm_storel_epi64((xmmi *) (void *) &st->H.hh[8], T4); + } else { + uint32_t t0, t1, t2, t3, t4, b; + uint64_t h0, h1, h2, g0, g1, g2, c, nc; + + /* H = H[0]+H[1] */ + T0 = H0; + T1 = H1; + T2 = H2; + T3 = H3; + T4 = H4; + + T0 = _mm_add_epi64(T0, _mm_srli_si128(T0, 8)); + T1 = _mm_add_epi64(T1, _mm_srli_si128(T1, 8)); + T2 = _mm_add_epi64(T2, _mm_srli_si128(T2, 8)); + T3 = _mm_add_epi64(T3, _mm_srli_si128(T3, 8)); + T4 = _mm_add_epi64(T4, _mm_srli_si128(T4, 8)); + + t0 = _mm_cvtsi128_si32(T0); + b = (t0 >> 26); + t0 &= 0x3ffffff; + t1 = _mm_cvtsi128_si32(T1) + b; + b = (t1 >> 26); + t1 &= 0x3ffffff; + t2 = _mm_cvtsi128_si32(T2) + b; + b = (t2 >> 26); + t2 &= 0x3ffffff; + t3 = _mm_cvtsi128_si32(T3) + b; + b = (t3 >> 26); + t3 &= 0x3ffffff; + t4 = _mm_cvtsi128_si32(T4) + b; + + /* everything except t4 is in range, so this is all safe */ + h0 = (((uint64_t) t0) | ((uint64_t) t1 << 26)) & 0xfffffffffffull; + h1 = (((uint64_t) t1 >> 18) | ((uint64_t) t2 << 8) | + ((uint64_t) t3 << 34)) & + 0xfffffffffffull; + h2 = (((uint64_t) t3 >> 10) | ((uint64_t) t4 << 16)); + + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + + g0 = h0 + 5; + c = (g0 >> 44); + g0 &= 0xfffffffffff; + g1 = h1 + c; + c = (g1 >> 44); + g1 &= 0xfffffffffff; + g2 = h2 + c - ((uint64_t) 1 << 42); + + c = (g2 >> 63) - 1; + nc = ~c; + h0 = (h0 & nc) | (g0 & c); + h1 = (h1 & nc) | (g1 & c); + h2 = (h2 & nc) | (g2 & c); + + st->H.h[0] = h0; + st->H.h[1] = h1; + st->H.h[2] = h2; + } +} + +static void +poly1305_update(poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long bytes) +{ + unsigned long long i; + + /* handle leftover */ + if (st->leftover) { + unsigned long long want = (poly1305_block_size - st->leftover); + + if (want > bytes) { + want = bytes; + } + for (i = 0; i < want; i++) { + st->buffer[st->leftover + i] = m[i]; + } + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < poly1305_block_size) { + return; + } + poly1305_blocks(st, st->buffer, poly1305_block_size); + st->leftover = 0; + } + + /* process full blocks */ + if (bytes >= poly1305_block_size) { + unsigned long long want = (bytes & ~(poly1305_block_size - 1)); + + poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) { + st->buffer[st->leftover + i] = m[i]; + } + st->leftover += bytes; + } +} + +static POLY1305_NOINLINE void +poly1305_finish_ext(poly1305_state_internal_t *st, const unsigned char *m, + unsigned long long leftover, unsigned char mac[16]) +{ + uint64_t h0, h1, h2; + + if (leftover) { + CRYPTO_ALIGN(16) unsigned char final[32] = { 0 }; + + poly1305_block_copy31(final, m, leftover); + if (leftover != 16) { + final[leftover] = 1; + } + st->flags |= + (leftover >= 16) ? poly1305_final_shift8 : poly1305_final_shift16; + poly1305_blocks(st, final, 32); + } + + if (st->flags & poly1305_started) { + /* finalize, H *= [r^2,r], or H *= [r,1] */ + if (!leftover || (leftover > 16)) { + st->flags |= poly1305_final_r2_r; + } else { + st->flags |= poly1305_final_r_1; + } + poly1305_blocks(st, NULL, 32); + } + + h0 = st->H.h[0]; + h1 = st->H.h[1]; + h2 = st->H.h[2]; + + /* pad */ + h0 = ((h0) | (h1 << 44)); + h1 = ((h1 >> 20) | (h2 << 24)); +#ifdef HAVE_AMD64_ASM + __asm__ __volatile__( + "addq %2, %0 ;\n" + "adcq %3, %1 ;\n" + : "+r"(h0), "+r"(h1) + : "r"(st->pad[0]), "r"(st->pad[1]) + : "flags", "cc"); +#else + { + uint128_t h; + + memcpy(&h, &st->pad[0], 16); + h += ((uint128_t) h1 << 64) | h0; + h0 = (uint64_t) h; + h1 = (uint64_t)(h >> 64); + } +#endif + _mm_storeu_si128((xmmi *) (void *) st + 0, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 1, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 2, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 3, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 4, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 5, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 6, _mm_setzero_si128()); + _mm_storeu_si128((xmmi *) (void *) st + 7, _mm_setzero_si128()); + + memcpy(&mac[0], &h0, 8); + memcpy(&mac[8], &h1, 8); + + sodium_memzero((void *) st, sizeof *st); +} + +static void +poly1305_finish(poly1305_state_internal_t *st, unsigned char mac[16]) +{ + poly1305_finish_ext(st, st->buffer, st->leftover, mac); +} + +static int +crypto_onetimeauth_poly1305_sse2_init(crypto_onetimeauth_poly1305_state *state, + const unsigned char *key) +{ + COMPILER_ASSERT(sizeof(crypto_onetimeauth_poly1305_state) >= + sizeof(poly1305_state_internal_t)); + poly1305_init_ext((poly1305_state_internal_t *) (void *) state, key, 0U); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_sse2_update( + crypto_onetimeauth_poly1305_state *state, const unsigned char *in, + unsigned long long inlen) +{ + poly1305_update((poly1305_state_internal_t *) (void *) state, in, inlen); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_sse2_final(crypto_onetimeauth_poly1305_state *state, + unsigned char *out) +{ + poly1305_finish((poly1305_state_internal_t *) (void *) state, out); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_sse2(unsigned char *out, const unsigned char *m, + unsigned long long inlen, + const unsigned char *key) +{ + CRYPTO_ALIGN(64) poly1305_state_internal_t st; + unsigned long long blocks; + + poly1305_init_ext(&st, key, inlen); + blocks = inlen & ~31; + if (blocks > 0) { + poly1305_blocks(&st, m, blocks); + m += blocks; + inlen -= blocks; + } + poly1305_finish_ext(&st, m, inlen, out); + + return 0; +} + +static int +crypto_onetimeauth_poly1305_sse2_verify(const unsigned char *h, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k) +{ + unsigned char correct[16]; + + crypto_onetimeauth_poly1305_sse2(correct, in, inlen, k); + + return crypto_verify_16(h, correct); +} + +struct crypto_onetimeauth_poly1305_implementation + crypto_onetimeauth_poly1305_sse2_implementation = { + SODIUM_C99(.onetimeauth =) crypto_onetimeauth_poly1305_sse2, + SODIUM_C99(.onetimeauth_verify =) + crypto_onetimeauth_poly1305_sse2_verify, + SODIUM_C99(.onetimeauth_init =) crypto_onetimeauth_poly1305_sse2_init, + SODIUM_C99(.onetimeauth_update =) + crypto_onetimeauth_poly1305_sse2_update, + SODIUM_C99(.onetimeauth_final =) crypto_onetimeauth_poly1305_sse2_final + }; + +#endif diff --git a/libs/libsodium/src/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.h b/libs/libsodium/src/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.h new file mode 100644 index 0000000000..9177cad487 --- /dev/null +++ b/libs/libsodium/src/crypto_onetimeauth/poly1305/sse2/poly1305_sse2.h @@ -0,0 +1,12 @@ +#ifndef poly1305_sse2_H +#define poly1305_sse2_H + +#include + +#include "../onetimeauth_poly1305.h" +#include "crypto_onetimeauth_poly1305.h" + +extern struct crypto_onetimeauth_poly1305_implementation + crypto_onetimeauth_poly1305_sse2_implementation; + +#endif /* poly1305_sse2_H */ diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.c new file mode 100644 index 0000000000..b52b04d36d --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.c @@ -0,0 +1,549 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include +#include +#include + +#include +#ifdef HAVE_SYS_MMAN_H +# include +#endif + +#include "crypto_generichash_blake2b.h" +#include "private/common.h" +#include "private/implementations.h" +#include "runtime.h" +#include "utils.h" + +#include "argon2-core.h" +#include "blake2b-long.h" + +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +# define MAP_ANON MAP_ANONYMOUS +#endif +#ifndef MAP_NOCORE +# define MAP_NOCORE 0 +#endif +#ifndef MAP_POPULATE +# define MAP_POPULATE 0 +#endif + +static fill_segment_fn fill_segment = fill_segment_ref; + +static void +load_block(block *dst, const void *input) +{ + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] = LOAD64_LE((const uint8_t *) input + i * sizeof(dst->v[i])); + } +} + +static void +store_block(void *output, const block *src) +{ + unsigned i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + STORE64_LE((uint8_t *) output + i * sizeof(src->v[i]), src->v[i]); + } +} + +/***************Memory allocators*****************/ +/* Allocates memory to the given pointer + * @param memory pointer to the pointer to the memory + * @param m_cost number of blocks to allocate in the memory + * @return ARGON2_OK if @memory is a valid pointer and memory is allocated + */ +static int allocate_memory(block_region **memory, uint32_t m_cost); + +static int +allocate_memory(block_region **region, uint32_t m_cost) +{ + void * base; + block *memory; + size_t memory_size; + + if (region == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */ + } + memory_size = sizeof(block) * m_cost; + if (m_cost == 0 || + memory_size / m_cost != + sizeof(block)) { /*1. Check for multiplication overflow*/ + return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */ + } + *region = (block_region *) malloc( + sizeof(block_region)); /*2. Try to allocate region*/ + if (!*region) { + return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */ + } + (*region)->base = (*region)->memory = NULL; + +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if ((base = mmap(NULL, memory_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_NOCORE | MAP_POPULATE, + -1, 0)) == MAP_FAILED) { + base = NULL; /* LCOV_EXCL_LINE */ + } /* LCOV_EXCL_LINE */ + memcpy(&memory, &base, sizeof memory); +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **) &base, 64, memory_size)) != 0) { + base = NULL; + } + memcpy(&memory, &base, sizeof memory); +#else + memory = NULL; + if (memory_size + 63 < memory_size) { + base = NULL; + errno = ENOMEM; + } else if ((base = malloc(memory_size + 63)) != NULL) { + uint8_t *aligned = ((uint8_t *) base) + 63; + aligned -= (uintptr_t) aligned & 63; + memcpy(&memory, &aligned, sizeof memory); + } +#endif + if (base == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; /* LCOV_EXCL_LINE */ + } + (*region)->base = base; + (*region)->memory = memory; + (*region)->size = memory_size; + + return ARGON2_OK; +} + +/*********Memory functions*/ + +/* Clears memory + * @param instance pointer to the current instance + * @param clear_memory indicates if we clear the memory with zeros. + */ +static void clear_memory(argon2_instance_t *instance, int clear); + +static void +clear_memory(argon2_instance_t *instance, int clear) +{ + /* LCOV_EXCL_START */ + if (clear) { + if (instance->region != NULL) { + sodium_memzero(instance->region->memory, + sizeof(block) * instance->memory_blocks); + } + if (instance->pseudo_rands != NULL) { + sodium_memzero(instance->pseudo_rands, + sizeof(uint64_t) * instance->segment_length); + } + } + /* LCOV_EXCL_STOP */ +} + +/* Deallocates memory + * @param memory pointer to the blocks + */ +static void free_memory(block_region *memory); + +static void +free_memory(block_region *region) +{ + if (region && region->base) { +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if (munmap(region->base, region->size)) { + return; /* LCOV_EXCL_LINE */ + } +#else + free(region->base); +#endif + } + free(region); +} + +void +free_instance(argon2_instance_t *instance, int flags) +{ + /* Clear memory */ + clear_memory(instance, flags & ARGON2_FLAG_CLEAR_MEMORY); + + /* Deallocate the memory */ + free(instance->pseudo_rands); + instance->pseudo_rands = NULL; + free_memory(instance->region); + instance->region = NULL; +} + +void +finalize(const argon2_context *context, argon2_instance_t *instance) +{ + if (context != NULL && instance != NULL) { + block blockhash; + uint32_t l; + + copy_block(&blockhash, + instance->region->memory + instance->lane_length - 1); + + /* XOR the last blocks */ + for (l = 1; l < instance->lanes; ++l) { + uint32_t last_block_in_lane = + l * instance->lane_length + (instance->lane_length - 1); + xor_block(&blockhash, + instance->region->memory + last_block_in_lane); + } + + /* Hash the result */ + { + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + store_block(blockhash_bytes, &blockhash); + blake2b_long(context->out, context->outlen, blockhash_bytes, + ARGON2_BLOCK_SIZE); + sodium_memzero(blockhash.v, + ARGON2_BLOCK_SIZE); /* clear blockhash */ + sodium_memzero(blockhash_bytes, + ARGON2_BLOCK_SIZE); /* clear blockhash_bytes */ + } + + free_instance(instance, context->flags); + } +} + +void +fill_memory_blocks(argon2_instance_t *instance, uint32_t pass) +{ + argon2_position_t position; + uint32_t l; + uint32_t s; + + if (instance == NULL || instance->lanes == 0) { + return; /* LCOV_EXCL_LINE */ + } + + position.pass = pass; + for (s = 0; s < ARGON2_SYNC_POINTS; ++s) { + position.slice = (uint8_t) s; + for (l = 0; l < instance->lanes; ++l) { + position.lane = l; + position.index = 0; + fill_segment(instance, position); + } + } +} + +int +validate_inputs(const argon2_context *context) +{ + /* LCOV_EXCL_START */ + if (NULL == context) { + return ARGON2_INCORRECT_PARAMETER; + } + + if (NULL == context->out) { + return ARGON2_OUTPUT_PTR_NULL; + } + + /* Validate output length */ + if (ARGON2_MIN_OUTLEN > context->outlen) { + return ARGON2_OUTPUT_TOO_SHORT; + } + + if (ARGON2_MAX_OUTLEN < context->outlen) { + return ARGON2_OUTPUT_TOO_LONG; + } + + /* Validate password (required param) */ + if (NULL == context->pwd) { + if (0 != context->pwdlen) { + return ARGON2_PWD_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_PWD_LENGTH > context->pwdlen) { + return ARGON2_PWD_TOO_SHORT; + } + + if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) { + return ARGON2_PWD_TOO_LONG; + } + + /* Validate salt (required param) */ + if (NULL == context->salt) { + if (0 != context->saltlen) { + return ARGON2_SALT_PTR_MISMATCH; + } + } + + if (ARGON2_MIN_SALT_LENGTH > context->saltlen) { + return ARGON2_SALT_TOO_SHORT; + } + + if (ARGON2_MAX_SALT_LENGTH < context->saltlen) { + return ARGON2_SALT_TOO_LONG; + } + + /* Validate secret (optional param) */ + if (NULL == context->secret) { + if (0 != context->secretlen) { + return ARGON2_SECRET_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_SECRET > context->secretlen) { + return ARGON2_SECRET_TOO_SHORT; + } + + if (ARGON2_MAX_SECRET < context->secretlen) { + return ARGON2_SECRET_TOO_LONG; + } + } + + /* Validate associated data (optional param) */ + if (NULL == context->ad) { + if (0 != context->adlen) { + return ARGON2_AD_PTR_MISMATCH; + } + } else { + if (ARGON2_MIN_AD_LENGTH > context->adlen) { + return ARGON2_AD_TOO_SHORT; + } + + if (ARGON2_MAX_AD_LENGTH < context->adlen) { + return ARGON2_AD_TOO_LONG; + } + } + + /* Validate memory cost */ + if (ARGON2_MIN_MEMORY > context->m_cost) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + if (ARGON2_MAX_MEMORY < context->m_cost) { + return ARGON2_MEMORY_TOO_MUCH; + } + + if (context->m_cost < 8 * context->lanes) { + return ARGON2_MEMORY_TOO_LITTLE; + } + + /* Validate time cost */ + if (ARGON2_MIN_TIME > context->t_cost) { + return ARGON2_TIME_TOO_SMALL; + } + + if (ARGON2_MAX_TIME < context->t_cost) { + return ARGON2_TIME_TOO_LARGE; + } + + /* Validate lanes */ + if (ARGON2_MIN_LANES > context->lanes) { + return ARGON2_LANES_TOO_FEW; + } + + if (ARGON2_MAX_LANES < context->lanes) { + return ARGON2_LANES_TOO_MANY; + } + + /* Validate threads */ + if (ARGON2_MIN_THREADS > context->threads) { + return ARGON2_THREADS_TOO_FEW; + } + + if (ARGON2_MAX_THREADS < context->threads) { + return ARGON2_THREADS_TOO_MANY; + } + /* LCOV_EXCL_STOP */ + + return ARGON2_OK; +} + +void +fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance) +{ + uint32_t l; + /* Make the first and second block in each lane as G(H0||i||0) or + G(H0||i||1) */ + uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE]; + for (l = 0; l < instance->lanes; ++l) { + STORE32_LE(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0); + STORE32_LE(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->region->memory[l * instance->lane_length + 0], + blockhash_bytes); + + STORE32_LE(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1); + blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash, + ARGON2_PREHASH_SEED_LENGTH); + load_block(&instance->region->memory[l * instance->lane_length + 1], + blockhash_bytes); + } + sodium_memzero(blockhash_bytes, ARGON2_BLOCK_SIZE); +} + +void +initial_hash(uint8_t *blockhash, argon2_context *context, argon2_type type) +{ + crypto_generichash_blake2b_state BlakeHash; + uint8_t value[4U /* sizeof(uint32_t) */]; + + if (NULL == context || NULL == blockhash) { + return; /* LCOV_EXCL_LINE */ + } + + crypto_generichash_blake2b_init(&BlakeHash, NULL, 0U, + ARGON2_PREHASH_DIGEST_LENGTH); + + STORE32_LE(value, context->lanes); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, context->outlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, context->m_cost); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, context->t_cost); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, ARGON2_VERSION_NUMBER); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, (uint32_t) type); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + STORE32_LE(value, context->pwdlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + if (context->pwd != NULL) { + crypto_generichash_blake2b_update( + &BlakeHash, (const uint8_t *) context->pwd, context->pwdlen); + + /* LCOV_EXCL_START */ + if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) { + sodium_memzero(context->pwd, context->pwdlen); + context->pwdlen = 0; + } + /* LCOV_EXCL_STOP */ + } + + STORE32_LE(value, context->saltlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + if (context->salt != NULL) { + crypto_generichash_blake2b_update( + &BlakeHash, (const uint8_t *) context->salt, context->saltlen); + } + + STORE32_LE(value, context->secretlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + /* LCOV_EXCL_START */ + if (context->secret != NULL) { + crypto_generichash_blake2b_update( + &BlakeHash, (const uint8_t *) context->secret, context->secretlen); + + if (context->flags & ARGON2_FLAG_CLEAR_SECRET) { + sodium_memzero(context->secret, context->secretlen); + context->secretlen = 0; + } + } + /* LCOV_EXCL_STOP */ + + STORE32_LE(value, context->adlen); + crypto_generichash_blake2b_update(&BlakeHash, value, sizeof(value)); + + /* LCOV_EXCL_START */ + if (context->ad != NULL) { + crypto_generichash_blake2b_update( + &BlakeHash, (const uint8_t *) context->ad, context->adlen); + } + /* LCOV_EXCL_STOP */ + + crypto_generichash_blake2b_final(&BlakeHash, blockhash, + ARGON2_PREHASH_DIGEST_LENGTH); +} + +int +initialize(argon2_instance_t *instance, argon2_context *context) +{ + uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; + int result = ARGON2_OK; + + if (instance == NULL || context == NULL) { + return ARGON2_INCORRECT_PARAMETER; + } + + /* 1. Memory allocation */ + + if ((instance->pseudo_rands = (uint64_t *) + malloc(sizeof(uint64_t) * instance->segment_length)) == NULL) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + result = allocate_memory(&(instance->region), instance->memory_blocks); + if (ARGON2_OK != result) { + free_instance(instance, context->flags); + return result; + } + + /* 2. Initial hashing */ + /* H_0 + 8 extra bytes to produce the first blocks */ + /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */ + /* Hashing all inputs */ + initial_hash(blockhash, context, instance->type); + /* Zeroing 8 extra bytes */ + sodium_memzero(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, + ARGON2_PREHASH_SEED_LENGTH - ARGON2_PREHASH_DIGEST_LENGTH); + + /* 3. Creating first blocks, we always have at least two blocks in a slice + */ + fill_first_blocks(blockhash, instance); + /* Clearing the hash */ + sodium_memzero(blockhash, ARGON2_PREHASH_SEED_LENGTH); + + return ARGON2_OK; +} + +int +argon2_pick_best_implementation(void) +{ +/* LCOV_EXCL_START */ +#if defined(HAVE_AVX512FINTRIN_H) && defined(HAVE_AVX2INTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + if (sodium_runtime_has_avx512f()) { + fill_segment = fill_segment_avx512f; + return 0; + } +#endif +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_TMMINTRIN_H) && \ + defined(HAVE_SMMINTRIN_H) + if (sodium_runtime_has_avx2()) { + fill_segment = fill_segment_avx2; + return 0; + } +#endif +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) + if (sodium_runtime_has_ssse3()) { + fill_segment = fill_segment_ssse3; + return 0; + } +#endif + fill_segment = fill_segment_ref; + + return 0; + /* LCOV_EXCL_STOP */ +} + +int +_crypto_pwhash_argon2_pick_best_implementation(void) +{ + return argon2_pick_best_implementation(); +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.h b/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.h new file mode 100644 index 0000000000..caab103891 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-core.h @@ -0,0 +1,297 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#ifndef argon2_core_H +#define argon2_core_H + +#include + +#include "argon2.h" + +/*************************Argon2 internal + * constants**************************************************/ + +enum argon2_ctx_constants { + /* Version of the algorithm */ + ARGON2_VERSION_NUMBER = 0x13, + + /* Memory block size in bytes */ + ARGON2_BLOCK_SIZE = 1024, + ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8, + ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16, + ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32, + ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64, + + /* Number of pseudo-random values generated by one call to Blake in Argon2i + to + generate reference block positions */ + ARGON2_ADDRESSES_IN_BLOCK = 128, + + /* Pre-hashing digest length and its extension*/ + ARGON2_PREHASH_DIGEST_LENGTH = 64, + ARGON2_PREHASH_SEED_LENGTH = 72 +}; + +/*************************Argon2 internal data + * types**************************************************/ + +/* + * Structure for the (1KB) memory block implemented as 128 64-bit words. + * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no + * bounds checking). + */ +typedef struct block_ { + uint64_t v[ARGON2_QWORDS_IN_BLOCK]; +} block; + +typedef struct block_region_ { + void * base; + block *memory; + size_t size; +} block_region; + +/*****************Functions that work with the block******************/ + +/* Initialize each byte of the block with @in */ +static inline void +init_block_value(block *b, uint8_t in) +{ + memset(b->v, in, sizeof(b->v)); +} + +/* Copy block @src to block @dst */ +static inline void +copy_block(block *dst, const block *src) +{ + memcpy(dst->v, src->v, sizeof(uint64_t) * ARGON2_QWORDS_IN_BLOCK); +} + +/* XOR @src onto @dst bytewise */ +static inline void +xor_block(block *dst, const block *src) +{ + int i; + for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) { + dst->v[i] ^= src->v[i]; + } +} + +/* + * Argon2 instance: memory pointer, number of passes, amount of memory, type, + * and derived values. + * Used to evaluate the number and location of blocks to construct in each + * thread + */ +typedef struct Argon2_instance_t { + block_region *region; /* Memory region pointer */ + uint64_t *pseudo_rands; + uint32_t passes; /* Number of passes */ + uint32_t current_pass; + uint32_t memory_blocks; /* Number of blocks in memory */ + uint32_t segment_length; + uint32_t lane_length; + uint32_t lanes; + uint32_t threads; + argon2_type type; + int print_internals; /* whether to print the memory blocks */ +} argon2_instance_t; + +/* + * Argon2 position: where we construct the block right now. Used to distribute + * work between threads. + */ +typedef struct Argon2_position_t { + uint32_t pass; + uint32_t lane; + uint8_t slice; + uint32_t index; +} argon2_position_t; + +/*Struct that holds the inputs for thread handling FillSegment*/ +typedef struct Argon2_thread_data { + argon2_instance_t *instance_ptr; + argon2_position_t pos; +} argon2_thread_data; + +/*************************Argon2 core + * functions**************************************************/ + +/* + * Computes absolute position of reference block in the lane following a skewed + * distribution and using a pseudo-random value as input + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rand 32-bit pseudo-random value used to determine the position + * @param same_lane Indicates if the block will be taken from the current lane. + * If so we can reference the current segment + * @pre All pointers must be valid + */ +static uint32_t index_alpha(const argon2_instance_t *instance, + const argon2_position_t *position, uint32_t pseudo_rand, + int same_lane) +{ + /* + * Pass 0: + * This lane : all already finished segments plus already constructed + * blocks in this segment + * Other lanes : all already finished segments + * Pass 1+: + * This lane : (SYNC_POINTS - 1) last segments plus already constructed + * blocks in this segment + * Other lanes : (SYNC_POINTS - 1) last segments + */ + uint32_t reference_area_size; + uint64_t relative_position; + uint32_t start_position, absolute_position; + + if (position->pass == 0) { + /* First pass */ + if (position->slice == 0) { + /* First slice */ + reference_area_size = + position->index - 1; /* all but the previous */ + } else { + if (same_lane) { + /* The same lane => add current segment */ + reference_area_size = + position->slice * instance->segment_length + + position->index - 1; + } else { + reference_area_size = + position->slice * instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + } else { + /* Second pass */ + if (same_lane) { + reference_area_size = instance->lane_length - + instance->segment_length + position->index - + 1; + } else { + reference_area_size = instance->lane_length - + instance->segment_length + + ((position->index == 0) ? (-1) : 0); + } + } + + /* 1.2.4. Mapping pseudo_rand to 0.. and produce + * relative position */ + relative_position = pseudo_rand; + relative_position = relative_position * relative_position >> 32; + relative_position = reference_area_size - 1 - + (reference_area_size * relative_position >> 32); + + /* 1.2.5 Computing starting position */ + start_position = 0; + + if (position->pass != 0) { + start_position = (position->slice == ARGON2_SYNC_POINTS - 1) + ? 0 + : (position->slice + 1) * instance->segment_length; + } + + /* 1.2.6. Computing absolute position */ + absolute_position = (start_position + relative_position) % + instance->lane_length; /* absolute position */ + return absolute_position; +} + +/* + * Function that validates all inputs against predefined restrictions and return + * an error code + * @param context Pointer to current Argon2 context + * @return ARGON2_OK if everything is all right, otherwise one of error codes + * (all defined in + */ +int validate_inputs(const argon2_context *context); + +/* + * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears + * password and secret if needed + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param blockhash Buffer for pre-hashing digest + * @param type Argon2 type + * @pre @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes + * allocated + */ +void initial_hash(uint8_t *blockhash, argon2_context *context, + argon2_type type); + +/* + * Function creates first 2 blocks per lane + * @param instance Pointer to the current instance + * @param blockhash Pointer to the pre-hashing digest + * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values + */ +void fill_first_blocks(uint8_t *blockhash, const argon2_instance_t *instance); + +/* + * Function allocates memory, hashes the inputs with Blake, and creates first + * two blocks. Returns the pointer to the main memory with 2 blocks per lane + * initialized + * @param context Pointer to the Argon2 internal structure containing memory + * pointer, and parameters for time and space requirements. + * @param instance Current Argon2 instance + * @return Zero if successful, -1 if memory failed to allocate. @context->state + * will be modified if successful. + */ +int initialize(argon2_instance_t *instance, argon2_context *context); + +/* + * Deallocates memory. Used on error path. + */ +void free_instance(argon2_instance_t *instance, int flags); + +/* + * XORing the last block of each lane, hashing it, making the tag. Deallocates + * the memory. + * @param context Pointer to current Argon2 context (use only the out parameters + * from it) + * @param instance Pointer to current instance of Argon2 + * @pre instance->state must point to necessary amount of memory + * @pre context->out must point to outlen bytes of memory + * @pre if context->free_cbk is not NULL, it should point to a function that + * deallocates memory + */ +void finalize(const argon2_context *context, argon2_instance_t *instance); + +/* + * Function that fills the segment using previous segments also from other + * threads + * @param instance Pointer to the current instance + * @param position Current position + * @pre all block pointers must be valid + */ +typedef void (*fill_segment_fn)(const argon2_instance_t *instance, + argon2_position_t position); +int argon2_pick_best_implementation(void); +void fill_segment_avx512f(const argon2_instance_t *instance, + argon2_position_t position); +void fill_segment_avx2(const argon2_instance_t *instance, + argon2_position_t position); +void fill_segment_ssse3(const argon2_instance_t *instance, + argon2_position_t position); +void fill_segment_ref(const argon2_instance_t *instance, + argon2_position_t position); + +/* + * Function that fills the entire memory t_cost times based on the first two + * blocks in each lane + * @param instance Pointer to the current instance + * @return Zero if successful, -1 if memory failed to allocate + */ +void fill_memory_blocks(argon2_instance_t *instance, uint32_t pass); + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.c new file mode 100644 index 0000000000..a08acdda80 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.c @@ -0,0 +1,305 @@ +#include "argon2-encoding.h" +#include "argon2-core.h" +#include "utils.h" +#include +#include +#include +#include + +/* + * Example code for a decoder and encoder of "hash strings", with Argon2 + * parameters. + * + * The code was originally written by Thomas Pornin , + * to whom comments and remarks may be sent. It is released under what + * should amount to Public Domain or its closest equivalent; the + * following mantra is supposed to incarnate that fact with all the + * proper legal rituals: + * + * --------------------------------------------------------------------- + * This file is provided under the terms of Creative Commons CC0 1.0 + * Public Domain Dedication. To the extent possible under law, the + * author (Thomas Pornin) has waived all copyright and related or + * neighboring rights to this file. This work is published from: Canada. + * --------------------------------------------------------------------- + * + * Copyright (c) 2015 Thomas Pornin + */ + +/* ==================================================================== */ + +/* + * Decode decimal integer from 'str'; the value is written in '*v'. + * Returned value is a pointer to the next non-decimal character in the + * string. If there is no digit at all, or the value encoding is not + * minimal (extra leading zeros), or the value does not fit in an + * 'unsigned long', then NULL is returned. + */ +static const char * +decode_decimal(const char *str, unsigned long *v) +{ + const char *orig; + unsigned long acc; + + acc = 0; + for (orig = str;; str++) { + int c; + + c = *str; + if (c < '0' || c > '9') { + break; + } + c -= '0'; + if (acc > (ULONG_MAX / 10)) { + return NULL; + } + acc *= 10; + if ((unsigned long) c > (ULONG_MAX - acc)) { + return NULL; + } + acc += (unsigned long) c; + } + if (str == orig || (*orig == '0' && str != (orig + 1))) { + return NULL; + } + *v = acc; + return str; +} + +/* ==================================================================== */ +/* + * Code specific to Argon2. + * + * The code below applies the following format: + * + * $argon2[$v=]$m=,t=,p=$$ + * + * where is either 'i', is a decimal integer (positive, fits in an + * 'unsigned long') and is Base64-encoded data (no '=' padding characters, + * no newline or whitespace). + * + * The last two binary chunks (encoded in Base64) are, in that order, + * the salt and the output. Both are required. The binary salt length and the + * output length must be in the allowed ranges defined in argon2.h. + * + * The ctx struct must contain buffers large enough to hold the salt and pwd + * when it is fed into decode_string. + */ + +/* + * Decode an Argon2i hash string into the provided structure 'ctx'. + * Returned value is ARGON2_OK on success. + */ +int +decode_string(argon2_context *ctx, const char *str, argon2_type type) +{ +/* Prefix checking */ +#define CC(prefix) \ + do { \ + size_t cc_len = strlen(prefix); \ + if (strncmp(str, prefix, cc_len) != 0) { \ + return ARGON2_DECODING_FAIL; \ + } \ + str += cc_len; \ + } while ((void) 0, 0) + +/* Optional prefix checking with supplied code */ +#define CC_opt(prefix, code) \ + do { \ + size_t cc_len = strlen(prefix); \ + if (strncmp(str, prefix, cc_len) == 0) { \ + str += cc_len; \ + { \ + code; \ + } \ + } \ + } while ((void) 0, 0) + +/* Decoding prefix into decimal */ +#define DECIMAL(x) \ + do { \ + unsigned long dec_x; \ + str = decode_decimal(str, &dec_x); \ + if (str == NULL) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (x) = dec_x; \ + } while ((void) 0, 0) + +/* Decoding prefix into uint32_t decimal */ +#define DECIMAL_U32(x) \ + do { \ + unsigned long dec_x; \ + str = decode_decimal(str, &dec_x); \ + if (str == NULL || dec_x > UINT32_MAX) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (x) = (uint32_t)dec_x; \ + } while ((void)0, 0) + +/* Decoding base64 into a binary buffer */ +#define BIN(buf, max_len, len) \ + do { \ + size_t bin_len = (max_len); \ + const char *str_end; \ + if (sodium_base642bin((buf), (max_len), str, strlen(str), NULL, \ + &bin_len, &str_end, \ + sodium_base64_VARIANT_ORIGINAL_NO_PADDING) != 0 || \ + bin_len > UINT32_MAX) { \ + return ARGON2_DECODING_FAIL; \ + } \ + (len) = (uint32_t) bin_len; \ + str = str_end; \ + } while ((void) 0, 0) + + size_t maxsaltlen = ctx->saltlen; + size_t maxoutlen = ctx->outlen; + int validation_result; + uint32_t version = 0; + + ctx->saltlen = 0; + ctx->outlen = 0; + + if (type == Argon2_id) { + CC("$argon2id"); + } else if (type == Argon2_i) { + CC("$argon2i"); + } else { + return ARGON2_INCORRECT_TYPE; + } + CC("$v="); + DECIMAL_U32(version); + if (version != ARGON2_VERSION_NUMBER) { + return ARGON2_INCORRECT_TYPE; + } + CC("$m="); + DECIMAL_U32(ctx->m_cost); + if (ctx->m_cost > UINT32_MAX) { + return ARGON2_INCORRECT_TYPE; + } + CC(",t="); + DECIMAL_U32(ctx->t_cost); + if (ctx->t_cost > UINT32_MAX) { + return ARGON2_INCORRECT_TYPE; + } + CC(",p="); + DECIMAL_U32(ctx->lanes); + if (ctx->lanes > UINT32_MAX) { + return ARGON2_INCORRECT_TYPE; + } + ctx->threads = ctx->lanes; + + CC("$"); + BIN(ctx->salt, maxsaltlen, ctx->saltlen); + CC("$"); + BIN(ctx->out, maxoutlen, ctx->outlen); + validation_result = validate_inputs(ctx); + if (validation_result != ARGON2_OK) { + return validation_result; + } + if (*str == 0) { + return ARGON2_OK; + } + return ARGON2_DECODING_FAIL; + +#undef CC +#undef CC_opt +#undef DECIMAL +#undef BIN +} + +#define U32_STR_MAXSIZE 11U + +static void +u32_to_string(char *str, uint32_t x) +{ + char tmp[U32_STR_MAXSIZE - 1U]; + size_t i; + + i = sizeof tmp; + do { + tmp[--i] = (x % (uint32_t) 10U) + '0'; + x /= (uint32_t) 10U; + } while (x != 0U && i != 0U); + memcpy(str, &tmp[i], (sizeof tmp) - i); + str[(sizeof tmp) - i] = 0; +} + +/* + * Encode an argon2i hash string into the provided buffer. 'dst_len' + * contains the size, in characters, of the 'dst' buffer; if 'dst_len' + * is less than the number of required characters (including the + * terminating 0), then this function returns 0. + * + * If pp->output_len is 0, then the hash string will be a salt string + * (no output). if pp->salt_len is also 0, then the string will be a + * parameter-only string (no salt and no output). + * + * On success, ARGON2_OK is returned. + */ +int +encode_string(char *dst, size_t dst_len, argon2_context *ctx, argon2_type type) +{ +#define SS(str) \ + do { \ + size_t pp_len = strlen(str); \ + if (pp_len >= dst_len) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + memcpy(dst, str, pp_len + 1); \ + dst += pp_len; \ + dst_len -= pp_len; \ + } while ((void) 0, 0) + +#define SX(x) \ + do { \ + char tmp[U32_STR_MAXSIZE]; \ + u32_to_string(tmp, x); \ + SS(tmp); \ + } while ((void) 0, 0) + +#define SB(buf, len) \ + do { \ + size_t sb_len; \ + if (sodium_bin2base64(dst, dst_len, (buf), (len), \ + sodium_base64_VARIANT_ORIGINAL_NO_PADDING) == NULL) { \ + return ARGON2_ENCODING_FAIL; \ + } \ + sb_len = strlen(dst); \ + dst += sb_len; \ + dst_len -= sb_len; \ + } while ((void) 0, 0) + + int validation_result; + + switch (type) { + case Argon2_id: + SS("$argon2id$v="); break; + case Argon2_i: + SS("$argon2i$v="); break; + default: + return ARGON2_ENCODING_FAIL; + } + validation_result = validate_inputs(ctx); + if (validation_result != ARGON2_OK) { + return validation_result; + } + SX(ARGON2_VERSION_NUMBER); + SS("$m="); + SX(ctx->m_cost); + SS(",t="); + SX(ctx->t_cost); + SS(",p="); + SX(ctx->lanes); + + SS("$"); + SB(ctx->salt, ctx->saltlen); + + SS("$"); + SB(ctx->out, ctx->outlen); + return ARGON2_OK; + +#undef SS +#undef SX +#undef SB +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.h b/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.h new file mode 100644 index 0000000000..e929b31dc3 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-encoding.h @@ -0,0 +1,33 @@ +#ifndef argon2_encoding_H +#define argon2_encoding_H + +#include "argon2.h" + +/* + * encode an Argon2 hash string into the provided buffer. 'dst_len' + * contains the size, in characters, of the 'dst' buffer; if 'dst_len' + * is less than the number of required characters (including the + * terminating 0), then this function returns 0. + * + * if ctx->outlen is 0, then the hash string will be a salt string + * (no output). if ctx->saltlen is also 0, then the string will be a + * parameter-only string (no salt and no output). + * + * On success, ARGON2_OK is returned. + * + * No other parameters are checked + */ +int encode_string(char *dst, size_t dst_len, argon2_context *ctx, + argon2_type type); + +/* + * Decodes an Argon2 hash string into the provided structure 'ctx'. + * The fields ctx.saltlen, ctx.adlen, ctx.outlen set the maximal salt, ad, out + * length values + * that are allowed; invalid input string causes an error + * + * Returned value is ARGON2_OK on success. + */ +int decode_string(argon2_context *ctx, const char *str, argon2_type type); + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx2.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx2.c new file mode 100644 index 0000000000..8acb42ca4d --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx2.c @@ -0,0 +1,239 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include + +#include "argon2-core.h" +#include "argon2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" + +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_EMMINTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# pragma GCC target("sse4.1") +# pragma GCC target("avx2") +# endif + +# ifdef _MSC_VER +# include /* for _mm_set_epi64x */ +# endif +#include +#include +#include +#include + +# include "blamka-round-avx2.h" + +static void +fill_block(__m256i *state, const uint8_t *ref_block, uint8_t *next_block) +{ + __m256i block_XY[ARGON2_HWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + block_XY[i] = state[i] = _mm256_xor_si256( + state[i], _mm256_loadu_si256((__m256i const *) (&ref_block[32 * i]))); + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5], + state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]); + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i], + state[16 + i], state[20 + i], state[24 + i], state[28 + i]); + } + + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + state[i] = _mm256_xor_si256(state[i], block_XY[i]); + _mm256_storeu_si256((__m256i *) (&next_block[32 * i]), state[i]); + } +} + +static void +fill_block_with_xor(__m256i *state, const uint8_t *ref_block, + uint8_t *next_block) +{ + __m256i block_XY[ARGON2_HWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + state[i] = _mm256_xor_si256( + state[i], _mm256_loadu_si256((__m256i const *) (&ref_block[32 * i]))); + block_XY[i] = _mm256_xor_si256( + state[i], _mm256_loadu_si256((__m256i const *) (&next_block[32 * i]))); + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND_1(state[8 * i + 0], state[8 * i + 4], state[8 * i + 1], state[8 * i + 5], + state[8 * i + 2], state[8 * i + 6], state[8 * i + 3], state[8 * i + 7]); + } + + for (i = 0; i < 4; ++i) { + BLAKE2_ROUND_2(state[ 0 + i], state[ 4 + i], state[ 8 + i], state[12 + i], + state[16 + i], state[20 + i], state[24 + i], state[28 + i]); + } + + for (i = 0; i < ARGON2_HWORDS_IN_BLOCK; i++) { + state[i] = _mm256_xor_si256(state[i], block_XY[i]); + _mm256_storeu_si256((__m256i *) (&next_block[32 * i]), state[i]); + } +} + +static void +generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, uint64_t *pseudo_rands) +{ + block address_block, input_block, tmp_block; + uint32_t i; + + init_block_value(&address_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + /* Temporary zero-initialized blocks */ + __m256i zero_block[ARGON2_HWORDS_IN_BLOCK]; + __m256i zero2_block[ARGON2_HWORDS_IN_BLOCK]; + + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + init_block_value(&address_block, 0); + init_block_value(&tmp_block, 0); + /* Increasing index counter */ + input_block.v[6]++; + /* First iteration of G */ + fill_block_with_xor(zero_block, (uint8_t *) &input_block.v, + (uint8_t *) &tmp_block.v); + /* Second iteration of G */ + fill_block_with_xor(zero2_block, (uint8_t *) &tmp_block.v, + (uint8_t *) &address_block.v); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void +fill_segment_avx2(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m256i state[ARGON2_HWORDS_IN_BLOCK]; + int data_independent_addressing = 1; + + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + + if (instance == NULL) { + return; + } + + if (instance->type == Argon2_id && + (position.pass != 0 || position.slice >= ARGON2_SYNC_POINTS / 2)) { + data_independent_addressing = 0; + } + + pseudo_rands = instance->pseudo_rands; + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->region->memory + prev_offset)->v), + ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { +#pragma warning(push) +#pragma warning(disable : 6385) + pseudo_rand = pseudo_rands[i]; +#pragma warning(pop) + } else { + pseudo_rand = instance->region->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = instance->region->memory + + instance->lane_length * ref_lane + ref_index; + curr_block = instance->region->memory + curr_offset; + if (position.pass != 0) { + fill_block_with_xor(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } else { + fill_block(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } + } +} +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx512f.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx512f.c new file mode 100644 index 0000000000..1f1ec8b3b4 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-avx512f.c @@ -0,0 +1,244 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include + +#include "argon2-core.h" +#include "argon2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" + +#if defined(HAVE_AVX512FINTRIN_H) && defined(HAVE_AVX2INTRIN_H) && \ + defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# pragma GCC target("sse4.1") +# pragma GCC target("avx2") +# pragma GCC target("avx512f") +# endif + +# ifdef _MSC_VER +# include /* for _mm_set_epi64x */ +# endif +#include +#include +#include +#include + +# include "blamka-round-avx512f.h" + +static void +fill_block(__m512i *state, const uint8_t *ref_block, uint8_t *next_block) +{ + __m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) { + block_XY[i] = state[i] = _mm512_xor_si512( + state[i], _mm512_loadu_si512((__m512i const *) (&ref_block[64 * i]))); + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND_1( + state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], + state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND_2( + state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i], + state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]); + } + + for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) { + state[i] = _mm512_xor_si512(state[i], block_XY[i]); + _mm512_storeu_si512((__m512i *) (&next_block[64 * i]), state[i]); + } +} + +static void +fill_block_with_xor(__m512i *state, const uint8_t *ref_block, + uint8_t *next_block) +{ + __m512i block_XY[ARGON2_512BIT_WORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) { + state[i] = _mm512_xor_si512( + state[i], _mm512_loadu_si512((__m512i const *) (&ref_block[64 * i]))); + block_XY[i] = _mm512_xor_si512( + state[i], _mm512_loadu_si512((__m512i const *) (&next_block[64 * i]))); + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND_1( + state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], state[8 * i + 3], + state[8 * i + 4], state[8 * i + 5], state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 2; ++i) { + BLAKE2_ROUND_2( + state[2 * 0 + i], state[2 * 1 + i], state[2 * 2 + i], state[2 * 3 + i], + state[2 * 4 + i], state[2 * 5 + i], state[2 * 6 + i], state[2 * 7 + i]); + } + + for (i = 0; i < ARGON2_512BIT_WORDS_IN_BLOCK; i++) { + state[i] = _mm512_xor_si512(state[i], block_XY[i]); + _mm512_storeu_si512((__m512i *) (&next_block[64 * i]), state[i]); + } +} + +static void +generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, uint64_t *pseudo_rands) +{ + block address_block, input_block, tmp_block; + uint32_t i; + + init_block_value(&address_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + /* Temporary zero-initialized blocks */ + __m512i zero_block[ARGON2_512BIT_WORDS_IN_BLOCK]; + __m512i zero2_block[ARGON2_512BIT_WORDS_IN_BLOCK]; + + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + init_block_value(&address_block, 0); + init_block_value(&tmp_block, 0); + /* Increasing index counter */ + input_block.v[6]++; + /* First iteration of G */ + fill_block_with_xor(zero_block, (uint8_t *) &input_block.v, + (uint8_t *) &tmp_block.v); + /* Second iteration of G */ + fill_block_with_xor(zero2_block, (uint8_t *) &tmp_block.v, + (uint8_t *) &address_block.v); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void +fill_segment_avx512f(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m512i state[ARGON2_512BIT_WORDS_IN_BLOCK]; + int data_independent_addressing = 1; + + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + + if (instance == NULL) { + return; + } + + if (instance->type == Argon2_id && + (position.pass != 0 || position.slice >= ARGON2_SYNC_POINTS / 2)) { + data_independent_addressing = 0; + } + + pseudo_rands = instance->pseudo_rands; + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->region->memory + prev_offset)->v), + ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { +#pragma warning(push) +#pragma warning(disable : 6385) + pseudo_rand = pseudo_rands[i]; +#pragma warning(pop) + } else { + pseudo_rand = instance->region->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = instance->region->memory + + instance->lane_length * ref_lane + ref_index; + curr_block = instance->region->memory + curr_offset; + if (position.pass != 0) { + fill_block_with_xor(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } else { + fill_block(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } + } +} +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ref.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ref.c new file mode 100644 index 0000000000..75e8d8f5ea --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ref.c @@ -0,0 +1,233 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include + +#include "argon2-core.h" +#include "argon2.h" +#include "blamka-round-ref.h" +#include "private/common.h" + +static void +fill_block(const block *prev_block, const block *ref_block, block *next_block) +{ + block blockR, block_tmp; + unsigned i; + + copy_block(&blockR, ref_block); + xor_block(&blockR, prev_block); + copy_block(&block_tmp, &blockR); + /* Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block + Apply Blake2 on columns of 64-bit words: (0,1,...,15), then + (16,17,..31)... finally (112,113,...127) */ + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND_NOMSG( + blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], + blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], + blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], + blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], + blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], + blockR.v[16 * i + 15]); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (i = 0; i < 8; i++) { + BLAKE2_ROUND_NOMSG( + blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], + blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], + blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], + blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], + blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], + blockR.v[2 * i + 113]); + } + + copy_block(next_block, &block_tmp); + xor_block(next_block, &blockR); +} + +static void +fill_block_with_xor(const block *prev_block, const block *ref_block, + block *next_block) +{ + block blockR, block_tmp; + unsigned i; + + copy_block(&blockR, ref_block); + xor_block(&blockR, prev_block); + copy_block(&block_tmp, &blockR); + xor_block(&block_tmp, + next_block); /* Saving the next block contents for XOR over */ + /* Now blockR = ref_block + prev_block and bloc_tmp = ref_block + prev_block + * + next_block */ + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND_NOMSG( + blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2], + blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5], + blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8], + blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11], + blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14], + blockR.v[16 * i + 15]); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (i = 0; i < 8; i++) { + BLAKE2_ROUND_NOMSG( + blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16], + blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33], + blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64], + blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81], + blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112], + blockR.v[2 * i + 113]); + } + + copy_block(next_block, &block_tmp); + xor_block(next_block, &blockR); +} + +/* + * Generate pseudo-random values to reference blocks in the segment and puts + * them into the array + * @param instance Pointer to the current instance + * @param position Pointer to the current position + * @param pseudo_rands Pointer to the array of 64-bit values + * @pre pseudo_rands must point to @a instance->segment_length allocated values + */ +static void +generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, uint64_t *pseudo_rands) +{ + block zero_block, input_block, address_block, tmp_block; + uint32_t i; + + init_block_value(&zero_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + input_block.v[6]++; + init_block_value(&tmp_block, 0); + init_block_value(&address_block, 0); + fill_block_with_xor(&zero_block, &input_block, &tmp_block); + fill_block_with_xor(&zero_block, &tmp_block, &address_block); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void +fill_segment_ref(const argon2_instance_t *instance, argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index; + uint32_t i; + int data_independent_addressing = 1; + + if (instance == NULL) { + return; + } + + if (instance->type == Argon2_id && + (position.pass != 0 || position.slice >= ARGON2_SYNC_POINTS / 2)) { + data_independent_addressing = 0; + } + + pseudo_rands = instance->pseudo_rands; + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { +#pragma warning(push) +#pragma warning(disable : 6385) + pseudo_rand = pseudo_rands[i]; +#pragma warning(pop) + } else { + pseudo_rand = instance->region->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = instance->region->memory + + instance->lane_length * ref_lane + ref_index; + curr_block = instance->region->memory + curr_offset; + if (position.pass != 0) { + fill_block_with_xor(instance->region->memory + prev_offset, + ref_block, curr_block); + } else { + fill_block(instance->region->memory + prev_offset, ref_block, + curr_block); + } + } +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ssse3.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ssse3.c new file mode 100644 index 0000000000..796c445560 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2-fill-block-ssse3.c @@ -0,0 +1,238 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include + +#include "argon2-core.h" +#include "argon2.h" +#include "private/common.h" +#include "private/sse2_64_32.h" + +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# endif + +# ifdef _MSC_VER +# include /* for _mm_set_epi64x */ +# endif +# include +# include + +# include "blamka-round-ssse3.h" + +static void +fill_block(__m128i *state, const uint8_t *ref_block, uint8_t *next_block) +{ + __m128i block_XY[ARGON2_OWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + block_XY[i] = state[i] = _mm_xor_si128( + state[i], _mm_loadu_si128((__m128i const *) (&ref_block[16 * i]))); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], + state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], + state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], + state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], + state[8 * 6 + i], state[8 * 7 + i]); + } + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + state[i] = _mm_xor_si128(state[i], block_XY[i]); + _mm_storeu_si128((__m128i *) (&next_block[16 * i]), state[i]); + } +} + +static void +fill_block_with_xor(__m128i *state, const uint8_t *ref_block, + uint8_t *next_block) +{ + __m128i block_XY[ARGON2_OWORDS_IN_BLOCK]; + uint32_t i; + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + state[i] = _mm_xor_si128( + state[i], _mm_loadu_si128((__m128i const *) (&ref_block[16 * i]))); + block_XY[i] = _mm_xor_si128( + state[i], _mm_loadu_si128((__m128i const *) (&next_block[16 * i]))); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * i + 0], state[8 * i + 1], state[8 * i + 2], + state[8 * i + 3], state[8 * i + 4], state[8 * i + 5], + state[8 * i + 6], state[8 * i + 7]); + } + + for (i = 0; i < 8; ++i) { + BLAKE2_ROUND(state[8 * 0 + i], state[8 * 1 + i], state[8 * 2 + i], + state[8 * 3 + i], state[8 * 4 + i], state[8 * 5 + i], + state[8 * 6 + i], state[8 * 7 + i]); + } + + for (i = 0; i < ARGON2_OWORDS_IN_BLOCK; i++) { + state[i] = _mm_xor_si128(state[i], block_XY[i]); + _mm_storeu_si128((__m128i *) (&next_block[16 * i]), state[i]); + } +} + +static void +generate_addresses(const argon2_instance_t *instance, + const argon2_position_t *position, uint64_t *pseudo_rands) +{ + block address_block, input_block, tmp_block; + uint32_t i; + + init_block_value(&address_block, 0); + init_block_value(&input_block, 0); + + if (instance != NULL && position != NULL) { + input_block.v[0] = position->pass; + input_block.v[1] = position->lane; + input_block.v[2] = position->slice; + input_block.v[3] = instance->memory_blocks; + input_block.v[4] = instance->passes; + input_block.v[5] = instance->type; + + for (i = 0; i < instance->segment_length; ++i) { + if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) { + /* Temporary zero-initialized blocks */ + __m128i zero_block[ARGON2_OWORDS_IN_BLOCK]; + __m128i zero2_block[ARGON2_OWORDS_IN_BLOCK]; + + memset(zero_block, 0, sizeof(zero_block)); + memset(zero2_block, 0, sizeof(zero2_block)); + init_block_value(&address_block, 0); + init_block_value(&tmp_block, 0); + /* Increasing index counter */ + input_block.v[6]++; + /* First iteration of G */ + fill_block_with_xor(zero_block, (uint8_t *) &input_block.v, + (uint8_t *) &tmp_block.v); + /* Second iteration of G */ + fill_block_with_xor(zero2_block, (uint8_t *) &tmp_block.v, + (uint8_t *) &address_block.v); + } + + pseudo_rands[i] = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK]; + } + } +} + +void +fill_segment_ssse3(const argon2_instance_t *instance, + argon2_position_t position) +{ + block *ref_block = NULL, *curr_block = NULL; + uint64_t pseudo_rand, ref_index, ref_lane; + uint32_t prev_offset, curr_offset; + uint32_t starting_index, i; + __m128i state[ARGON2_OWORDS_IN_BLOCK]; + int data_independent_addressing = 1; + + /* Pseudo-random values that determine the reference block position */ + uint64_t *pseudo_rands = NULL; + + if (instance == NULL) { + return; + } + + if (instance->type == Argon2_id && + (position.pass != 0 || position.slice >= ARGON2_SYNC_POINTS / 2)) { + data_independent_addressing = 0; + } + + pseudo_rands = instance->pseudo_rands; + + if (data_independent_addressing) { + generate_addresses(instance, &position, pseudo_rands); + } + + starting_index = 0; + + if ((0 == position.pass) && (0 == position.slice)) { + starting_index = 2; /* we have already generated the first two blocks */ + } + + /* Offset of the current block */ + curr_offset = position.lane * instance->lane_length + + position.slice * instance->segment_length + starting_index; + + if (0 == curr_offset % instance->lane_length) { + /* Last block in this lane */ + prev_offset = curr_offset + instance->lane_length - 1; + } else { + /* Previous block */ + prev_offset = curr_offset - 1; + } + + memcpy(state, ((instance->region->memory + prev_offset)->v), + ARGON2_BLOCK_SIZE); + + for (i = starting_index; i < instance->segment_length; + ++i, ++curr_offset, ++prev_offset) { + /*1.1 Rotating prev_offset if needed */ + if (curr_offset % instance->lane_length == 1) { + prev_offset = curr_offset - 1; + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + if (data_independent_addressing) { +#pragma warning(push) +#pragma warning(disable : 6385) + pseudo_rand = pseudo_rands[i]; +#pragma warning(pop) + } else { + pseudo_rand = instance->region->memory[prev_offset].v[0]; + } + + /* 1.2.2 Computing the lane of the reference block */ + ref_lane = ((pseudo_rand >> 32)) % instance->lanes; + + if ((position.pass == 0) && (position.slice == 0)) { + /* Can not reference other lanes yet */ + ref_lane = position.lane; + } + + /* 1.2.3 Computing the number of possible reference block within the + * lane. + */ + position.index = i; + ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF, + ref_lane == position.lane); + + /* 2 Creating a new block */ + ref_block = instance->region->memory + + instance->lane_length * ref_lane + ref_index; + curr_block = instance->region->memory + curr_offset; + if (position.pass != 0) { + fill_block_with_xor(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } else { + fill_block(state, (uint8_t *) ref_block->v, + (uint8_t *) curr_block->v); + } + } +} +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2.c b/libs/libsodium/src/crypto_pwhash/argon2/argon2.c new file mode 100644 index 0000000000..ac1628c991 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2.c @@ -0,0 +1,277 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with + * this software. If not, see + * . + */ + +#include +#include +#include +#include +#include + +#include "utils.h" + +#include "argon2-core.h" +#include "argon2-encoding.h" +#include "argon2.h" + +int +argon2_ctx(argon2_context *context, argon2_type type) +{ + /* 1. Validate all inputs */ + int result = validate_inputs(context); + uint32_t memory_blocks, segment_length; + uint32_t pass; + argon2_instance_t instance; + + if (ARGON2_OK != result) { + return result; + } + + if (type != Argon2_id && type != Argon2_i) { + return ARGON2_INCORRECT_TYPE; + } + + /* 2. Align memory size */ + /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */ + memory_blocks = context->m_cost; + + if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) { + memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes; + } + + segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS); + /* Ensure that all segments have equal length */ + memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS); + + instance.region = NULL; + instance.passes = context->t_cost; + instance.current_pass = ~ 0U; + instance.memory_blocks = memory_blocks; + instance.segment_length = segment_length; + instance.lane_length = segment_length * ARGON2_SYNC_POINTS; + instance.lanes = context->lanes; + instance.threads = context->threads; + instance.type = type; + + /* 3. Initialization: Hashing inputs, allocating memory, filling first + * blocks + */ + result = initialize(&instance, context); + + if (ARGON2_OK != result) { + return result; + } + + /* 4. Filling memory */ + for (pass = 0; pass < instance.passes; pass++) { + fill_memory_blocks(&instance, pass); + } + + /* 5. Finalization */ + finalize(context, &instance); + + return ARGON2_OK; +} + +int +argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, const size_t pwdlen, + const void *salt, const size_t saltlen, void *hash, + const size_t hashlen, char *encoded, const size_t encodedlen, + argon2_type type) +{ + argon2_context context; + int result; + uint8_t *out; + + if (pwdlen > ARGON2_MAX_PWD_LENGTH) { + return ARGON2_PWD_TOO_LONG; + } + + if (hashlen > ARGON2_MAX_OUTLEN) { + return ARGON2_OUTPUT_TOO_LONG; + } + + if (saltlen > ARGON2_MAX_SALT_LENGTH) { + return ARGON2_SALT_TOO_LONG; + } + + out = (uint8_t *) malloc(hashlen); + if (!out) { + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + context.out = (uint8_t *) out; + context.outlen = (uint32_t) hashlen; + context.pwd = (uint8_t *) pwd; + context.pwdlen = (uint32_t) pwdlen; + context.salt = (uint8_t *) salt; + context.saltlen = (uint32_t) saltlen; + context.secret = NULL; + context.secretlen = 0; + context.ad = NULL; + context.adlen = 0; + context.t_cost = t_cost; + context.m_cost = m_cost; + context.lanes = parallelism; + context.threads = parallelism; + context.flags = ARGON2_DEFAULT_FLAGS; + + result = argon2_ctx(&context, type); + + if (result != ARGON2_OK) { + sodium_memzero(out, hashlen); + free(out); + return result; + } + + /* if raw hash requested, write it */ + if (hash) { + memcpy(hash, out, hashlen); + } + + /* if encoding requested, write it */ + if (encoded && encodedlen) { + if (encode_string(encoded, encodedlen, &context, type) != ARGON2_OK) { + sodium_memzero(out, hashlen); + sodium_memzero(encoded, encodedlen); + free(out); + return ARGON2_ENCODING_FAIL; + } + } + + sodium_memzero(out, hashlen); + free(out); + + return ARGON2_OK; +} + +int +argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, char *encoded, + const size_t encodedlen) +{ + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_i); +} + +int +argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, const size_t saltlen, + void *hash, const size_t hashlen) +{ + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_i); +} + +int +argon2id_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, char *encoded, + const size_t encodedlen) +{ + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + NULL, hashlen, encoded, encodedlen, Argon2_id); +} + +int +argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, const size_t saltlen, + void *hash, const size_t hashlen) +{ + return argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, + hash, hashlen, NULL, 0, Argon2_id); +} + +int +argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen, + argon2_type type) +{ + argon2_context ctx; + uint8_t *out; + int decode_result; + int ret; + size_t encoded_len; + + memset(&ctx, 0, sizeof ctx); + + ctx.pwd = NULL; + ctx.pwdlen = 0; + ctx.secret = NULL; + ctx.secretlen = 0; + + /* max values, to be updated in decode_string */ + encoded_len = strlen(encoded); + if (encoded_len > UINT32_MAX) { + return ARGON2_DECODING_LENGTH_FAIL; + } + ctx.adlen = (uint32_t) encoded_len; + ctx.saltlen = (uint32_t) encoded_len; + ctx.outlen = (uint32_t) encoded_len; + + ctx.ad = (uint8_t *) malloc(ctx.adlen); + ctx.salt = (uint8_t *) malloc(ctx.saltlen); + ctx.out = (uint8_t *) malloc(ctx.outlen); + if (!ctx.out || !ctx.salt || !ctx.ad) { + free(ctx.ad); + free(ctx.salt); + free(ctx.out); + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + out = (uint8_t *) malloc(ctx.outlen); + if (!out) { + free(ctx.ad); + free(ctx.salt); + free(ctx.out); + return ARGON2_MEMORY_ALLOCATION_ERROR; + } + + decode_result = decode_string(&ctx, encoded, type); + if (decode_result != ARGON2_OK) { + free(ctx.ad); + free(ctx.salt); + free(ctx.out); + free(out); + return decode_result; + } + + ret = argon2_hash(ctx.t_cost, ctx.m_cost, ctx.threads, pwd, pwdlen, + ctx.salt, ctx.saltlen, out, ctx.outlen, NULL, 0, type); + + free(ctx.ad); + free(ctx.salt); + + if (ret != ARGON2_OK || sodium_memcmp(out, ctx.out, ctx.outlen) != 0) { + ret = ARGON2_VERIFY_MISMATCH; + } + free(out); + free(ctx.out); + + return ret; +} + +int +argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen) +{ + return argon2_verify(encoded, pwd, pwdlen, Argon2_i); +} + +int +argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen) +{ + return argon2_verify(encoded, pwd, pwdlen, Argon2_id); +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/argon2.h b/libs/libsodium/src/crypto_pwhash/argon2/argon2.h new file mode 100644 index 0000000000..85ca4dd373 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/argon2.h @@ -0,0 +1,305 @@ +/* + * Argon2 source code package + * + * Written by Daniel Dinu and Dmitry Khovratovich, 2015 + * + * This work is licensed under a Creative Commons CC0 1.0 License/Waiver. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * . + */ +#ifndef argon2_H +#define argon2_H + +#include +#include +#include + +/* + * Argon2 input parameter restrictions + */ + +/* Minimum and maximum number of lanes (degree of parallelism) */ +#define ARGON2_MIN_LANES UINT32_C(1) +#define ARGON2_MAX_LANES UINT32_C(0xFFFFFF) + +/* Minimum and maximum number of threads */ +#define ARGON2_MIN_THREADS UINT32_C(1) +#define ARGON2_MAX_THREADS UINT32_C(0xFFFFFF) + +/* Number of synchronization points between lanes per pass */ +#define ARGON2_SYNC_POINTS UINT32_C(4) + +/* Minimum and maximum digest size in bytes */ +#define ARGON2_MIN_OUTLEN UINT32_C(16) +#define ARGON2_MAX_OUTLEN UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */ +#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */ + +#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b)) +/* Max memory size is half the addressing space, topping at 2^32 blocks (4 TB) + */ +#define ARGON2_MAX_MEMORY_BITS \ + ARGON2_MIN(UINT32_C(32), (sizeof(void *) * CHAR_BIT - 10 - 1)) +#define ARGON2_MAX_MEMORY \ + ARGON2_MIN(UINT32_C(0xFFFFFFFF), UINT64_C(1) << ARGON2_MAX_MEMORY_BITS) + +/* Minimum and maximum number of passes */ +#define ARGON2_MIN_TIME UINT32_C(1) +#define ARGON2_MAX_TIME UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum password length in bytes */ +#define ARGON2_MIN_PWD_LENGTH UINT32_C(0) +#define ARGON2_MAX_PWD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum associated data length in bytes */ +#define ARGON2_MIN_AD_LENGTH UINT32_C(0) +#define ARGON2_MAX_AD_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum salt length in bytes */ +#define ARGON2_MIN_SALT_LENGTH UINT32_C(8) +#define ARGON2_MAX_SALT_LENGTH UINT32_C(0xFFFFFFFF) + +/* Minimum and maximum key length in bytes */ +#define ARGON2_MIN_SECRET UINT32_C(0) +#define ARGON2_MAX_SECRET UINT32_C(0xFFFFFFFF) + +#define ARGON2_FLAG_CLEAR_PASSWORD (UINT32_C(1) << 0) +#define ARGON2_FLAG_CLEAR_SECRET (UINT32_C(1) << 1) +#define ARGON2_FLAG_CLEAR_MEMORY (UINT32_C(1) << 2) +#define ARGON2_DEFAULT_FLAGS (UINT32_C(0)) + +/* Error codes */ +typedef enum Argon2_ErrorCodes { + ARGON2_OK = 0, + + ARGON2_OUTPUT_PTR_NULL = -1, + + ARGON2_OUTPUT_TOO_SHORT = -2, + ARGON2_OUTPUT_TOO_LONG = -3, + + ARGON2_PWD_TOO_SHORT = -4, + ARGON2_PWD_TOO_LONG = -5, + + ARGON2_SALT_TOO_SHORT = -6, + ARGON2_SALT_TOO_LONG = -7, + + ARGON2_AD_TOO_SHORT = -8, + ARGON2_AD_TOO_LONG = -9, + + ARGON2_SECRET_TOO_SHORT = -10, + ARGON2_SECRET_TOO_LONG = -11, + + ARGON2_TIME_TOO_SMALL = -12, + ARGON2_TIME_TOO_LARGE = -13, + + ARGON2_MEMORY_TOO_LITTLE = -14, + ARGON2_MEMORY_TOO_MUCH = -15, + + ARGON2_LANES_TOO_FEW = -16, + ARGON2_LANES_TOO_MANY = -17, + + ARGON2_PWD_PTR_MISMATCH = -18, /* NULL ptr with non-zero length */ + ARGON2_SALT_PTR_MISMATCH = -19, /* NULL ptr with non-zero length */ + ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */ + ARGON2_AD_PTR_MISMATCH = -21, /* NULL ptr with non-zero length */ + + ARGON2_MEMORY_ALLOCATION_ERROR = -22, + + ARGON2_FREE_MEMORY_CBK_NULL = -23, + ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24, + + ARGON2_INCORRECT_PARAMETER = -25, + ARGON2_INCORRECT_TYPE = -26, + + ARGON2_OUT_PTR_MISMATCH = -27, + + ARGON2_THREADS_TOO_FEW = -28, + ARGON2_THREADS_TOO_MANY = -29, + + ARGON2_MISSING_ARGS = -30, + + ARGON2_ENCODING_FAIL = -31, + + ARGON2_DECODING_FAIL = -32, + + ARGON2_THREAD_FAIL = -33, + + ARGON2_DECODING_LENGTH_FAIL = -34, + + ARGON2_VERIFY_MISMATCH = -35 +} argon2_error_codes; + +/* Argon2 external data structures */ + +/* + * Context: structure to hold Argon2 inputs: + * output array and its length, + * password and its length, + * salt and its length, + * secret and its length, + * associated data and its length, + * number of passes, amount of used memory (in KBytes, can be rounded up a bit) + * number of parallel threads that will be run. + * All the parameters above affect the output hash value. + * Additionally, two function pointers can be provided to allocate and + * deallocate the memory (if NULL, memory will be allocated internally). + * Also, three flags indicate whether to erase password, secret as soon as they + * are pre-hashed (and thus not needed anymore), and the entire memory + ***** + * Simplest situation: you have output array out[8], password is stored in + * pwd[32], salt is stored in salt[16], you do not have keys nor associated + *data. + * You need to spend 1 GB of RAM and you run 5 passes of Argon2 with 4 parallel + *lanes. + * You want to erase the password, but you're OK with last pass not being + *erased. + * You want to use the default memory allocator. + * Then you initialize: + * Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false). + */ +typedef struct Argon2_Context { + uint8_t *out; /* output array */ + uint32_t outlen; /* digest length */ + + uint8_t *pwd; /* password array */ + uint32_t pwdlen; /* password length */ + + uint8_t *salt; /* salt array */ + uint32_t saltlen; /* salt length */ + + uint8_t *secret; /* key array */ + uint32_t secretlen; /* key length */ + + uint8_t *ad; /* associated data array */ + uint32_t adlen; /* associated data length */ + + uint32_t t_cost; /* number of passes */ + uint32_t m_cost; /* amount of memory requested (KB) */ + uint32_t lanes; /* number of lanes */ + uint32_t threads; /* maximum number of threads */ + + uint32_t flags; /* array of bool options */ +} argon2_context; + +/* Argon2 primitive type */ +typedef enum Argon2_type { Argon2_i = 1, Argon2_id = 2 } argon2_type; + +/* + * Function that performs memory-hard hashing with certain degree of parallelism + * @param context Pointer to the Argon2 internal structure + * @return Error code if smth is wrong, ARGON2_OK otherwise + */ +int argon2_ctx(argon2_context *context, argon2_type type); + +/** + * Hashes a password with Argon2i, producing an encoded hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hashlen Desired length of the hash in bytes + * @param encoded Buffer where to write the encoded hash + * @param encodedlen Size of the buffer (thus max size of the encoded hash) + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +int argon2i_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen); + +/** + * Hashes a password with Argon2id, producing an encoded hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hashlen Desired length of the hash in bytes + * @param encoded Buffer where to write the encoded hash + * @param encodedlen Size of the buffer (thus max size of the encoded hash) + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +int argon2id_hash_encoded(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, const size_t hashlen, + char *encoded, const size_t encodedlen); + +/** + * Hashes a password with Argon2i, producing a raw hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hash Buffer where to write the raw hash + * @param hashlen Desired length of the hash in bytes + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +int argon2i_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen); + +/** + * Hashes a password with Argon2id, producing a raw hash + * @param t_cost Number of iterations + * @param m_cost Sets memory usage to m_cost kibibytes + * @param parallelism Number of threads and compute lanes + * @param pwd Pointer to password + * @param pwdlen Password size in bytes + * @param salt Pointer to salt + * @param saltlen Salt size in bytes + * @param hash Buffer where to write the raw hash + * @param hashlen Desired length of the hash in bytes + * @pre Different parallelism levels will give different results + * @pre Returns ARGON2_OK if successful + */ +int argon2id_hash_raw(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, + const size_t saltlen, void *hash, const size_t hashlen); + +/* generic function underlying the above ones */ +int argon2_hash(const uint32_t t_cost, const uint32_t m_cost, + const uint32_t parallelism, const void *pwd, + const size_t pwdlen, const void *salt, const size_t saltlen, + void *hash, const size_t hashlen, char *encoded, + const size_t encodedlen, argon2_type type); + +/** + * Verifies a password against an encoded string + * Encoded string is restricted as in validate_inputs() + * @param encoded String encoding parameters, salt, hash + * @param pwd Pointer to password + * @pre Returns ARGON2_OK if successful + */ +int argon2i_verify(const char *encoded, const void *pwd, const size_t pwdlen); + +/** + * Verifies a password against an encoded string + * Encoded string is restricted as in validate_inputs() + * @param encoded String encoding parameters, salt, hash + * @param pwd Pointer to password + * @pre Returns ARGON2_OK if successful + */ +int argon2id_verify(const char *encoded, const void *pwd, const size_t pwdlen); + +/* generic function underlying the above ones */ +int argon2_verify(const char *encoded, const void *pwd, const size_t pwdlen, + argon2_type type); +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.c b/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.c new file mode 100644 index 0000000000..f0364aca87 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include + +#include "crypto_generichash_blake2b.h" +#include "private/common.h" +#include "utils.h" + +#include "blake2b-long.h" + +int +blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) +{ + uint8_t *out = (uint8_t *) pout; + crypto_generichash_blake2b_state blake_state; + uint8_t outlen_bytes[4 /* sizeof(uint32_t) */] = { 0 }; + int ret = -1; + + if (outlen > UINT32_MAX) { + goto fail; /* LCOV_EXCL_LINE */ + } + + /* Ensure little-endian byte order! */ + STORE32_LE(outlen_bytes, (uint32_t) outlen); + +#define TRY(statement) \ + do { \ + ret = statement; \ + if (ret < 0) { \ + goto fail; \ + } \ + } while ((void) 0, 0) + + if (outlen <= crypto_generichash_blake2b_BYTES_MAX) { + TRY(crypto_generichash_blake2b_init(&blake_state, NULL, 0U, outlen)); + TRY(crypto_generichash_blake2b_update(&blake_state, outlen_bytes, + sizeof(outlen_bytes))); + TRY(crypto_generichash_blake2b_update( + &blake_state, (const unsigned char *) in, inlen)); + TRY(crypto_generichash_blake2b_final(&blake_state, out, outlen)); + } else { + uint32_t toproduce; + uint8_t out_buffer[crypto_generichash_blake2b_BYTES_MAX]; + uint8_t in_buffer[crypto_generichash_blake2b_BYTES_MAX]; + TRY(crypto_generichash_blake2b_init( + &blake_state, NULL, 0U, crypto_generichash_blake2b_BYTES_MAX)); + TRY(crypto_generichash_blake2b_update(&blake_state, outlen_bytes, + sizeof(outlen_bytes))); + TRY(crypto_generichash_blake2b_update( + &blake_state, (const unsigned char *) in, inlen)); + TRY(crypto_generichash_blake2b_final( + &blake_state, out_buffer, crypto_generichash_blake2b_BYTES_MAX)); + memcpy(out, out_buffer, crypto_generichash_blake2b_BYTES_MAX / 2); + out += crypto_generichash_blake2b_BYTES_MAX / 2; + toproduce = + (uint32_t) outlen - crypto_generichash_blake2b_BYTES_MAX / 2; + + while (toproduce > crypto_generichash_blake2b_BYTES_MAX) { + memcpy(in_buffer, out_buffer, crypto_generichash_blake2b_BYTES_MAX); + TRY(crypto_generichash_blake2b( + out_buffer, crypto_generichash_blake2b_BYTES_MAX, in_buffer, + crypto_generichash_blake2b_BYTES_MAX, NULL, 0U)); + memcpy(out, out_buffer, crypto_generichash_blake2b_BYTES_MAX / 2); + out += crypto_generichash_blake2b_BYTES_MAX / 2; + toproduce -= crypto_generichash_blake2b_BYTES_MAX / 2; + } + + memcpy(in_buffer, out_buffer, crypto_generichash_blake2b_BYTES_MAX); + TRY(crypto_generichash_blake2b(out_buffer, toproduce, in_buffer, + crypto_generichash_blake2b_BYTES_MAX, + NULL, 0U)); + memcpy(out, out_buffer, toproduce); + } +fail: + sodium_memzero(&blake_state, sizeof(blake_state)); + return ret; +#undef TRY +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.h b/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.h new file mode 100644 index 0000000000..3d6d775521 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blake2b-long.h @@ -0,0 +1,8 @@ +#ifndef blake2b_long_H +#define blake2b_long_H + +#include + +int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen); + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx2.h b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx2.h new file mode 100644 index 0000000000..f3dfa0f506 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx2.h @@ -0,0 +1,150 @@ +#ifndef blamka_round_avx2_H +#define blamka_round_avx2_H + +#include "private/common.h" +#include "private/sse2_64_32.h" + +#define rotr32(x) _mm256_shuffle_epi32(x, _MM_SHUFFLE(2, 3, 0, 1)) +#define rotr24(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10, 3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10)) +#define rotr16(x) _mm256_shuffle_epi8(x, _mm256_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9, 2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9)) +#define rotr63(x) _mm256_xor_si256(_mm256_srli_epi64((x), 63), _mm256_add_epi64((x), (x))) + +#define G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + __m256i ml = _mm256_mul_epu32(A0, B0); \ + ml = _mm256_add_epi64(ml, ml); \ + A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \ + D0 = _mm256_xor_si256(D0, A0); \ + D0 = rotr32(D0); \ + \ + ml = _mm256_mul_epu32(C0, D0); \ + ml = _mm256_add_epi64(ml, ml); \ + C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \ + \ + B0 = _mm256_xor_si256(B0, C0); \ + B0 = rotr24(B0); \ + \ + ml = _mm256_mul_epu32(A1, B1); \ + ml = _mm256_add_epi64(ml, ml); \ + A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \ + D1 = _mm256_xor_si256(D1, A1); \ + D1 = rotr32(D1); \ + \ + ml = _mm256_mul_epu32(C1, D1); \ + ml = _mm256_add_epi64(ml, ml); \ + C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \ + \ + B1 = _mm256_xor_si256(B1, C1); \ + B1 = rotr24(B1); \ + } while((void)0, 0); + +#define G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + __m256i ml = _mm256_mul_epu32(A0, B0); \ + ml = _mm256_add_epi64(ml, ml); \ + A0 = _mm256_add_epi64(A0, _mm256_add_epi64(B0, ml)); \ + D0 = _mm256_xor_si256(D0, A0); \ + D0 = rotr16(D0); \ + \ + ml = _mm256_mul_epu32(C0, D0); \ + ml = _mm256_add_epi64(ml, ml); \ + C0 = _mm256_add_epi64(C0, _mm256_add_epi64(D0, ml)); \ + B0 = _mm256_xor_si256(B0, C0); \ + B0 = rotr63(B0); \ + \ + ml = _mm256_mul_epu32(A1, B1); \ + ml = _mm256_add_epi64(ml, ml); \ + A1 = _mm256_add_epi64(A1, _mm256_add_epi64(B1, ml)); \ + D1 = _mm256_xor_si256(D1, A1); \ + D1 = rotr16(D1); \ + \ + ml = _mm256_mul_epu32(C1, D1); \ + ml = _mm256_add_epi64(ml, ml); \ + C1 = _mm256_add_epi64(C1, _mm256_add_epi64(D1, ml)); \ + B1 = _mm256_xor_si256(B1, C1); \ + B1 = rotr63(B1); \ + } while((void)0, 0); + +#define DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \ + C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \ + D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \ + \ + B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \ + C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \ + D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \ + } while((void)0, 0); + +#define DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + __m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \ + __m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \ + B1 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \ + B0 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \ + \ + tmp1 = C0; \ + C0 = C1; \ + C1 = tmp1; \ + \ + tmp1 = _mm256_blend_epi32(D0, D1, 0xCC); \ + tmp2 = _mm256_blend_epi32(D0, D1, 0x33); \ + D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \ + D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \ + } while(0); + +#define UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + B0 = _mm256_permute4x64_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \ + C0 = _mm256_permute4x64_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \ + D0 = _mm256_permute4x64_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \ + \ + B1 = _mm256_permute4x64_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \ + C1 = _mm256_permute4x64_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \ + D1 = _mm256_permute4x64_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \ + } while((void)0, 0); + +#define UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + __m256i tmp1 = _mm256_blend_epi32(B0, B1, 0xCC); \ + __m256i tmp2 = _mm256_blend_epi32(B0, B1, 0x33); \ + B0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \ + B1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \ + \ + tmp1 = C0; \ + C0 = C1; \ + C1 = tmp1; \ + \ + tmp1 = _mm256_blend_epi32(D0, D1, 0x33); \ + tmp2 = _mm256_blend_epi32(D0, D1, 0xCC); \ + D0 = _mm256_permute4x64_epi64(tmp1, _MM_SHUFFLE(2,3,0,1)); \ + D1 = _mm256_permute4x64_epi64(tmp2, _MM_SHUFFLE(2,3,0,1)); \ + } while((void)0, 0); + +#define BLAKE2_ROUND_1(A0, A1, B0, B1, C0, C1, D0, D1) \ + do{ \ + G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + \ + DIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \ + \ + G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + \ + UNDIAGONALIZE_1(A0, B0, C0, D0, A1, B1, C1, D1) \ + } while((void)0, 0); + +#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \ + do{ \ + G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + \ + DIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \ + \ + G1_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + G2_AVX2(A0, A1, B0, B1, C0, C1, D0, D1) \ + \ + UNDIAGONALIZE_2(A0, A1, B0, B1, C0, C1, D0, D1) \ + } while((void)0, 0); + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx512f.h b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx512f.h new file mode 100644 index 0000000000..9a822402d8 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-avx512f.h @@ -0,0 +1,145 @@ +#ifndef blamka_round_avx512f_H +#define blamka_round_avx512f_H + +#include "private/common.h" +#include "private/sse2_64_32.h" + +#define ror64(x, n) _mm512_ror_epi64((x), (n)) + +static inline __m512i +muladd(__m512i x, __m512i y) +{ + __m512i z = _mm512_mul_epu32(x, y); + + return _mm512_add_epi64(_mm512_add_epi64(x, y), _mm512_add_epi64(z, z)); +} + +#define G1_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = muladd(A0, B0); \ + A1 = muladd(A1, B1); \ + \ + D0 = _mm512_xor_si512(D0, A0); \ + D1 = _mm512_xor_si512(D1, A1); \ + \ + D0 = ror64(D0, 32); \ + D1 = ror64(D1, 32); \ + \ + C0 = muladd(C0, D0); \ + C1 = muladd(C1, D1); \ + \ + B0 = _mm512_xor_si512(B0, C0); \ + B1 = _mm512_xor_si512(B1, C1); \ + \ + B0 = ror64(B0, 24); \ + B1 = ror64(B1, 24); \ + } while ((void)0, 0) + +#define G2_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = muladd(A0, B0); \ + A1 = muladd(A1, B1); \ + \ + D0 = _mm512_xor_si512(D0, A0); \ + D1 = _mm512_xor_si512(D1, A1); \ + \ + D0 = ror64(D0, 16); \ + D1 = ror64(D1, 16); \ + \ + C0 = muladd(C0, D0); \ + C1 = muladd(C1, D1); \ + \ + B0 = _mm512_xor_si512(B0, C0); \ + B1 = _mm512_xor_si512(B1, C1); \ + \ + B0 = ror64(B0, 63); \ + B1 = ror64(B1, 63); \ + } while ((void)0, 0) + +#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(0, 3, 2, 1)); \ + B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(0, 3, 2, 1)); \ + \ + C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \ + C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \ + \ + D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(2, 1, 0, 3)); \ + D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(2, 1, 0, 3)); \ + } while ((void)0, 0) + +#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + B0 = _mm512_permutex_epi64(B0, _MM_SHUFFLE(2, 1, 0, 3)); \ + B1 = _mm512_permutex_epi64(B1, _MM_SHUFFLE(2, 1, 0, 3)); \ + \ + C0 = _mm512_permutex_epi64(C0, _MM_SHUFFLE(1, 0, 3, 2)); \ + C1 = _mm512_permutex_epi64(C1, _MM_SHUFFLE(1, 0, 3, 2)); \ + \ + D0 = _mm512_permutex_epi64(D0, _MM_SHUFFLE(0, 3, 2, 1)); \ + D1 = _mm512_permutex_epi64(D1, _MM_SHUFFLE(0, 3, 2, 1)); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + G1_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + G1_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2_AVX512F(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void)0, 0) + +#define SWAP_HALVES(A0, A1) \ + do { \ + __m512i t0, t1; \ + t0 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(1, 0, 1, 0)); \ + t1 = _mm512_shuffle_i64x2(A0, A1, _MM_SHUFFLE(3, 2, 3, 2)); \ + A0 = t0; \ + A1 = t1; \ + } while((void)0, 0) + +#define SWAP_QUARTERS(A0, A1) \ + do { \ + SWAP_HALVES(A0, A1); \ + A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \ + A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \ + } while((void)0, 0) + +#define UNSWAP_QUARTERS(A0, A1) \ + do { \ + A0 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A0); \ + A1 = _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 1, 4, 5, 2, 3, 6, 7), A1); \ + SWAP_HALVES(A0, A1); \ + } while((void)0, 0) + +#define BLAKE2_ROUND_1(A0, C0, B0, D0, A1, C1, B1, D1) \ + do { \ + SWAP_HALVES(A0, B0); \ + SWAP_HALVES(C0, D0); \ + SWAP_HALVES(A1, B1); \ + SWAP_HALVES(C1, D1); \ + BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \ + SWAP_HALVES(A0, B0); \ + SWAP_HALVES(C0, D0); \ + SWAP_HALVES(A1, B1); \ + SWAP_HALVES(C1, D1); \ + } while ((void)0, 0) + +#define BLAKE2_ROUND_2(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + SWAP_QUARTERS(A0, A1); \ + SWAP_QUARTERS(B0, B1); \ + SWAP_QUARTERS(C0, C1); \ + SWAP_QUARTERS(D0, D1); \ + BLAKE2_ROUND(A0, B0, C0, D0, A1, B1, C1, D1); \ + UNSWAP_QUARTERS(A0, A1); \ + UNSWAP_QUARTERS(B0, B1); \ + UNSWAP_QUARTERS(C0, C1); \ + UNSWAP_QUARTERS(D0, D1); \ + } while ((void)0, 0) + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ref.h b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ref.h new file mode 100644 index 0000000000..7a2c6eb20e --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ref.h @@ -0,0 +1,40 @@ +#ifndef blamka_round_ref_H +#define blamka_round_ref_H + +#include "private/common.h" + +/*designed by the Lyra PHC team */ +static inline uint64_t +fBlaMka(uint64_t x, uint64_t y) +{ + const uint64_t m = UINT64_C(0xFFFFFFFF); + const uint64_t xy = (x & m) * (y & m); + return x + y + 2 * xy; +} + +#define G(a, b, c, d) \ + do { \ + a = fBlaMka(a, b); \ + d = ROTR64(d ^ a, 32); \ + c = fBlaMka(c, d); \ + b = ROTR64(b ^ c, 24); \ + a = fBlaMka(a, b); \ + d = ROTR64(d ^ a, 16); \ + c = fBlaMka(c, d); \ + b = ROTR64(b ^ c, 63); \ + } while ((void) 0, 0) + +#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, \ + v12, v13, v14, v15) \ + do { \ + G(v0, v4, v8, v12); \ + G(v1, v5, v9, v13); \ + G(v2, v6, v10, v14); \ + G(v3, v7, v11, v15); \ + G(v0, v5, v10, v15); \ + G(v1, v6, v11, v12); \ + G(v2, v7, v8, v13); \ + G(v3, v4, v9, v14); \ + } while ((void) 0, 0) + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ssse3.h b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ssse3.h new file mode 100644 index 0000000000..98a47b93f8 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/blamka-round-ssse3.h @@ -0,0 +1,120 @@ +#ifndef blamka_round_ssse3_H +#define blamka_round_ssse3_H + +#include "private/common.h" +#include "private/sse2_64_32.h" + +#define r16 \ + (_mm_setr_epi8(2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9)) +#define r24 \ + (_mm_setr_epi8(3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10)) +#define _mm_roti_epi64(x, c) \ + (-(c) == 32) \ + ? _mm_shuffle_epi32((x), _MM_SHUFFLE(2, 3, 0, 1)) \ + : (-(c) == 24) \ + ? _mm_shuffle_epi8((x), r24) \ + : (-(c) == 16) \ + ? _mm_shuffle_epi8((x), r16) \ + : (-(c) == 63) \ + ? _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ + _mm_add_epi64((x), (x))) \ + : _mm_xor_si128(_mm_srli_epi64((x), -(c)), \ + _mm_slli_epi64((x), 64 - (-(c)))) + +static inline __m128i +fBlaMka(__m128i x, __m128i y) +{ + const __m128i z = _mm_mul_epu32(x, y); + return _mm_add_epi64(_mm_add_epi64(x, y), _mm_add_epi64(z, z)); +} + +#define G1(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = fBlaMka(A0, B0); \ + A1 = fBlaMka(A1, B1); \ + \ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ + \ + D0 = _mm_roti_epi64(D0, -32); \ + D1 = _mm_roti_epi64(D1, -32); \ + \ + C0 = fBlaMka(C0, D0); \ + C1 = fBlaMka(C1, D1); \ + \ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ + \ + B0 = _mm_roti_epi64(B0, -24); \ + B1 = _mm_roti_epi64(B1, -24); \ + } while ((void) 0, 0) + +#define G2(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + A0 = fBlaMka(A0, B0); \ + A1 = fBlaMka(A1, B1); \ + \ + D0 = _mm_xor_si128(D0, A0); \ + D1 = _mm_xor_si128(D1, A1); \ + \ + D0 = _mm_roti_epi64(D0, -16); \ + D1 = _mm_roti_epi64(D1, -16); \ + \ + C0 = fBlaMka(C0, D0); \ + C1 = fBlaMka(C1, D1); \ + \ + B0 = _mm_xor_si128(B0, C0); \ + B1 = _mm_xor_si128(B1, C1); \ + \ + B0 = _mm_roti_epi64(B0, -63); \ + B1 = _mm_roti_epi64(B1, -63); \ + } while ((void) 0, 0) + +#define DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = _mm_alignr_epi8(B1, B0, 8); \ + __m128i t1 = _mm_alignr_epi8(B0, B1, 8); \ + B0 = t0; \ + B1 = t1; \ + \ + t0 = C0; \ + C0 = C1; \ + C1 = t0; \ + \ + t0 = _mm_alignr_epi8(D1, D0, 8); \ + t1 = _mm_alignr_epi8(D0, D1, 8); \ + D0 = t1; \ + D1 = t0; \ + } while ((void) 0, 0) + +#define UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1) \ + do { \ + __m128i t0 = _mm_alignr_epi8(B0, B1, 8); \ + __m128i t1 = _mm_alignr_epi8(B1, B0, 8); \ + B0 = t0; \ + B1 = t1; \ + \ + t0 = C0; \ + C0 = C1; \ + C1 = t0; \ + \ + t0 = _mm_alignr_epi8(D0, D1, 8); \ + t1 = _mm_alignr_epi8(D1, D0, 8); \ + D0 = t1; \ + D1 = t0; \ + } while ((void) 0, 0) + +#define BLAKE2_ROUND(A0, A1, B0, B1, C0, C1, D0, D1) \ + do { \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + DIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + G1(A0, B0, C0, D0, A1, B1, C1, D1); \ + G2(A0, B0, C0, D0, A1, B1, C1, D1); \ + \ + UNDIAGONALIZE(A0, B0, C0, D0, A1, B1, C1, D1); \ + } while ((void) 0, 0) + +#endif diff --git a/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2i.c b/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2i.c new file mode 100644 index 0000000000..0515bd6135 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2i.c @@ -0,0 +1,290 @@ + +#include +#include +#include +#include +#include +#include + +#include "argon2-core.h" +#include "argon2-encoding.h" +#include "argon2.h" +#include "crypto_pwhash.h" +#include "crypto_pwhash_argon2i.h" +#include "crypto_pwhash_argon2id.h" +#include "private/common.h" +#include "randombytes.h" +#include "utils.h" + +#define STR_HASHBYTES 32U + +int +crypto_pwhash_argon2i_alg_argon2i13(void) +{ + return crypto_pwhash_argon2i_ALG_ARGON2I13; +} + +size_t +crypto_pwhash_argon2i_bytes_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_BYTES_MIN >= ARGON2_MIN_OUTLEN); + return crypto_pwhash_argon2i_BYTES_MIN; +} + +size_t +crypto_pwhash_argon2i_bytes_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_BYTES_MAX <= ARGON2_MAX_OUTLEN); + return crypto_pwhash_argon2i_BYTES_MAX; +} + +size_t +crypto_pwhash_argon2i_passwd_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_PASSWD_MIN >= ARGON2_MIN_PWD_LENGTH); + return crypto_pwhash_argon2i_PASSWD_MIN; +} + +size_t +crypto_pwhash_argon2i_passwd_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_PASSWD_MAX <= ARGON2_MAX_PWD_LENGTH); + return crypto_pwhash_argon2i_PASSWD_MAX; +} + +size_t +crypto_pwhash_argon2i_saltbytes(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_SALTBYTES >= ARGON2_MIN_SALT_LENGTH); + COMPILER_ASSERT(crypto_pwhash_argon2i_SALTBYTES <= ARGON2_MAX_SALT_LENGTH); + return crypto_pwhash_argon2i_SALTBYTES; +} + +size_t +crypto_pwhash_argon2i_strbytes(void) +{ + return crypto_pwhash_argon2i_STRBYTES; +} + +const char* +crypto_pwhash_argon2i_strprefix(void) +{ + return crypto_pwhash_argon2i_STRPREFIX; +} + +size_t +crypto_pwhash_argon2i_opslimit_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_OPSLIMIT_MIN >= ARGON2_MIN_TIME); + return crypto_pwhash_argon2i_OPSLIMIT_MIN; +} + +size_t +crypto_pwhash_argon2i_opslimit_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2i_OPSLIMIT_MAX <= ARGON2_MAX_TIME); + return crypto_pwhash_argon2i_OPSLIMIT_MAX; +} + +size_t +crypto_pwhash_argon2i_memlimit_min(void) +{ + COMPILER_ASSERT((crypto_pwhash_argon2i_MEMLIMIT_MIN / 1024U) >= ARGON2_MIN_MEMORY); + return crypto_pwhash_argon2i_MEMLIMIT_MIN; +} + +size_t +crypto_pwhash_argon2i_memlimit_max(void) +{ + COMPILER_ASSERT((crypto_pwhash_argon2i_MEMLIMIT_MAX / 1024U) <= ARGON2_MAX_MEMORY); + return crypto_pwhash_argon2i_MEMLIMIT_MAX; +} + +size_t +crypto_pwhash_argon2i_opslimit_interactive(void) +{ + return crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_argon2i_memlimit_interactive(void) +{ + return crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_argon2i_opslimit_moderate(void) +{ + return crypto_pwhash_argon2i_OPSLIMIT_MODERATE; +} + +size_t +crypto_pwhash_argon2i_memlimit_moderate(void) +{ + return crypto_pwhash_argon2i_MEMLIMIT_MODERATE; +} + +size_t +crypto_pwhash_argon2i_opslimit_sensitive(void) +{ + return crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_argon2i_memlimit_sensitive(void) +{ + return crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash_argon2i(unsigned char *const out, unsigned long long outlen, + const char *const passwd, unsigned long long passwdlen, + const unsigned char *const salt, + unsigned long long opslimit, size_t memlimit, int alg) +{ + memset(out, 0, outlen); + if (outlen > crypto_pwhash_argon2i_BYTES_MAX) { + errno = EFBIG; + return -1; + } + if (outlen < crypto_pwhash_argon2i_BYTES_MIN) { + errno = EINVAL; + return -1; + } + if (passwdlen > crypto_pwhash_argon2i_PASSWD_MAX || + opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX || + memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX) { + errno = EFBIG; + return -1; + } + if (passwdlen < crypto_pwhash_argon2i_PASSWD_MIN || + opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN || + memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN) { + errno = EINVAL; + return -1; + } + switch (alg) { + case crypto_pwhash_argon2i_ALG_ARGON2I13: + if (argon2i_hash_raw((uint32_t) opslimit, (uint32_t) (memlimit / 1024U), + (uint32_t) 1U, passwd, (size_t) passwdlen, salt, + (size_t) crypto_pwhash_argon2i_SALTBYTES, out, + (size_t) outlen) != ARGON2_OK) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; + default: + errno = EINVAL; + return -1; + } +} + +int +crypto_pwhash_argon2i_str(char out[crypto_pwhash_argon2i_STRBYTES], + const char *const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) +{ + unsigned char salt[crypto_pwhash_argon2i_SALTBYTES]; + + memset(out, 0, crypto_pwhash_argon2i_STRBYTES); + if (passwdlen > crypto_pwhash_argon2i_PASSWD_MAX || + opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX || + memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX) { + errno = EFBIG; + return -1; + } + if (passwdlen < crypto_pwhash_argon2i_PASSWD_MIN || + opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN || + memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN) { + errno = EINVAL; + return -1; + } + randombytes_buf(salt, sizeof salt); + if (argon2i_hash_encoded((uint32_t) opslimit, (uint32_t) (memlimit / 1024U), + (uint32_t) 1U, passwd, (size_t) passwdlen, salt, + sizeof salt, STR_HASHBYTES, out, + crypto_pwhash_argon2i_STRBYTES) != ARGON2_OK) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; +} + +int +crypto_pwhash_argon2i_str_verify(const char str[crypto_pwhash_argon2i_STRBYTES], + const char *const passwd, + unsigned long long passwdlen) +{ + int verify_ret; + + if (passwdlen > crypto_pwhash_argon2i_PASSWD_MAX) { + errno = EFBIG; + return -1; + } + /* LCOV_EXCL_START */ + if (passwdlen < crypto_pwhash_argon2i_PASSWD_MIN) { + errno = EINVAL; + return -1; + } + /* LCOV_EXCL_STOP */ + + verify_ret = argon2i_verify(str, passwd, (size_t) passwdlen); + if (verify_ret == ARGON2_OK) { + return 0; + } + if (verify_ret == ARGON2_VERIFY_MISMATCH) { + errno = EINVAL; + } + return -1; +} + +static int +_needs_rehash(const char *str, unsigned long long opslimit, size_t memlimit, + argon2_type type) +{ + unsigned char *fodder; + argon2_context ctx; + size_t fodder_len; + int ret = -1; + + fodder_len = strlen(str); + memlimit /= 1024U; + if (opslimit > UINT32_MAX || memlimit > UINT32_MAX || + fodder_len >= crypto_pwhash_STRBYTES) { + errno = EINVAL; + return -1; + } + memset(&ctx, 0, sizeof ctx); + if ((fodder = (unsigned char *) calloc(fodder_len, 1U)) == NULL) { + return -1; /* LCOV_EXCL_LINE */ + } + ctx.out = ctx.pwd = ctx.salt = fodder; + ctx.outlen = ctx.pwdlen = ctx.saltlen = (uint32_t) fodder_len; + ctx.ad = ctx.secret = NULL; + ctx.adlen = ctx.secretlen = 0U; + if (decode_string(&ctx, str, type) != 0) { + errno = EINVAL; + ret = -1; + } else if (ctx.t_cost != (uint32_t) opslimit || + ctx.m_cost != (uint32_t) memlimit) { + ret = 1; + } else { + ret = 0; + } + free(fodder); + + return ret; +} + +int +crypto_pwhash_argon2i_str_needs_rehash(const char str[crypto_pwhash_argon2i_STRBYTES], + unsigned long long opslimit, size_t memlimit) +{ + return _needs_rehash(str, opslimit, memlimit, Argon2_i); +} + +int +crypto_pwhash_argon2id_str_needs_rehash(const char str[crypto_pwhash_argon2id_STRBYTES], + unsigned long long opslimit, size_t memlimit) +{ + return _needs_rehash(str, opslimit, memlimit, Argon2_id); +} diff --git a/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2id.c b/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2id.c new file mode 100644 index 0000000000..99d3e219bf --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/argon2/pwhash_argon2id.c @@ -0,0 +1,234 @@ + +#include +#include +#include +#include +#include + +#include "argon2-core.h" +#include "argon2.h" +#include "crypto_pwhash_argon2id.h" +#include "private/common.h" +#include "randombytes.h" +#include "utils.h" + +#define STR_HASHBYTES 32U + +int +crypto_pwhash_argon2id_alg_argon2id13(void) +{ + return crypto_pwhash_argon2id_ALG_ARGON2ID13; +} + +size_t +crypto_pwhash_argon2id_bytes_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_BYTES_MIN >= ARGON2_MIN_OUTLEN); + return crypto_pwhash_argon2id_BYTES_MIN; +} + +size_t +crypto_pwhash_argon2id_bytes_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_BYTES_MAX <= ARGON2_MAX_OUTLEN); + return crypto_pwhash_argon2id_BYTES_MAX; +} + +size_t +crypto_pwhash_argon2id_passwd_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_PASSWD_MIN >= ARGON2_MIN_PWD_LENGTH); + return crypto_pwhash_argon2id_PASSWD_MIN; +} + +size_t +crypto_pwhash_argon2id_passwd_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_PASSWD_MAX <= ARGON2_MAX_PWD_LENGTH); + return crypto_pwhash_argon2id_PASSWD_MAX; +} + +size_t +crypto_pwhash_argon2id_saltbytes(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_SALTBYTES >= ARGON2_MIN_SALT_LENGTH); + COMPILER_ASSERT(crypto_pwhash_argon2id_SALTBYTES <= ARGON2_MAX_SALT_LENGTH); + return crypto_pwhash_argon2id_SALTBYTES; +} + +size_t +crypto_pwhash_argon2id_strbytes(void) +{ + return crypto_pwhash_argon2id_STRBYTES; +} + +const char* +crypto_pwhash_argon2id_strprefix(void) +{ + return crypto_pwhash_argon2id_STRPREFIX; +} + +size_t +crypto_pwhash_argon2id_opslimit_min(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_OPSLIMIT_MIN >= ARGON2_MIN_TIME); + return crypto_pwhash_argon2id_OPSLIMIT_MIN; +} + +size_t +crypto_pwhash_argon2id_opslimit_max(void) +{ + COMPILER_ASSERT(crypto_pwhash_argon2id_OPSLIMIT_MAX <= ARGON2_MAX_TIME); + return crypto_pwhash_argon2id_OPSLIMIT_MAX; +} + +size_t +crypto_pwhash_argon2id_memlimit_min(void) +{ + COMPILER_ASSERT((crypto_pwhash_argon2id_MEMLIMIT_MIN / 1024U) >= ARGON2_MIN_MEMORY); + return crypto_pwhash_argon2id_MEMLIMIT_MIN; +} + +size_t +crypto_pwhash_argon2id_memlimit_max(void) +{ + COMPILER_ASSERT((crypto_pwhash_argon2id_MEMLIMIT_MAX / 1024U) <= ARGON2_MAX_MEMORY); + return crypto_pwhash_argon2id_MEMLIMIT_MAX; +} + +size_t +crypto_pwhash_argon2id_opslimit_interactive(void) +{ + return crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_argon2id_memlimit_interactive(void) +{ + return crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_argon2id_opslimit_moderate(void) +{ + return crypto_pwhash_argon2id_OPSLIMIT_MODERATE; +} + +size_t +crypto_pwhash_argon2id_memlimit_moderate(void) +{ + return crypto_pwhash_argon2id_MEMLIMIT_MODERATE; +} + +size_t +crypto_pwhash_argon2id_opslimit_sensitive(void) +{ + return crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_argon2id_memlimit_sensitive(void) +{ + return crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash_argon2id(unsigned char *const out, unsigned long long outlen, + const char *const passwd, unsigned long long passwdlen, + const unsigned char *const salt, + unsigned long long opslimit, size_t memlimit, int alg) +{ + memset(out, 0, outlen); + if (outlen > crypto_pwhash_argon2id_BYTES_MAX) { + errno = EFBIG; + return -1; + } + if (outlen < crypto_pwhash_argon2id_BYTES_MIN) { + errno = EINVAL; + return -1; + } + if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX || + opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX || + memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX) { + errno = EFBIG; + return -1; + } + if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN || + opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN || + memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN) { + errno = EINVAL; + return -1; + } + switch (alg) { + case crypto_pwhash_argon2id_ALG_ARGON2ID13: + if (argon2id_hash_raw((uint32_t) opslimit, (uint32_t) (memlimit / 1024U), + (uint32_t) 1U, passwd, (size_t) passwdlen, salt, + (size_t) crypto_pwhash_argon2id_SALTBYTES, out, + (size_t) outlen) != ARGON2_OK) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; + default: + errno = EINVAL; + return -1; + } +} + +int +crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES], + const char *const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) +{ + unsigned char salt[crypto_pwhash_argon2id_SALTBYTES]; + + memset(out, 0, crypto_pwhash_argon2id_STRBYTES); + if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX || + opslimit > crypto_pwhash_argon2id_OPSLIMIT_MAX || + memlimit > crypto_pwhash_argon2id_MEMLIMIT_MAX) { + errno = EFBIG; + return -1; + } + if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN || + opslimit < crypto_pwhash_argon2id_OPSLIMIT_MIN || + memlimit < crypto_pwhash_argon2id_MEMLIMIT_MIN) { + errno = EINVAL; + return -1; + } + randombytes_buf(salt, sizeof salt); + if (argon2id_hash_encoded((uint32_t) opslimit, (uint32_t) (memlimit / 1024U), + (uint32_t) 1U, passwd, (size_t) passwdlen, salt, + sizeof salt, STR_HASHBYTES, out, + crypto_pwhash_argon2id_STRBYTES) != ARGON2_OK) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; +} + +int +crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES], + const char *const passwd, + unsigned long long passwdlen) +{ + int verify_ret; + + if (passwdlen > crypto_pwhash_argon2id_PASSWD_MAX) { + errno = EFBIG; + return -1; + } + /* LCOV_EXCL_START */ + if (passwdlen < crypto_pwhash_argon2id_PASSWD_MIN) { + errno = EINVAL; + return -1; + } + /* LCOV_EXCL_STOP */ + + verify_ret = argon2id_verify(str, passwd, (size_t) passwdlen); + if (verify_ret == ARGON2_OK) { + return 0; + } + if (verify_ret == ARGON2_VERIFY_MISMATCH) { + errno = EINVAL; + } + return -1; +} diff --git a/libs/libsodium/src/crypto_pwhash/crypto_pwhash.c b/libs/libsodium/src/crypto_pwhash/crypto_pwhash.c new file mode 100644 index 0000000000..8168f96216 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/crypto_pwhash.c @@ -0,0 +1,211 @@ + +#include +#include + +#include "core.h" +#include "crypto_pwhash.h" + +int +crypto_pwhash_alg_argon2i13(void) +{ + return crypto_pwhash_ALG_ARGON2I13; +} + +int +crypto_pwhash_alg_argon2id13(void) +{ + return crypto_pwhash_ALG_ARGON2ID13; +} + +int +crypto_pwhash_alg_default(void) +{ + return crypto_pwhash_ALG_DEFAULT; +} + +size_t +crypto_pwhash_bytes_min(void) +{ + return crypto_pwhash_BYTES_MIN; +} + +size_t +crypto_pwhash_bytes_max(void) +{ + return crypto_pwhash_BYTES_MAX; +} + +size_t +crypto_pwhash_passwd_min(void) +{ + return crypto_pwhash_PASSWD_MIN; +} + +size_t +crypto_pwhash_passwd_max(void) +{ + return crypto_pwhash_PASSWD_MAX; +} + +size_t +crypto_pwhash_saltbytes(void) +{ + return crypto_pwhash_SALTBYTES; +} + +size_t +crypto_pwhash_strbytes(void) +{ + return crypto_pwhash_STRBYTES; +} + +const char * +crypto_pwhash_strprefix(void) +{ + return crypto_pwhash_STRPREFIX; +} + +size_t +crypto_pwhash_opslimit_min(void) +{ + return crypto_pwhash_OPSLIMIT_MIN; +} + +size_t +crypto_pwhash_opslimit_max(void) +{ + return crypto_pwhash_OPSLIMIT_MAX; +} + +size_t +crypto_pwhash_memlimit_min(void) +{ + return crypto_pwhash_MEMLIMIT_MIN; +} + +size_t +crypto_pwhash_memlimit_max(void) +{ + return crypto_pwhash_MEMLIMIT_MAX; +} + +size_t +crypto_pwhash_opslimit_interactive(void) +{ + return crypto_pwhash_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_memlimit_interactive(void) +{ + return crypto_pwhash_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_opslimit_moderate(void) +{ + return crypto_pwhash_OPSLIMIT_MODERATE; +} + +size_t +crypto_pwhash_memlimit_moderate(void) +{ + return crypto_pwhash_MEMLIMIT_MODERATE; +} + +size_t +crypto_pwhash_opslimit_sensitive(void) +{ + return crypto_pwhash_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_memlimit_sensitive(void) +{ + return crypto_pwhash_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash(unsigned char * const out, unsigned long long outlen, + const char * const passwd, unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, size_t memlimit, int alg) +{ + switch (alg) { + case crypto_pwhash_ALG_ARGON2I13: + return crypto_pwhash_argon2i(out, outlen, passwd, passwdlen, salt, + opslimit, memlimit, alg); + case crypto_pwhash_ALG_ARGON2ID13: + return crypto_pwhash_argon2id(out, outlen, passwd, passwdlen, salt, + opslimit, memlimit, alg); + default: + errno = EINVAL; + return -1; + } +} + +int +crypto_pwhash_str(char out[crypto_pwhash_STRBYTES], + const char * const passwd, unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) +{ + return crypto_pwhash_argon2id_str(out, passwd, passwdlen, + opslimit, memlimit); +} + +int +crypto_pwhash_str_alg(char out[crypto_pwhash_STRBYTES], + const char * const passwd, unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit, int alg) +{ + switch (alg) { + case crypto_pwhash_ALG_ARGON2I13: + return crypto_pwhash_argon2i_str(out, passwd, passwdlen, + opslimit, memlimit); + case crypto_pwhash_ALG_ARGON2ID13: + return crypto_pwhash_argon2id_str(out, passwd, passwdlen, + opslimit, memlimit); + } + sodium_misuse(); + /* NOTREACHED */ +} + +int +crypto_pwhash_str_verify(const char str[crypto_pwhash_STRBYTES], + const char * const passwd, + unsigned long long passwdlen) +{ + if (strncmp(str, crypto_pwhash_argon2id_STRPREFIX, + sizeof crypto_pwhash_argon2id_STRPREFIX - 1) == 0) { + return crypto_pwhash_argon2id_str_verify(str, passwd, passwdlen); + } + if (strncmp(str, crypto_pwhash_argon2i_STRPREFIX, + sizeof crypto_pwhash_argon2i_STRPREFIX - 1) == 0) { + return crypto_pwhash_argon2i_str_verify(str, passwd, passwdlen); + } + errno = EINVAL; + + return -1; +} + +int +crypto_pwhash_str_needs_rehash(const char str[crypto_pwhash_STRBYTES], + unsigned long long opslimit, size_t memlimit) +{ + if (strncmp(str, crypto_pwhash_argon2id_STRPREFIX, + sizeof crypto_pwhash_argon2id_STRPREFIX - 1) == 0) { + return crypto_pwhash_argon2id_str_needs_rehash(str, opslimit, memlimit); + } + if (strncmp(str, crypto_pwhash_argon2i_STRPREFIX, + sizeof crypto_pwhash_argon2i_STRPREFIX - 1) == 0) { + return crypto_pwhash_argon2i_str_needs_rehash(str, opslimit, memlimit); + } + errno = EINVAL; + + return -1; +} + +const char * +crypto_pwhash_primitive(void) { + return crypto_pwhash_PRIMITIVE; +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c new file mode 100644 index 0000000000..e15e12b294 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt-common.c @@ -0,0 +1,263 @@ +/*- + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "crypto_scrypt.h" +#include "private/common.h" +#include "runtime.h" +#include "utils.h" + +static const char *const itoa64 = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static uint8_t * +encode64_uint32(uint8_t *dst, size_t dstlen, uint32_t src, uint32_t srcbits) +{ + uint32_t bit; + + for (bit = 0; bit < srcbits; bit += 6) { + if (dstlen < 1) { + return NULL; /* LCOV_EXCL_LINE */ + } + *dst++ = itoa64[src & 0x3f]; + dstlen--; + src >>= 6; + } + return dst; +} + +static uint8_t * +encode64(uint8_t *dst, size_t dstlen, const uint8_t *src, size_t srclen) +{ + size_t i; + + for (i = 0; i < srclen;) { + uint8_t *dnext; + uint32_t value = 0, bits = 0; + + do { + value |= (uint32_t) src[i++] << bits; + bits += 8; + } while (bits < 24 && i < srclen); + + dnext = encode64_uint32(dst, dstlen, value, bits); + if (!dnext) { + return NULL; /* LCOV_EXCL_LINE */ + } + dstlen -= dnext - dst; + dst = dnext; + } + return dst; +} + +static int +decode64_one(uint32_t *dst, uint8_t src) +{ + const char *ptr = strchr(itoa64, src); + + if (ptr) { + *dst = (uint32_t)(ptr - itoa64); + return 0; + } + *dst = 0; + + return -1; +} + +static const uint8_t * +decode64_uint32(uint32_t *dst, uint32_t dstbits, const uint8_t *src) +{ + uint32_t bit; + uint32_t value; + + value = 0; + for (bit = 0; bit < dstbits; bit += 6) { + uint32_t one; + if (decode64_one(&one, *src)) { + *dst = 0; + return NULL; + } + src++; + value |= one << bit; + } + *dst = value; + + return src; +} + +const uint8_t * +escrypt_parse_setting(const uint8_t *setting, + uint32_t *N_log2_p, uint32_t *r_p, uint32_t *p_p) +{ + const uint8_t *src; + + if (setting[0] != '$' || setting[1] != '7' || setting[2] != '$') { + return NULL; + } + src = setting + 3; + + if (decode64_one(N_log2_p, *src)) { + return NULL; + } + src++; + + src = decode64_uint32(r_p, 30, src); + if (!src) { + return NULL; + } + + src = decode64_uint32(p_p, 30, src); + if (!src) { + return NULL; + } + return src; +} + +uint8_t * +escrypt_r(escrypt_local_t *local, const uint8_t *passwd, size_t passwdlen, + const uint8_t *setting, uint8_t *buf, size_t buflen) +{ + uint8_t hash[crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES]; + escrypt_kdf_t escrypt_kdf; + const uint8_t *src; + const uint8_t *salt; + uint8_t *dst; + size_t prefixlen; + size_t saltlen; + size_t need; + uint64_t N; + uint32_t N_log2; + uint32_t r; + uint32_t p; + + src = escrypt_parse_setting(setting, &N_log2, &r, &p); + if (!src) { + return NULL; + } + N = (uint64_t) 1 << N_log2; + prefixlen = src - setting; + + salt = src; + src = (uint8_t *) strrchr((char *) salt, '$'); + if (src) { + saltlen = src - salt; + } else { + saltlen = strlen((char *) salt); + } + need = prefixlen + saltlen + 1 + + crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1; + if (need > buflen || need < saltlen) { + return NULL; + } +#ifdef HAVE_EMMINTRIN_H + escrypt_kdf = + sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; +#else + escrypt_kdf = escrypt_kdf_nosse; +#endif + if (escrypt_kdf(local, passwd, passwdlen, salt, saltlen, N, r, p, hash, + sizeof(hash))) { + return NULL; + } + dst = buf; + memcpy(dst, setting, prefixlen + saltlen); + dst += prefixlen + saltlen; + *dst++ = '$'; + + dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash)); + sodium_memzero(hash, sizeof hash); + if (!dst || dst >= buf + buflen) { + return NULL; /* Can't happen LCOV_EXCL_LINE */ + } + *dst = 0; /* NUL termination */ + + return buf; +} + +uint8_t * +escrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, const uint8_t *src, + size_t srclen, uint8_t *buf, size_t buflen) +{ + uint8_t *dst; + size_t prefixlen = + (sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */); + size_t saltlen = BYTES2CHARS(srclen); + size_t need; + + need = prefixlen + saltlen + 1; + if (need > buflen || need < saltlen || saltlen < srclen) { + return NULL; /* LCOV_EXCL_LINE */ + } + if (N_log2 > 63 || ((uint64_t) r * (uint64_t) p >= (1U << 30))) { + return NULL; /* LCOV_EXCL_LINE */ + } + dst = buf; + *dst++ = '$'; + *dst++ = '7'; + *dst++ = '$'; + + *dst++ = itoa64[N_log2]; + + dst = encode64_uint32(dst, buflen - (dst - buf), r, 30); + if (!dst) { + return NULL; /* Can't happen LCOV_EXCL_LINE */ + } + dst = encode64_uint32(dst, buflen - (dst - buf), p, 30); + if (!dst) { + return NULL; /* Can't happen LCOV_EXCL_LINE */ + } + dst = encode64(dst, buflen - (dst - buf), src, srclen); + if (!dst || dst >= buf + buflen) { + return NULL; /* Can't happen LCOV_EXCL_LINE */ + } + *dst = 0; /* NUL termination */ + + return buf; +} + +int +crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t *passwd, size_t passwdlen, + const uint8_t *salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, + uint8_t *buf, size_t buflen) +{ + escrypt_kdf_t escrypt_kdf; + escrypt_local_t local; + int retval; + + if (escrypt_init_local(&local)) { + return -1; /* LCOV_EXCL_LINE */ + } +#if defined(HAVE_EMMINTRIN_H) + escrypt_kdf = + sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; +#else + escrypt_kdf = escrypt_kdf_nosse; +#endif + retval = escrypt_kdf(&local, passwd, passwdlen, salt, saltlen, N, r, p, buf, + buflen); + if (escrypt_free_local(&local)) { + return -1; /* LCOV_EXCL_LINE */ + } + return retval; +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt.h b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt.h new file mode 100644 index 0000000000..83101967c3 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/crypto_scrypt.h @@ -0,0 +1,98 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef crypto_scrypt_H +#define crypto_scrypt_H + +#include +#include +#include + +#if SIZE_MAX > 0xffffffffULL +#define ARCH_BITS 64 +#else +#define ARCH_BITS 32 +#endif + +#define crypto_pwhash_scryptsalsa208sha256_STRPREFIXBYTES 14 +#define crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES 57 +#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES 32 +#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES_ENCODED 43 +#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES 32 +#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED 43 + +#define BYTES2CHARS(bytes) ((((bytes) *8) + 5) / 6) + +typedef struct { + void * base, *aligned; + size_t size; +} escrypt_region_t; + +typedef union { + uint64_t d[8]; + uint32_t w[16]; +} escrypt_block_t; + +typedef escrypt_region_t escrypt_local_t; + +extern int escrypt_init_local(escrypt_local_t *__local); + +extern int escrypt_free_local(escrypt_local_t *__local); + +extern void *alloc_region(escrypt_region_t *region, size_t size); +extern int free_region(escrypt_region_t *region); + +typedef int (*escrypt_kdf_t)(escrypt_local_t *__local, const uint8_t *__passwd, + size_t __passwdlen, const uint8_t *__salt, + size_t __saltlen, uint64_t __N, uint32_t __r, + uint32_t __p, uint8_t *__buf, size_t __buflen); + +extern int escrypt_kdf_nosse(escrypt_local_t *__local, const uint8_t *__passwd, + size_t __passwdlen, const uint8_t *__salt, + size_t __saltlen, uint64_t __N, uint32_t __r, + uint32_t __p, uint8_t *__buf, size_t __buflen); + +extern int escrypt_kdf_sse(escrypt_local_t *__local, const uint8_t *__passwd, + size_t __passwdlen, const uint8_t *__salt, + size_t __saltlen, uint64_t __N, uint32_t __r, + uint32_t __p, uint8_t *__buf, size_t __buflen); + +extern uint8_t *escrypt_r(escrypt_local_t *__local, const uint8_t *__passwd, + size_t __passwdlen, const uint8_t *__setting, + uint8_t *__buf, size_t __buflen); + +extern uint8_t *escrypt_gensalt_r(uint32_t __N_log2, uint32_t __r, uint32_t __p, + const uint8_t *__src, size_t __srclen, + uint8_t *__buf, size_t __buflen); + +extern const uint8_t *escrypt_parse_setting(const uint8_t *setting, + uint32_t *N_log2_p, uint32_t *r_p, + uint32_t *p_p); + +#endif /* !_CRYPTO_SCRYPT_H_ */ diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c new file mode 100644 index 0000000000..9e31352dc2 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c @@ -0,0 +1,375 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include +#include +#include +#include + +#include "../crypto_scrypt.h" +#include "../pbkdf2-sha256.h" +#include "private/common.h" + +static inline void +blkcpy_64(escrypt_block_t *dest, const escrypt_block_t *src) +{ + int i; + +#if (ARCH_BITS == 32) + for (i = 0; i < 16; ++i) { + dest->w[i] = src->w[i]; + } +#else + for (i = 0; i < 8; ++i) { + dest->d[i] = src->d[i]; + } +#endif +} + +static inline void +blkxor_64(escrypt_block_t *dest, const escrypt_block_t *src) +{ + int i; + +#if (ARCH_BITS == 32) + for (i = 0; i < 16; ++i) { + dest->w[i] ^= src->w[i]; + } +#else + for (i = 0; i < 8; ++i) { + dest->d[i] ^= src->d[i]; + } +#endif +} + +static inline void +blkcpy(escrypt_block_t *dest, const escrypt_block_t *src, size_t len) +{ + size_t i, L; + +#if (ARCH_BITS == 32) + L = (len >> 2); + for (i = 0; i < L; ++i) { + dest->w[i] = src->w[i]; + } +#else + L = (len >> 3); + for (i = 0; i < L; ++i) { + dest->d[i] = src->d[i]; + } +#endif +} + +static inline void +blkxor(escrypt_block_t *dest, const escrypt_block_t *src, size_t len) +{ + size_t i, L; + +#if (ARCH_BITS == 32) + L = (len >> 2); + for (i = 0; i < L; ++i) { + dest->w[i] ^= src->w[i]; + } +#else + L = (len >> 3); + for (i = 0; i < L; ++i) { + dest->d[i] ^= src->d[i]; + } +#endif +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + escrypt_block_t X; + uint32_t *x = X.w; + size_t i; + + blkcpy_64(&X, (escrypt_block_t *) B); + for (i = 0; i < 8; i += 2) { +#define R(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[4] ^= R(x[0] + x[12], 7); + x[8] ^= R(x[4] + x[0], 9); + x[12] ^= R(x[8] + x[4], 13); + x[0] ^= R(x[12] + x[8], 18); + + x[9] ^= R(x[5] + x[1], 7); + x[13] ^= R(x[9] + x[5], 9); + x[1] ^= R(x[13] + x[9], 13); + x[5] ^= R(x[1] + x[13], 18); + + x[14] ^= R(x[10] + x[6], 7); + x[2] ^= R(x[14] + x[10], 9); + x[6] ^= R(x[2] + x[14], 13); + x[10] ^= R(x[6] + x[2], 18); + + x[3] ^= R(x[15] + x[11], 7); + x[7] ^= R(x[3] + x[15], 9); + x[11] ^= R(x[7] + x[3], 13); + x[15] ^= R(x[11] + x[7], 18); + + /* Operate on rows. */ + x[1] ^= R(x[0] + x[3], 7); + x[2] ^= R(x[1] + x[0], 9); + x[3] ^= R(x[2] + x[1], 13); + x[0] ^= R(x[3] + x[2], 18); + + x[6] ^= R(x[5] + x[4], 7); + x[7] ^= R(x[6] + x[5], 9); + x[4] ^= R(x[7] + x[6], 13); + x[5] ^= R(x[4] + x[7], 18); + + x[11] ^= R(x[10] + x[9], 7); + x[8] ^= R(x[11] + x[10], 9); + x[9] ^= R(x[8] + x[11], 13); + x[10] ^= R(x[9] + x[8], 18); + + x[12] ^= R(x[15] + x[14], 7); + x[13] ^= R(x[12] + x[15], 9); + x[14] ^= R(x[13] + x[12], 13); + x[15] ^= R(x[14] + x[13], 18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(const uint32_t *Bin, uint32_t *Bout, uint32_t *X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy_64((escrypt_block_t *) X, + (escrypt_block_t *) &Bin[(2 * r - 1) * 16]); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor_64((escrypt_block_t *) X, (escrypt_block_t *) &Bin[i * 16]); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy_64((escrypt_block_t *) &Bout[i * 8], (escrypt_block_t *) X); + + /* 3: X <-- H(X \xor B_i) */ + blkxor_64((escrypt_block_t *) X, (escrypt_block_t *) &Bin[i * 16 + 16]); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy_64((escrypt_block_t *) &Bout[i * 8 + r * 16], + (escrypt_block_t *) X); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint64_t +integerify(const void *B, size_t r) +{ + const uint32_t *X = (const uint32_t *) ((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t *B, size_t r, uint64_t N, uint32_t *V, uint32_t *XY) +{ + uint32_t *X = XY; + uint32_t *Y = &XY[32 * r]; + uint32_t *Z = &XY[64 * r]; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) { + X[k] = LOAD32_LE(&B[4 * k]); + } + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy((escrypt_block_t *) &V[i * (32 * r)], (escrypt_block_t *) X, + 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy((escrypt_block_t *) &V[(i + 1) * (32 * r)], + (escrypt_block_t *) Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor((escrypt_block_t *) X, (escrypt_block_t *) &V[j * (32 * r)], + 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor((escrypt_block_t *) Y, (escrypt_block_t *) &V[j * (32 * r)], + 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) { + STORE32_LE(&B[4 * k], X[k]); + } +} + +/** + * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + * N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +escrypt_kdf_nosse(escrypt_local_t *local, const uint8_t *passwd, + size_t passwdlen, const uint8_t *salt, size_t saltlen, + uint64_t N, uint32_t _r, uint32_t _p, uint8_t *buf, + size_t buflen) +{ + size_t B_size, V_size, XY_size, need; + uint8_t * B; + uint32_t *V, *XY; + size_t r = _r, p = _p; + uint32_t i; + +/* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= ((uint64_t) 1 << 30)) { + errno = EFBIG; + return -1; + } + if (N > UINT32_MAX) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + return -1; + } + if (r == 0 || p == 0) { + errno = EINVAL; + return -1; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } + + /* Allocate memory. */ + B_size = (size_t) 128 * r * p; + V_size = (size_t) 128 * r * (size_t) N; + need = B_size + V_size; + if (need < V_size) { + errno = ENOMEM; + return -1; + } + XY_size = (size_t) 256 * r + 64; + need += XY_size; + if (need < XY_size) { + errno = ENOMEM; + return -1; + } + if (local->size < need) { + if (free_region(local)) { + return -1; + } + if (!alloc_region(local, need)) { + return -1; + } + } + B = (uint8_t *) local->aligned; + V = (uint32_t *) ((uint8_t *) B + B_size); + XY = (uint32_t *) ((uint8_t *) V + V_size); + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[(size_t) 128 * i * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); + + /* Success! */ + return 0; +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c new file mode 100644 index 0000000000..42cab61fe2 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.c @@ -0,0 +1,95 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +#include "core.h" +#include "crypto_auth_hmacsha256.h" +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "pbkdf2-sha256.h" +#include "private/common.h" +#include "utils.h" + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen, const uint8_t *salt, + size_t saltlen, uint64_t c, uint8_t *buf, size_t dkLen) +{ + crypto_auth_hmacsha256_state PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + +#if SIZE_MAX > 0x1fffffffe0ULL + COMPILER_ASSERT(crypto_pwhash_scryptsalsa208sha256_BYTES_MAX + <= 0x1fffffffe0ULL); + if (dkLen > 0x1fffffffe0ULL) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#endif + crypto_auth_hmacsha256_init(&PShctx, passwd, passwdlen); + crypto_auth_hmacsha256_update(&PShctx, salt, saltlen); + + for (i = 0; i * 32 < dkLen; i++) { + STORE32_BE(ivec, (uint32_t)(i + 1)); + memcpy(&hctx, &PShctx, sizeof(crypto_auth_hmacsha256_state)); + crypto_auth_hmacsha256_update(&hctx, ivec, 4); + crypto_auth_hmacsha256_final(&hctx, U); + + memcpy(T, U, 32); + /* LCOV_EXCL_START */ + for (j = 2; j <= c; j++) { + crypto_auth_hmacsha256_init(&hctx, passwd, passwdlen); + crypto_auth_hmacsha256_update(&hctx, U, 32); + crypto_auth_hmacsha256_final(&hctx, U); + + for (k = 0; k < 32; k++) { + T[k] ^= U[k]; + } + } + /* LCOV_EXCL_STOP */ + + clen = dkLen - i * 32; + if (clen > 32) { + clen = 32; + } + memcpy(&buf[i * 32], T, clen); + } + sodium_memzero((void *) &PShctx, sizeof PShctx); +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.h b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.h new file mode 100644 index 0000000000..f9598c87aa --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pbkdf2-sha256.h @@ -0,0 +1,45 @@ +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef pbkdf2_sha256_H +#define pbkdf2_sha256_H + +#include + +#include + +#include "crypto_auth_hmacsha256.h" + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, + uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c new file mode 100644 index 0000000000..d1afd91afe --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c @@ -0,0 +1,285 @@ + +#include +#include +#include +#include +#include + +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "crypto_scrypt.h" +#include "private/common.h" +#include "randombytes.h" +#include "utils.h" + +#define SETTING_SIZE(saltbytes) \ + ((sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */) + \ + BYTES2CHARS(saltbytes)) + +static int +pickparams(unsigned long long opslimit, const size_t memlimit, + uint32_t *const N_log2, uint32_t *const p, uint32_t *const r) +{ + unsigned long long maxN; + unsigned long long maxrp; + + if (opslimit < 32768) { + opslimit = 32768; + } + *r = 8; + if (opslimit < memlimit / 32) { + *p = 1; + maxN = opslimit / (*r * 4); + for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { + if ((uint64_t)(1) << *N_log2 > maxN / 2) { + break; + } + } + } else { + maxN = memlimit / ((size_t) *r * 128); + for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { + if ((uint64_t)(1) << *N_log2 > maxN / 2) { + break; + } + } + maxrp = (opslimit / 4) / ((uint64_t)(1) << *N_log2); + /* LCOV_EXCL_START */ + if (maxrp > 0x3fffffff) { + maxrp = 0x3fffffff; + } + /* LCOV_EXCL_STOP */ + *p = (uint32_t)(maxrp) / *r; + } + return 0; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_bytes_min(void) +{ + return crypto_pwhash_scryptsalsa208sha256_BYTES_MIN; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_bytes_max(void) +{ + return crypto_pwhash_scryptsalsa208sha256_BYTES_MAX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_passwd_min(void) +{ + return crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_passwd_max(void) +{ + return crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_saltbytes(void) +{ + return crypto_pwhash_scryptsalsa208sha256_SALTBYTES; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_strbytes(void) +{ + return crypto_pwhash_scryptsalsa208sha256_STRBYTES; +} + +const char * +crypto_pwhash_scryptsalsa208sha256_strprefix(void) +{ + return crypto_pwhash_scryptsalsa208sha256_STRPREFIX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_min(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_max(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_min(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_max(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash_scryptsalsa208sha256(unsigned char *const out, + unsigned long long outlen, + const char *const passwd, + unsigned long long passwdlen, + const unsigned char *const salt, + unsigned long long opslimit, size_t memlimit) +{ + uint32_t N_log2; + uint32_t p; + uint32_t r; + + memset(out, 0, outlen); + if (passwdlen > crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX || + outlen > crypto_pwhash_scryptsalsa208sha256_BYTES_MAX) { + errno = EFBIG; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + if (outlen < crypto_pwhash_scryptsalsa208sha256_BYTES_MIN || + pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + return crypto_pwhash_scryptsalsa208sha256_ll( + (const uint8_t *) passwd, (size_t) passwdlen, (const uint8_t *) salt, + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, (uint64_t)(1) << N_log2, + r, p, out, (size_t) outlen); +} + +int +crypto_pwhash_scryptsalsa208sha256_str( + char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char *const passwd, unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) +{ + uint8_t salt[crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES]; + char setting[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U]; + escrypt_local_t escrypt_local; + uint32_t N_log2; + uint32_t p; + uint32_t r; + + memset(out, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES); + if (passwdlen > crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX) { + errno = EFBIG; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + if (passwdlen < crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN || + pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + randombytes_buf(salt, sizeof salt); + if (escrypt_gensalt_r(N_log2, r, p, salt, sizeof salt, (uint8_t *) setting, + sizeof setting) == NULL) { + errno = EINVAL; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ + } + if (escrypt_init_local(&escrypt_local) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, + (const uint8_t *) setting, (uint8_t *) out, + crypto_pwhash_scryptsalsa208sha256_STRBYTES) == NULL) { + /* LCOV_EXCL_START */ + escrypt_free_local(&escrypt_local); + errno = EINVAL; + return -1; + /* LCOV_EXCL_STOP */ + } + escrypt_free_local(&escrypt_local); + + COMPILER_ASSERT( + SETTING_SIZE(crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES) == + crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES); + COMPILER_ASSERT( + crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U + + crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1U == + crypto_pwhash_scryptsalsa208sha256_STRBYTES); + + return 0; +} + +int +crypto_pwhash_scryptsalsa208sha256_str_verify( + const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char *const passwd, unsigned long long passwdlen) +{ + char wanted[crypto_pwhash_scryptsalsa208sha256_STRBYTES]; + escrypt_local_t escrypt_local; + int ret = -1; + + if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) != + &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) { + return -1; + } + if (escrypt_init_local(&escrypt_local) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + memset(wanted, 0, sizeof wanted); + if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, + (const uint8_t *) str, (uint8_t *) wanted, + sizeof wanted) == NULL) { + escrypt_free_local(&escrypt_local); + return -1; + } + escrypt_free_local(&escrypt_local); + ret = sodium_memcmp(wanted, str, sizeof wanted); + sodium_memzero(wanted, sizeof wanted); + + return ret; +} + +int +crypto_pwhash_scryptsalsa208sha256_str_needs_rehash( + const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + unsigned long long opslimit, size_t memlimit) +{ + uint32_t N_log2, N_log2_; + uint32_t p, p_; + uint32_t r, r_; + + if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; + return -1; + } + if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) != + &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) { + errno = EINVAL; + return -1; + } + if (escrypt_parse_setting((const uint8_t *) str, + &N_log2_, &r_, &p_) == NULL) { + errno = EINVAL; + return -1; + } + if (N_log2 != N_log2_ || r != r_ || p != p_) { + return 1; + } + return 0; +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c new file mode 100644 index 0000000000..139a7df286 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/scrypt_platform.c @@ -0,0 +1,108 @@ +/*- + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#include +#include + +#include "crypto_scrypt.h" +#include "runtime.h" + +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +# define MAP_ANON MAP_ANONYMOUS +#endif +#ifndef MAP_NOCORE +# define MAP_NOCORE 0 +#endif +#ifndef MAP_POPULATE +# define MAP_POPULATE 0 +#endif + +void * +alloc_region(escrypt_region_t *region, size_t size) +{ + uint8_t *base, *aligned; +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if ((base = (uint8_t *) mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_NOCORE | MAP_POPULATE, + -1, 0)) == MAP_FAILED) { + base = NULL; /* LCOV_EXCL_LINE */ + } /* LCOV_EXCL_LINE */ + aligned = base; +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **) &base, 64, size)) != 0) { + base = NULL; + } + aligned = base; +#else + base = aligned = NULL; + if (size + 63 < size) + errno = ENOMEM; + else if ((base = (uint8_t *) malloc(size + 63)) != NULL) { + aligned = base + 63; + aligned -= (uintptr_t) aligned & 63; + } +#endif + region->base = base; + region->aligned = aligned; + region->size = base ? size : 0; + + return aligned; +} + +static inline void +init_region(escrypt_region_t *region) +{ + region->base = region->aligned = NULL; + region->size = 0; +} + +int +free_region(escrypt_region_t *region) +{ + if (region->base) { +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if (munmap(region->base, region->size)) { + return -1; /* LCOV_EXCL_LINE */ + } +#else + free(region->base); +#endif + } + init_region(region); + + return 0; +} + +int +escrypt_init_local(escrypt_local_t *local) +{ + init_region(local); + + return 0; +} + +int +escrypt_free_local(escrypt_local_t *local) +{ + return free_region(local); +} diff --git a/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c new file mode 100644 index 0000000000..754a19fdb8 --- /dev/null +++ b/libs/libsodium/src/crypto_pwhash/scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c @@ -0,0 +1,400 @@ +/*- + * Copyright 2009 Colin Percival + * Copyright 2012,2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include +#include +#include +#include + +#include "private/common.h" +#include "private/sse2_64_32.h" + +#ifdef HAVE_EMMINTRIN_H + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# endif +# include +# if defined(__XOP__) && defined(DISABLED) +# include +# endif + +# include "../crypto_scrypt.h" +# include "../pbkdf2-sha256.h" + +# if defined(__XOP__) && defined(DISABLED) +# define ARX(out, in1, in2, s) \ + out = _mm_xor_si128(out, _mm_roti_epi32(_mm_add_epi32(in1, in2), s)); +# else +# define ARX(out, in1, in2, s) \ + { \ + __m128i T = _mm_add_epi32(in1, in2); \ + out = _mm_xor_si128(out, _mm_slli_epi32(T, s)); \ + out = _mm_xor_si128(out, _mm_srli_epi32(T, 32 - s)); \ + } +# endif + +# define SALSA20_2ROUNDS \ + /* Operate on "columns". */ \ + ARX(X1, X0, X3, 7) \ + ARX(X2, X1, X0, 9) \ + ARX(X3, X2, X1, 13) \ + ARX(X0, X3, X2, 18) \ + \ + /* Rearrange data. */ \ + X1 = _mm_shuffle_epi32(X1, 0x93); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x39); \ + \ + /* Operate on "rows". */ \ + ARX(X3, X0, X1, 7) \ + ARX(X2, X3, X0, 9) \ + ARX(X1, X2, X3, 13) \ + ARX(X0, X1, X2, 18) \ + \ + /* Rearrange data. */ \ + X1 = _mm_shuffle_epi32(X1, 0x39); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x93); + +/** + * Apply the salsa20/8 core to the block provided in (X0 ... X3) ^ (Z0 ... Z3). + */ +# define SALSA20_8_XOR(in, out) \ + { \ + __m128i Y0 = X0 = _mm_xor_si128(X0, (in)[0]); \ + __m128i Y1 = X1 = _mm_xor_si128(X1, (in)[1]); \ + __m128i Y2 = X2 = _mm_xor_si128(X2, (in)[2]); \ + __m128i Y3 = X3 = _mm_xor_si128(X3, (in)[3]); \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS(out)[0] = X0 = _mm_add_epi32(X0, Y0); \ + (out)[1] = X1 = _mm_add_epi32(X1, Y1); \ + (out)[2] = X2 = _mm_add_epi32(X2, Y2); \ + (out)[3] = X3 = _mm_add_epi32(X3, Y3); \ + } + +/** + * blockmix_salsa8(Bin, Bout, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. + */ +static inline void +blockmix_salsa8(const __m128i *Bin, __m128i *Bout, size_t r) +{ + __m128i X0, X1, X2, X3; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + X0 = Bin[8 * r - 4]; + X1 = Bin[8 * r - 3]; + X2 = Bin[8 * r - 2]; + X3 = Bin[8 * r - 1]; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(Bin, Bout) + + /* 2: for i = 0 to 2r - 1 do */ + r--; + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8], &Bout[i * 4]) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) +} + +# define XOR4(in) \ + X0 = _mm_xor_si128(X0, (in)[0]); \ + X1 = _mm_xor_si128(X1, (in)[1]); \ + X2 = _mm_xor_si128(X2, (in)[2]); \ + X3 = _mm_xor_si128(X3, (in)[3]); + +# define XOR4_2(in1, in2) \ + X0 = _mm_xor_si128((in1)[0], (in2)[0]); \ + X1 = _mm_xor_si128((in1)[1], (in2)[1]); \ + X2 = _mm_xor_si128((in1)[2], (in2)[2]); \ + X3 = _mm_xor_si128((in1)[3], (in2)[3]); + +static inline uint32_t +blockmix_salsa8_xor(const __m128i *Bin1, const __m128i *Bin2, __m128i *Bout, + size_t r) +{ + __m128i X0, X1, X2, X3; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + XOR4_2(&Bin1[8 * r - 4], &Bin2[8 * r - 4]) + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1) + SALSA20_8_XOR(Bin2, Bout) + + /* 2: for i = 0 to 2r - 1 do */ + r--; + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8 + 4]) + SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8]) + SALSA20_8_XOR(&Bin2[i * 8], &Bout[i * 4]) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8 + 4]) + SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + return _mm_cvtsi128_si32(X0); +} + +# undef ARX +# undef SALSA20_2ROUNDS +# undef SALSA20_8_XOR +# undef XOR4 +# undef XOR4_2 + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + * Note that B's layout is permuted compared to the generic implementation. + */ +static inline uint32_t +integerify(const void *B, size_t r) +{ + return *(const uint32_t *) ((uintptr_t)(B) + (2 * r - 1) * 64); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t *B, size_t r, uint32_t N, void *V, void *XY) +{ + size_t s = 128 * r; + __m128i * X = (__m128i *) V, *Y; + uint32_t *X32 = (uint32_t *) V; + uint32_t i, j; + size_t k; + + /* 1: X <-- B */ + /* 3: V_i <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + X32[k * 16 + i] = LOAD32_LE(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + /* 2: for i = 0 to N - 1 do */ + for (i = 1; i < N - 1; i += 2) { + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = (__m128i *) ((uintptr_t)(V) + i * s); + blockmix_salsa8(X, Y, r); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = (__m128i *) ((uintptr_t)(V) + (i + 1) * s); + blockmix_salsa8(Y, X, r); + } + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = (__m128i *) ((uintptr_t)(V) + i * s); + blockmix_salsa8(X, Y, r); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = (__m128i *) XY; + blockmix_salsa8(Y, X, r); + + X32 = (uint32_t *) XY; + Y = (__m128i *) ((uintptr_t)(XY) + s); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + __m128i *V_j = (__m128i *) ((uintptr_t)(V) + j * s); + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_salsa8_xor(X, V_j, Y, r) & (N - 1); + V_j = (__m128i *) ((uintptr_t)(V) + j * s); + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_salsa8_xor(Y, V_j, X, r) & (N - 1); + } + + /* 10: B' <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + STORE32_LE(&B[(k * 16 + (i * 5 % 16)) * 4], X32[k * 16 + i]); + } + } +} + +/** + * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + * N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +escrypt_kdf_sse(escrypt_local_t *local, const uint8_t *passwd, size_t passwdlen, + const uint8_t *salt, size_t saltlen, uint64_t N, uint32_t _r, + uint32_t _p, uint8_t *buf, size_t buflen) +{ + size_t B_size, V_size, XY_size, need; + uint8_t * B; + uint32_t *V, *XY; + size_t r = _r, p = _p; + uint32_t i; + +/* Sanity-check parameters. */ +# if SIZE_MAX > UINT32_MAX +/* LCOV_EXCL_START */ + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +/* LCOV_EXCL_END */ +# endif + if ((uint64_t)(r) * (uint64_t)(p) >= ((uint64_t) 1 << 30)) { + errno = EFBIG; + return -1; + } + if (N > UINT32_MAX) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + return -1; + } + if (r == 0 || p == 0) { + errno = EINVAL; + return -1; + } +/* LCOV_EXCL_START */ + if ((r > SIZE_MAX / 128 / p) || +# if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +# endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } +/* LCOV_EXCL_END */ + + /* Allocate memory. */ + B_size = (size_t) 128 * r * p; + V_size = (size_t) 128 * r * N; + need = B_size + V_size; +/* LCOV_EXCL_START */ + if (need < V_size) { + errno = ENOMEM; + return -1; + } +/* LCOV_EXCL_END */ + XY_size = (size_t) 256 * r + 64; + need += XY_size; +/* LCOV_EXCL_START */ + if (need < XY_size) { + errno = ENOMEM; + return -1; + } +/* LCOV_EXCL_END */ + if (local->size < need) { + if (free_region(local)) { + return -1; /* LCOV_EXCL_LINE */ + } + if (!alloc_region(local, need)) { + return -1; /* LCOV_EXCL_LINE */ + } + } + B = (uint8_t *) local->aligned; + V = (uint32_t *) ((uint8_t *) B + B_size); + XY = (uint32_t *) ((uint8_t *) V + V_size); + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[(size_t) 128 * i * r], r, (uint32_t) N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); + + /* Success! */ + return 0; +} +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/crypto_scalarmult.c b/libs/libsodium/src/crypto_scalarmult/crypto_scalarmult.c new file mode 100644 index 0000000000..9afffce8a9 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/crypto_scalarmult.c @@ -0,0 +1,33 @@ + +#include "crypto_scalarmult.h" + +const char * +crypto_scalarmult_primitive(void) +{ + return crypto_scalarmult_PRIMITIVE; +} + +int +crypto_scalarmult_base(unsigned char *q, const unsigned char *n) +{ + return crypto_scalarmult_curve25519_base(q, n); +} + +int +crypto_scalarmult(unsigned char *q, const unsigned char *n, + const unsigned char *p) +{ + return crypto_scalarmult_curve25519(q, n, p); +} + +size_t +crypto_scalarmult_bytes(void) +{ + return crypto_scalarmult_BYTES; +} + +size_t +crypto_scalarmult_scalarbytes(void) +{ + return crypto_scalarmult_SCALARBYTES; +} diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/ref10/x25519_ref10.c b/libs/libsodium/src/crypto_scalarmult/curve25519/ref10/x25519_ref10.c new file mode 100644 index 0000000000..7b93a7247b --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/ref10/x25519_ref10.c @@ -0,0 +1,159 @@ + +#include +#include + +#include "../scalarmult_curve25519.h" +#include "export.h" +#include "private/ed25519_ref10.h" +#include "utils.h" +#include "x25519_ref10.h" + +/* + * Reject small order points early to mitigate the implications of + * unexpected optimizations that would affect the ref10 code. + * See https://eprint.iacr.org/2017/806.pdf for reference. + */ +static int +has_small_order(const unsigned char s[32]) +{ + CRYPTO_ALIGN(16) + static const unsigned char blacklist[][32] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00 }, + { 0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57 }, + { 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + { 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, + { 0xcd, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x80 }, + { 0x4c, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7 }, + { 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + }; + unsigned char c[12] = { 0 }; + unsigned int k; + size_t i, j; + + COMPILER_ASSERT(12 == sizeof blacklist / sizeof blacklist[0]); + for (j = 0; j < 32; j++) { + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + c[i] |= s[j] ^ blacklist[i][j]; + } + } + k = 0; + for (i = 0; i < sizeof blacklist / sizeof blacklist[0]; i++) { + k |= (c[i] - 1); + } + return (int) ((k >> 8) & 1); +} + +static int +crypto_scalarmult_curve25519_ref10(unsigned char *q, + const unsigned char *n, + const unsigned char *p) +{ + unsigned char *t = q; + unsigned int i; + fe25519 x1; + fe25519 x2; + fe25519 z2; + fe25519 x3; + fe25519 z3; + fe25519 tmp0; + fe25519 tmp1; + int pos; + unsigned int swap; + unsigned int b; + + if (has_small_order(p)) { + return -1; + } + for (i = 0; i < 32; i++) { + t[i] = n[i]; + } + t[0] &= 248; + t[31] &= 127; + t[31] |= 64; + fe25519_frombytes(x1, p); + fe25519_1(x2); + fe25519_0(z2); + fe25519_copy(x3, x1); + fe25519_1(z3); + + swap = 0; + for (pos = 254; pos >= 0; --pos) { + b = t[pos / 8] >> (pos & 7); + b &= 1; + swap ^= b; + fe25519_cswap(x2, x3, swap); + fe25519_cswap(z2, z3, swap); + swap = b; + fe25519_sub(tmp0, x3, z3); + fe25519_sub(tmp1, x2, z2); + fe25519_add(x2, x2, z2); + fe25519_add(z2, x3, z3); + fe25519_mul(z3, tmp0, x2); + fe25519_mul(z2, z2, tmp1); + fe25519_sq(tmp0, tmp1); + fe25519_sq(tmp1, x2); + fe25519_add(x3, z3, z2); + fe25519_sub(z2, z3, z2); + fe25519_mul(x2, tmp1, tmp0); + fe25519_sub(tmp1, tmp1, tmp0); + fe25519_sq(z2, z2); + fe25519_scalar_product(z3, tmp1, 121666); + fe25519_sq(x3, x3); + fe25519_add(tmp0, tmp0, z3); + fe25519_mul(z3, x1, z2); + fe25519_mul(z2, tmp1, tmp0); + } + fe25519_cswap(x2, x3, swap); + fe25519_cswap(z2, z3, swap); + + fe25519_invert(z2, z2); + fe25519_mul(x2, x2, z2); + fe25519_tobytes(q, x2); + + return 0; +} + +static void +edwards_to_montgomery(fe25519 montgomeryX, const fe25519 edwardsY, const fe25519 edwardsZ) +{ + fe25519 tempX; + fe25519 tempZ; + + fe25519_add(tempX, edwardsZ, edwardsY); + fe25519_sub(tempZ, edwardsZ, edwardsY); + fe25519_invert(tempZ, tempZ); + fe25519_mul(montgomeryX, tempX, tempZ); +} + +static int +crypto_scalarmult_curve25519_ref10_base(unsigned char *q, + const unsigned char *n) +{ + unsigned char *t = q; + ge25519_p3 A; + fe25519 pk; + unsigned int i; + + for (i = 0; i < 32; i++) { + t[i] = n[i]; + } + t[0] &= 248; + t[31] &= 127; + t[31] |= 64; + ge25519_scalarmult_base(&A, t); + edwards_to_montgomery(pk, A.Y, A.Z); + fe25519_tobytes(q, pk); + + return 0; +} + +struct crypto_scalarmult_curve25519_implementation + crypto_scalarmult_curve25519_ref10_implementation = { + SODIUM_C99(.mult =) crypto_scalarmult_curve25519_ref10, + SODIUM_C99(.mult_base =) crypto_scalarmult_curve25519_ref10_base + }; diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/ref10/x25519_ref10.h b/libs/libsodium/src/crypto_scalarmult/curve25519/ref10/x25519_ref10.h new file mode 100644 index 0000000000..ea52a62a69 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/ref10/x25519_ref10.h @@ -0,0 +1,10 @@ +#ifndef x25519_ref10_H +#define x25519_ref10_H + +#include "crypto_scalarmult_curve25519.h" +#include "../scalarmult_curve25519.h" + +extern struct crypto_scalarmult_curve25519_implementation + crypto_scalarmult_curve25519_ref10_implementation; + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/consts.S b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/consts.S new file mode 100644 index 0000000000..67f1f0183e --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/consts.S @@ -0,0 +1,25 @@ +#ifdef IN_SANDY2X + +/* + REDMASK51 is from amd64-51/consts.s. +*/ + +#include "consts_namespace.h" +.data +.p2align 4 +v0_0: .quad 0, 0 +v1_0: .quad 1, 0 +v2_1: .quad 2, 1 +v9_0: .quad 9, 0 +v9_9: .quad 9, 9 +v19_19: .quad 19, 19 +v38_1: .quad 38, 1 +v38_38: .quad 38, 38 +v121666_121666: .quad 121666, 121666 +m25: .quad 33554431, 33554431 +m26: .quad 67108863, 67108863 +subc0: .quad 0x07FFFFDA, 0x03FFFFFE +subc2: .quad 0x07FFFFFE, 0x03FFFFFE +REDMASK51: .quad 0x0007FFFFFFFFFFFF + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/consts_namespace.h b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/consts_namespace.h new file mode 100644 index 0000000000..9f81fa61c4 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/consts_namespace.h @@ -0,0 +1,20 @@ +#ifndef consts_namespace_H +#define consts_namespace_H + +#define v0_0 crypto_scalarmult_curve25519_sandy2x_v0_0 +#define v1_0 crypto_scalarmult_curve25519_sandy2x_v1_0 +#define v2_1 crypto_scalarmult_curve25519_sandy2x_v2_1 +#define v9_0 crypto_scalarmult_curve25519_sandy2x_v9_0 +#define v9_9 crypto_scalarmult_curve25519_sandy2x_v9_9 +#define v19_19 crypto_scalarmult_curve25519_sandy2x_v19_19 +#define v38_1 crypto_scalarmult_curve25519_sandy2x_v38_1 +#define v38_38 crypto_scalarmult_curve25519_sandy2x_v38_38 +#define v121666_121666 crypto_scalarmult_curve25519_sandy2x_v121666_121666 +#define m25 crypto_scalarmult_curve25519_sandy2x_m25 +#define m26 crypto_scalarmult_curve25519_sandy2x_m26 +#define subc0 crypto_scalarmult_curve25519_sandy2x_subc0 +#define subc2 crypto_scalarmult_curve25519_sandy2x_subc2 +#define REDMASK51 crypto_scalarmult_curve25519_sandy2x_REDMASK51 + +#endif /* ifndef consts_namespace_H */ + diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c new file mode 100644 index 0000000000..98b7cf79e5 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.c @@ -0,0 +1,114 @@ +/* + This file is adapted from ref10/scalarmult.c: + The code for Mongomery ladder is replace by the ladder assembly function; + Inversion is done in the same way as amd64-51/. + (fe is first converted into fe51 after Mongomery ladder) +*/ + +#include + +#ifdef HAVE_AVX_ASM + +#include "utils.h" +#include "curve25519_sandy2x.h" +#include "../scalarmult_curve25519.h" +#include "fe.h" +#include "fe51.h" +#include "ladder.h" +#include "ladder_base.h" + +#define x1 var[0] +#define x2 var[1] +#define z2 var[2] + +static int +crypto_scalarmult_curve25519_sandy2x(unsigned char *q, const unsigned char *n, + const unsigned char *p) +{ + unsigned char *t = q; + fe var[3]; + fe51 x_51; + fe51 z_51; + unsigned int i; + + for (i = 0; i < 32; i++) { + t[i] = n[i]; + } + t[0] &= 248; + t[31] &= 127; + t[31] |= 64; + + fe_frombytes(x1, p); + + ladder(var, t); + + z_51.v[0] = (z2[1] << 26) + z2[0]; + z_51.v[1] = (z2[3] << 26) + z2[2]; + z_51.v[2] = (z2[5] << 26) + z2[4]; + z_51.v[3] = (z2[7] << 26) + z2[6]; + z_51.v[4] = (z2[9] << 26) + z2[8]; + + x_51.v[0] = (x2[1] << 26) + x2[0]; + x_51.v[1] = (x2[3] << 26) + x2[2]; + x_51.v[2] = (x2[5] << 26) + x2[4]; + x_51.v[3] = (x2[7] << 26) + x2[6]; + x_51.v[4] = (x2[9] << 26) + x2[8]; + + fe51_invert(&z_51, &z_51); + fe51_mul(&x_51, &x_51, &z_51); + fe51_pack(q, &x_51); + + return 0; +} + +#undef x2 +#undef z2 + +#define x2 var[0] +#define z2 var[1] + +static int +crypto_scalarmult_curve25519_sandy2x_base(unsigned char *q, + const unsigned char *n) +{ + unsigned char *t = q; + fe var[3]; + fe51 x_51; + fe51 z_51; + unsigned int i; + + for (i = 0;i < 32; i++) { + t[i] = n[i]; + } + t[0] &= 248; + t[31] &= 127; + t[31] |= 64; + + ladder_base(var, t); + + z_51.v[0] = (z2[1] << 26) + z2[0]; + z_51.v[1] = (z2[3] << 26) + z2[2]; + z_51.v[2] = (z2[5] << 26) + z2[4]; + z_51.v[3] = (z2[7] << 26) + z2[6]; + z_51.v[4] = (z2[9] << 26) + z2[8]; + + x_51.v[0] = (x2[1] << 26) + x2[0]; + x_51.v[1] = (x2[3] << 26) + x2[2]; + x_51.v[2] = (x2[5] << 26) + x2[4]; + x_51.v[3] = (x2[7] << 26) + x2[6]; + x_51.v[4] = (x2[9] << 26) + x2[8]; + + fe51_invert(&z_51, &z_51); + fe51_mul(&x_51, &x_51, &z_51); + fe51_pack(q, &x_51); + + return 0; +} + +struct crypto_scalarmult_curve25519_implementation +crypto_scalarmult_curve25519_sandy2x_implementation = { + SODIUM_C99(.mult = ) crypto_scalarmult_curve25519_sandy2x, + SODIUM_C99(.mult_base = ) crypto_scalarmult_curve25519_sandy2x_base +}; + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.h b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.h new file mode 100644 index 0000000000..f02d980187 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/curve25519_sandy2x.h @@ -0,0 +1,9 @@ +#ifndef curve25519_sandy2x_H +#define curve25519_sandy2x_H + +#include "crypto_scalarmult_curve25519.h" + +extern struct crypto_scalarmult_curve25519_implementation + crypto_scalarmult_curve25519_sandy2x_implementation; + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe.h b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe.h new file mode 100644 index 0000000000..b1115f8691 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe.h @@ -0,0 +1,26 @@ +/* + This file is adapted from ref10/fe.h: + All the redundant functions are removed. +*/ + +#ifndef fe_H +#define fe_H + +#include +#include + +typedef uint64_t fe[10]; + +/* +fe means field element. +Here the field is \Z/(2^255-19). +An element t, entries t[0]...t[9], represents the integer +t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. +Bounds on each t[i] vary depending on context. +*/ + +#define fe_frombytes crypto_scalarmult_curve25519_sandy2x_fe_frombytes + +extern void fe_frombytes(fe, const unsigned char *); + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51.h b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51.h new file mode 100644 index 0000000000..8e3f199b24 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51.h @@ -0,0 +1,35 @@ +/* + This file is adapted from amd64-51/fe25519.h: + 'fe25519' is renamed as 'fe51'; + All the redundant functions are removed; + New function fe51_nsquare is introduced. +*/ + +#ifndef fe51_H +#define fe51_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "fe51_namespace.h" + +typedef struct +{ + uint64_t v[5]; +} +fe51; + +extern void fe51_pack(unsigned char *, const fe51 *); +extern void fe51_mul(fe51 *, const fe51 *, const fe51 *); +extern void fe51_nsquare(fe51 *, const fe51 *, int); +extern void fe51_invert(fe51 *, const fe51 *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c new file mode 100644 index 0000000000..ec9bb1a91f --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_invert.c @@ -0,0 +1,58 @@ +/* + This file is adapted from amd64-51/fe25519_invert.c: + Loops of squares are replaced by nsquares for better performance. +*/ + +#include "fe51.h" + +#ifdef HAVE_AVX_ASM + +#define fe51_square(x, y) fe51_nsquare(x, y, 1) + +void +fe51_invert(fe51 *r, const fe51 *x) +{ + fe51 z2; + fe51 z9; + fe51 z11; + fe51 z2_5_0; + fe51 z2_10_0; + fe51 z2_20_0; + fe51 z2_50_0; + fe51 z2_100_0; + fe51 t; + + /* 2 */ fe51_square(&z2,x); + /* 4 */ fe51_square(&t,&z2); + /* 8 */ fe51_square(&t,&t); + /* 9 */ fe51_mul(&z9,&t,x); + /* 11 */ fe51_mul(&z11,&z9,&z2); + /* 22 */ fe51_square(&t,&z11); + /* 2^5 - 2^0 = 31 */ fe51_mul(&z2_5_0,&t,&z9); + + /* 2^10 - 2^5 */ fe51_nsquare(&t,&z2_5_0, 5); + /* 2^10 - 2^0 */ fe51_mul(&z2_10_0,&t,&z2_5_0); + + /* 2^20 - 2^10 */ fe51_nsquare(&t,&z2_10_0, 10); + /* 2^20 - 2^0 */ fe51_mul(&z2_20_0,&t,&z2_10_0); + + /* 2^40 - 2^20 */ fe51_nsquare(&t,&z2_20_0, 20); + /* 2^40 - 2^0 */ fe51_mul(&t,&t,&z2_20_0); + + /* 2^50 - 2^10 */ fe51_nsquare(&t,&t,10); + /* 2^50 - 2^0 */ fe51_mul(&z2_50_0,&t,&z2_10_0); + + /* 2^100 - 2^50 */ fe51_nsquare(&t,&z2_50_0, 50); + /* 2^100 - 2^0 */ fe51_mul(&z2_100_0,&t,&z2_50_0); + + /* 2^200 - 2^100 */ fe51_nsquare(&t,&z2_100_0, 100); + /* 2^200 - 2^0 */ fe51_mul(&t,&t,&z2_100_0); + + /* 2^250 - 2^50 */ fe51_nsquare(&t,&t, 50); + /* 2^250 - 2^0 */ fe51_mul(&t,&t,&z2_50_0); + + /* 2^255 - 2^5 */ fe51_nsquare(&t,&t,5); + /* 2^255 - 21 */ fe51_mul(r,&t,&z11); +} + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S new file mode 100644 index 0000000000..83501b0395 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_mul.S @@ -0,0 +1,197 @@ +#ifdef IN_SANDY2X + +/* + This file is basically amd64-51/fe25519_mul.s. +*/ +#include "fe51_namespace.h" +#include "consts_namespace.h" +.text +.p2align 5 +#ifdef ASM_HIDE_SYMBOL +ASM_HIDE_SYMBOL fe51_mul +ASM_HIDE_SYMBOL _fe51_mul +#endif +.globl fe51_mul +.globl _fe51_mul +#ifdef __ELF__ +.type fe51_mul, @function +.type _fe51_mul, @function +#endif +fe51_mul: +_fe51_mul: +mov %rsp,%r11 +and $31,%r11 +add $96,%r11 +sub %r11,%rsp +movq %r11,0(%rsp) +movq %r12,8(%rsp) +movq %r13,16(%rsp) +movq %r14,24(%rsp) +movq %r15,32(%rsp) +movq %rbx,40(%rsp) +movq %rbp,48(%rsp) +movq %rdi,56(%rsp) +mov %rdx,%rcx +movq 24(%rsi),%rdx +imulq $19,%rdx,%rax +movq %rax,64(%rsp) +mulq 16(%rcx) +mov %rax,%r8 +mov %rdx,%r9 +movq 32(%rsi),%rdx +imulq $19,%rdx,%rax +movq %rax,72(%rsp) +mulq 8(%rcx) +add %rax,%r8 +adc %rdx,%r9 +movq 0(%rsi),%rax +mulq 0(%rcx) +add %rax,%r8 +adc %rdx,%r9 +movq 0(%rsi),%rax +mulq 8(%rcx) +mov %rax,%r10 +mov %rdx,%r11 +movq 0(%rsi),%rax +mulq 16(%rcx) +mov %rax,%r12 +mov %rdx,%r13 +movq 0(%rsi),%rax +mulq 24(%rcx) +mov %rax,%r14 +mov %rdx,%r15 +movq 0(%rsi),%rax +mulq 32(%rcx) +mov %rax,%rbx +mov %rdx,%rbp +movq 8(%rsi),%rax +mulq 0(%rcx) +add %rax,%r10 +adc %rdx,%r11 +movq 8(%rsi),%rax +mulq 8(%rcx) +add %rax,%r12 +adc %rdx,%r13 +movq 8(%rsi),%rax +mulq 16(%rcx) +add %rax,%r14 +adc %rdx,%r15 +movq 8(%rsi),%rax +mulq 24(%rcx) +add %rax,%rbx +adc %rdx,%rbp +movq 8(%rsi),%rdx +imulq $19,%rdx,%rax +mulq 32(%rcx) +add %rax,%r8 +adc %rdx,%r9 +movq 16(%rsi),%rax +mulq 0(%rcx) +add %rax,%r12 +adc %rdx,%r13 +movq 16(%rsi),%rax +mulq 8(%rcx) +add %rax,%r14 +adc %rdx,%r15 +movq 16(%rsi),%rax +mulq 16(%rcx) +add %rax,%rbx +adc %rdx,%rbp +movq 16(%rsi),%rdx +imulq $19,%rdx,%rax +mulq 24(%rcx) +add %rax,%r8 +adc %rdx,%r9 +movq 16(%rsi),%rdx +imulq $19,%rdx,%rax +mulq 32(%rcx) +add %rax,%r10 +adc %rdx,%r11 +movq 24(%rsi),%rax +mulq 0(%rcx) +add %rax,%r14 +adc %rdx,%r15 +movq 24(%rsi),%rax +mulq 8(%rcx) +add %rax,%rbx +adc %rdx,%rbp +movq 64(%rsp),%rax +mulq 24(%rcx) +add %rax,%r10 +adc %rdx,%r11 +movq 64(%rsp),%rax +mulq 32(%rcx) +add %rax,%r12 +adc %rdx,%r13 +movq 32(%rsi),%rax +mulq 0(%rcx) +add %rax,%rbx +adc %rdx,%rbp +movq 72(%rsp),%rax +mulq 16(%rcx) +add %rax,%r10 +adc %rdx,%r11 +movq 72(%rsp),%rax +mulq 24(%rcx) +add %rax,%r12 +adc %rdx,%r13 +movq 72(%rsp),%rax +mulq 32(%rcx) +add %rax,%r14 +adc %rdx,%r15 +movq REDMASK51(%rip),%rsi +shld $13,%r8,%r9 +and %rsi,%r8 +shld $13,%r10,%r11 +and %rsi,%r10 +add %r9,%r10 +shld $13,%r12,%r13 +and %rsi,%r12 +add %r11,%r12 +shld $13,%r14,%r15 +and %rsi,%r14 +add %r13,%r14 +shld $13,%rbx,%rbp +and %rsi,%rbx +add %r15,%rbx +imulq $19,%rbp,%rdx +add %rdx,%r8 +mov %r8,%rdx +shr $51,%rdx +add %r10,%rdx +mov %rdx,%rcx +shr $51,%rdx +and %rsi,%r8 +add %r12,%rdx +mov %rdx,%r9 +shr $51,%rdx +and %rsi,%rcx +add %r14,%rdx +mov %rdx,%rax +shr $51,%rdx +and %rsi,%r9 +add %rbx,%rdx +mov %rdx,%r10 +shr $51,%rdx +and %rsi,%rax +imulq $19,%rdx,%rdx +add %rdx,%r8 +and %rsi,%r10 +movq %r8,0(%rdi) +movq %rcx,8(%rdi) +movq %r9,16(%rdi) +movq %rax,24(%rdi) +movq %r10,32(%rdi) +movq 0(%rsp),%r11 +movq 8(%rsp),%r12 +movq 16(%rsp),%r13 +movq 24(%rsp),%r14 +movq 32(%rsp),%r15 +movq 40(%rsp),%rbx +movq 48(%rsp),%rbp +add %r11,%rsp +mov %rdi,%rax +mov %rsi,%rdx +ret + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_namespace.h b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_namespace.h new file mode 100644 index 0000000000..057f242ca1 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_namespace.h @@ -0,0 +1,16 @@ +#ifndef fe51_namespace_H +#define fe51_namespace_H + +#define fe51 crypto_scalarmult_curve25519_sandy2x_fe51 +#define _fe51 _crypto_scalarmult_curve25519_sandy2x_fe51 +#define fe51_pack crypto_scalarmult_curve25519_sandy2x_fe51_pack +#define _fe51_pack _crypto_scalarmult_curve25519_sandy2x_fe51_pack +#define fe51_mul crypto_scalarmult_curve25519_sandy2x_fe51_mul +#define _fe51_mul _crypto_scalarmult_curve25519_sandy2x_fe51_mul +#define fe51_nsquare crypto_scalarmult_curve25519_sandy2x_fe51_nsquare +#define _fe51_nsquare _crypto_scalarmult_curve25519_sandy2x_fe51_nsquare + +#define fe51_invert crypto_scalarmult_curve25519_sandy2x_fe51_invert + +#endif /* ifndef fe51_namespace_H */ + diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S new file mode 100644 index 0000000000..41c3054805 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_nsquare.S @@ -0,0 +1,172 @@ +#ifdef IN_SANDY2X + +/* + This file is adapted from amd64-51/fe25519_square.s: + Adding loop to perform n squares. +*/ +#include "fe51_namespace.h" +#include "consts_namespace.h" +.p2align 5 + +#ifdef ASM_HIDE_SYMBOL +ASM_HIDE_SYMBOL fe51_nsquare +ASM_HIDE_SYMBOL _fe51_nsquare +#endif +.globl fe51_nsquare +.globl _fe51_nsquare +#ifdef __ELF__ +.type fe51_nsquare, @function +.type _fe51_nsquare, @function +#endif +fe51_nsquare: +_fe51_nsquare: + +mov %rsp,%r11 +and $31,%r11 +add $64,%r11 +sub %r11,%rsp +movq %r11,0(%rsp) +movq %r12,8(%rsp) +movq %r13,16(%rsp) +movq %r14,24(%rsp) +movq %r15,32(%rsp) +movq %rbx,40(%rsp) +movq %rbp,48(%rsp) +movq 0(%rsi),%rcx +movq 8(%rsi),%r8 +movq 16(%rsi),%r9 +movq 24(%rsi),%rax +movq 32(%rsi),%rsi +movq %r9,16(%rdi) +movq %rax,24(%rdi) +movq %rsi,32(%rdi) +mov %rdx,%rsi + +.p2align 4 +._loop: +sub $1,%rsi +mov %rcx,%rax +mul %rcx +add %rcx,%rcx +mov %rax,%r9 +mov %rdx,%r10 +mov %rcx,%rax +mul %r8 +mov %rax,%r11 +mov %rdx,%r12 +mov %rcx,%rax +mulq 16(%rdi) +mov %rax,%r13 +mov %rdx,%r14 +mov %rcx,%rax +mulq 24(%rdi) +mov %rax,%r15 +mov %rdx,%rbx +mov %rcx,%rax +mulq 32(%rdi) +mov %rax,%rcx +mov %rdx,%rbp +mov %r8,%rax +mul %r8 +add %r8,%r8 +add %rax,%r13 +adc %rdx,%r14 +mov %r8,%rax +mulq 16(%rdi) +add %rax,%r15 +adc %rdx,%rbx +mov %r8,%rax +imulq $19, %r8,%r8 +mulq 24(%rdi) +add %rax,%rcx +adc %rdx,%rbp +mov %r8,%rax +mulq 32(%rdi) +add %rax,%r9 +adc %rdx,%r10 +movq 16(%rdi),%rax +mulq 16(%rdi) +add %rax,%rcx +adc %rdx,%rbp +shld $13,%rcx,%rbp +movq 16(%rdi),%rax +imulq $38, %rax,%rax +mulq 24(%rdi) +add %rax,%r9 +adc %rdx,%r10 +shld $13,%r9,%r10 +movq 16(%rdi),%rax +imulq $38, %rax,%rax +mulq 32(%rdi) +add %rax,%r11 +adc %rdx,%r12 +movq 24(%rdi),%rax +imulq $19, %rax,%rax +mulq 24(%rdi) +add %rax,%r11 +adc %rdx,%r12 +shld $13,%r11,%r12 +movq 24(%rdi),%rax +imulq $38, %rax,%rax +mulq 32(%rdi) +add %rax,%r13 +adc %rdx,%r14 +shld $13,%r13,%r14 +movq 32(%rdi),%rax +imulq $19, %rax,%rax +mulq 32(%rdi) +add %rax,%r15 +adc %rdx,%rbx +shld $13,%r15,%rbx +movq REDMASK51(%rip),%rdx +and %rdx,%rcx +add %rbx,%rcx +and %rdx,%r9 +and %rdx,%r11 +add %r10,%r11 +and %rdx,%r13 +add %r12,%r13 +and %rdx,%r15 +add %r14,%r15 +imulq $19, %rbp,%rbp +lea (%r9,%rbp),%r9 +mov %r9,%rax +shr $51,%r9 +add %r11,%r9 +and %rdx,%rax +mov %r9,%r8 +shr $51,%r9 +add %r13,%r9 +and %rdx,%r8 +mov %r9,%r10 +shr $51,%r9 +add %r15,%r9 +and %rdx,%r10 +movq %r10,16(%rdi) +mov %r9,%r10 +shr $51,%r9 +add %rcx,%r9 +and %rdx,%r10 +movq %r10,24(%rdi) +mov %r9,%r10 +shr $51,%r9 +imulq $19, %r9,%r9 +lea (%rax,%r9),%rcx +and %rdx,%r10 +movq %r10,32(%rdi) +cmp $0,%rsi +jne ._loop + +movq %rcx,0(%rdi) +movq %r8,8(%rdi) +movq 0(%rsp),%r11 +movq 8(%rsp),%r12 +movq 16(%rsp),%r13 +movq 24(%rsp),%r14 +movq 32(%rsp),%r15 +movq 40(%rsp),%rbx +movq 48(%rsp),%rbp +add %r11,%rsp +ret + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S new file mode 100644 index 0000000000..500c858476 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe51_pack.S @@ -0,0 +1,226 @@ +#ifdef IN_SANDY2X + +/* + This file is the result of merging + amd64-51/fe25519_pack.c and amd64-51/fe25519_freeze.s. +*/ +#include "fe51_namespace.h" +#include "consts_namespace.h" +.p2align 5 + +#ifdef ASM_HIDE_SYMBOL +ASM_HIDE_SYMBOL fe51_pack +ASM_HIDE_SYMBOL _fe51_pack +#endif +.globl fe51_pack +.globl _fe51_pack +#ifdef __ELF__ +.type fe51_pack, @function +.type _fe51_pack, @function +#endif +fe51_pack: +_fe51_pack: + +mov %rsp,%r11 +and $31,%r11 +add $32,%r11 +sub %r11,%rsp +movq %r11,0(%rsp) +movq %r12,8(%rsp) +movq 0(%rsi),%rdx +movq 8(%rsi),%rcx +movq 16(%rsi),%r8 +movq 24(%rsi),%r9 +movq 32(%rsi),%rsi +movq REDMASK51(%rip),%rax +lea -18(%rax),%r10 +mov $3,%r11 + +.p2align 4 +._reduceloop: +mov %rdx,%r12 +shr $51,%r12 +and %rax,%rdx +add %r12,%rcx +mov %rcx,%r12 +shr $51,%r12 +and %rax,%rcx +add %r12,%r8 +mov %r8,%r12 +shr $51,%r12 +and %rax,%r8 +add %r12,%r9 +mov %r9,%r12 +shr $51,%r12 +and %rax,%r9 +add %r12,%rsi +mov %rsi,%r12 +shr $51,%r12 +and %rax,%rsi +imulq $19, %r12,%r12 +add %r12,%rdx +sub $1,%r11 +ja ._reduceloop + +mov $1,%r12 +cmp %r10,%rdx +cmovl %r11,%r12 +cmp %rax,%rcx +cmovne %r11,%r12 +cmp %rax,%r8 +cmovne %r11,%r12 +cmp %rax,%r9 +cmovne %r11,%r12 +cmp %rax,%rsi +cmovne %r11,%r12 +neg %r12 +and %r12,%rax +and %r12,%r10 +sub %r10,%rdx +sub %rax,%rcx +sub %rax,%r8 +sub %rax,%r9 +sub %rax,%rsi +mov %rdx,%rax +and $0xFF,%eax +movb %al,0(%rdi) +mov %rdx,%rax +shr $8,%rax +and $0xFF,%eax +movb %al,1(%rdi) +mov %rdx,%rax +shr $16,%rax +and $0xFF,%eax +movb %al,2(%rdi) +mov %rdx,%rax +shr $24,%rax +and $0xFF,%eax +movb %al,3(%rdi) +mov %rdx,%rax +shr $32,%rax +and $0xFF,%eax +movb %al,4(%rdi) +mov %rdx,%rax +shr $40,%rax +and $0xFF,%eax +movb %al,5(%rdi) +mov %rdx,%rdx +shr $48,%rdx +mov %rcx,%rax +shl $3,%rax +and $0xF8,%eax +xor %rdx,%rax +movb %al,6(%rdi) +mov %rcx,%rdx +shr $5,%rdx +and $0xFF,%edx +movb %dl,7(%rdi) +mov %rcx,%rdx +shr $13,%rdx +and $0xFF,%edx +movb %dl,8(%rdi) +mov %rcx,%rdx +shr $21,%rdx +and $0xFF,%edx +movb %dl,9(%rdi) +mov %rcx,%rdx +shr $29,%rdx +and $0xFF,%edx +movb %dl,10(%rdi) +mov %rcx,%rdx +shr $37,%rdx +and $0xFF,%edx +movb %dl,11(%rdi) +mov %rcx,%rdx +shr $45,%rdx +mov %r8,%rcx +shl $6,%rcx +and $0xC0,%ecx +xor %rdx,%rcx +movb %cl,12(%rdi) +mov %r8,%rdx +shr $2,%rdx +and $0xFF,%edx +movb %dl,13(%rdi) +mov %r8,%rdx +shr $10,%rdx +and $0xFF,%edx +movb %dl,14(%rdi) +mov %r8,%rdx +shr $18,%rdx +and $0xFF,%edx +movb %dl,15(%rdi) +mov %r8,%rdx +shr $26,%rdx +and $0xFF,%edx +movb %dl,16(%rdi) +mov %r8,%rdx +shr $34,%rdx +and $0xFF,%edx +movb %dl,17(%rdi) +mov %r8,%rdx +shr $42,%rdx +movb %dl,18(%rdi) +mov %r8,%rdx +shr $50,%rdx +mov %r9,%rcx +shl $1,%rcx +and $0xFE,%ecx +xor %rdx,%rcx +movb %cl,19(%rdi) +mov %r9,%rdx +shr $7,%rdx +and $0xFF,%edx +movb %dl,20(%rdi) +mov %r9,%rdx +shr $15,%rdx +and $0xFF,%edx +movb %dl,21(%rdi) +mov %r9,%rdx +shr $23,%rdx +and $0xFF,%edx +movb %dl,22(%rdi) +mov %r9,%rdx +shr $31,%rdx +and $0xFF,%edx +movb %dl,23(%rdi) +mov %r9,%rdx +shr $39,%rdx +and $0xFF,%edx +movb %dl,24(%rdi) +mov %r9,%rdx +shr $47,%rdx +mov %rsi,%rcx +shl $4,%rcx +and $0xF0,%ecx +xor %rdx,%rcx +movb %cl,25(%rdi) +mov %rsi,%rdx +shr $4,%rdx +and $0xFF,%edx +movb %dl,26(%rdi) +mov %rsi,%rdx +shr $12,%rdx +and $0xFF,%edx +movb %dl,27(%rdi) +mov %rsi,%rdx +shr $20,%rdx +and $0xFF,%edx +movb %dl,28(%rdi) +mov %rsi,%rdx +shr $28,%rdx +and $0xFF,%edx +movb %dl,29(%rdi) +mov %rsi,%rdx +shr $36,%rdx +and $0xFF,%edx +movb %dl,30(%rdi) +mov %rsi,%rsi +shr $44,%rsi +movb %sil,31(%rdi) +movq 0(%rsp),%r11 +movq 8(%rsp),%r12 +add %r11,%rsp +ret + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c new file mode 100644 index 0000000000..2fe081ee2a --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/fe_frombytes_sandy2x.c @@ -0,0 +1,78 @@ +/* + This file is basically ref10/fe_frombytes.h. +*/ + +#include "fe.h" + +#ifdef HAVE_AVX_ASM + +static uint64_t +load_3(const unsigned char *in) +{ + uint64_t result; + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + return result; +} + +static uint64_t +load_4(const unsigned char *in) +{ + uint64_t result; + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + result |= ((uint64_t) in[3]) << 24; + return result; +} + +void +fe_frombytes(fe h, const unsigned char *s) +{ + uint64_t h0 = load_4(s); + uint64_t h1 = load_3(s + 4) << 6; + uint64_t h2 = load_3(s + 7) << 5; + uint64_t h3 = load_3(s + 10) << 3; + uint64_t h4 = load_3(s + 13) << 2; + uint64_t h5 = load_4(s + 16); + uint64_t h6 = load_3(s + 20) << 7; + uint64_t h7 = load_3(s + 23) << 5; + uint64_t h8 = load_3(s + 26) << 4; + uint64_t h9 = (load_3(s + 29) & 8388607) << 2; + uint64_t carry0; + uint64_t carry1; + uint64_t carry2; + uint64_t carry3; + uint64_t carry4; + uint64_t carry5; + uint64_t carry6; + uint64_t carry7; + uint64_t carry8; + uint64_t carry9; + + carry9 = h9 >> 25; h0 += carry9 * 19; h9 &= 0x1FFFFFF; + carry1 = h1 >> 25; h2 += carry1; h1 &= 0x1FFFFFF; + carry3 = h3 >> 25; h4 += carry3; h3 &= 0x1FFFFFF; + carry5 = h5 >> 25; h6 += carry5; h5 &= 0x1FFFFFF; + carry7 = h7 >> 25; h8 += carry7; h7 &= 0x1FFFFFF; + + carry0 = h0 >> 26; h1 += carry0; h0 &= 0x3FFFFFF; + carry2 = h2 >> 26; h3 += carry2; h2 &= 0x3FFFFFF; + carry4 = h4 >> 26; h5 += carry4; h4 &= 0x3FFFFFF; + carry6 = h6 >> 26; h7 += carry6; h6 &= 0x3FFFFFF; + carry8 = h8 >> 26; h9 += carry8; h8 &= 0x3FFFFFF; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder.S b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder.S new file mode 100644 index 0000000000..c5c06021d8 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder.S @@ -0,0 +1,1440 @@ +#ifdef IN_SANDY2X + +#include "ladder_namespace.h" +#include "consts_namespace.h" +.p2align 5 + +#ifdef ASM_HIDE_SYMBOL +ASM_HIDE_SYMBOL ladder +ASM_HIDE_SYMBOL _ladder +#endif +.globl ladder +.globl _ladder +#ifdef __ELF__ +.type ladder, @function +.type _ladder, @function +#endif +ladder: +_ladder: + +mov %rsp,%r11 +and $31,%r11 +add $1856,%r11 +sub %r11,%rsp +movq %r11,1824(%rsp) +movq %r12,1832(%rsp) +movq %r13,1840(%rsp) +movq %r14,1848(%rsp) +vmovdqa v0_0(%rip),%xmm0 +vmovdqa v1_0(%rip),%xmm1 +vmovdqu 0(%rdi),%xmm2 +vmovdqa %xmm2,0(%rsp) +vmovdqu 16(%rdi),%xmm2 +vmovdqa %xmm2,16(%rsp) +vmovdqu 32(%rdi),%xmm2 +vmovdqa %xmm2,32(%rsp) +vmovdqu 48(%rdi),%xmm2 +vmovdqa %xmm2,48(%rsp) +vmovdqu 64(%rdi),%xmm2 +vmovdqa %xmm2,64(%rsp) +vmovdqa %xmm1,80(%rsp) +vmovdqa %xmm0,96(%rsp) +vmovdqa %xmm0,112(%rsp) +vmovdqa %xmm0,128(%rsp) +vmovdqa %xmm0,144(%rsp) +vmovdqa %xmm1,%xmm0 +vpxor %xmm1,%xmm1,%xmm1 +vpxor %xmm2,%xmm2,%xmm2 +vpxor %xmm3,%xmm3,%xmm3 +vpxor %xmm4,%xmm4,%xmm4 +vpxor %xmm5,%xmm5,%xmm5 +vpxor %xmm6,%xmm6,%xmm6 +vpxor %xmm7,%xmm7,%xmm7 +vpxor %xmm8,%xmm8,%xmm8 +vpxor %xmm9,%xmm9,%xmm9 +vmovdqu 0(%rdi),%xmm10 +vmovdqa %xmm10,160(%rsp) +vmovdqu 16(%rdi),%xmm10 +vmovdqa %xmm10,176(%rsp) +vpmuludq v19_19(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,192(%rsp) +vmovdqu 32(%rdi),%xmm10 +vmovdqa %xmm10,208(%rsp) +vpmuludq v19_19(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,224(%rsp) +vmovdqu 48(%rdi),%xmm10 +vmovdqa %xmm10,240(%rsp) +vpmuludq v19_19(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,256(%rsp) +vmovdqu 64(%rdi),%xmm10 +vmovdqa %xmm10,272(%rsp) +vpmuludq v19_19(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,288(%rsp) +vmovdqu 8(%rdi),%xmm10 +vpmuludq v2_1(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,304(%rsp) +vpmuludq v19_19(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,320(%rsp) +vmovdqu 24(%rdi),%xmm10 +vpmuludq v2_1(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,336(%rsp) +vpmuludq v19_19(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,352(%rsp) +vmovdqu 40(%rdi),%xmm10 +vpmuludq v2_1(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,368(%rsp) +vpmuludq v19_19(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,384(%rsp) +vmovdqu 56(%rdi),%xmm10 +vpmuludq v2_1(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,400(%rsp) +vpmuludq v19_19(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,416(%rsp) +vmovdqu 0(%rdi),%xmm10 +vmovdqu 64(%rdi),%xmm11 +vblendps $12, %xmm11, %xmm10, %xmm10 +vpshufd $2,%xmm10,%xmm10 +vpmuludq v38_1(%rip),%xmm10,%xmm10 +vmovdqa %xmm10,432(%rsp) +movq 0(%rsi),%rdx +movq 8(%rsi),%rcx +movq 16(%rsi),%r8 +movq 24(%rsi),%r9 +shrd $1,%rcx,%rdx +shrd $1,%r8,%rcx +shrd $1,%r9,%r8 +shr $1,%r9 +xorq 0(%rsi),%rdx +xorq 8(%rsi),%rcx +xorq 16(%rsi),%r8 +xorq 24(%rsi),%r9 +leaq 800(%rsp),%rsi +mov $64,%rax + +.p2align 4 +._ladder_small_loop: +mov %rdx,%r10 +mov %rcx,%r11 +mov %r8,%r12 +mov %r9,%r13 +shr $1,%rdx +shr $1,%rcx +shr $1,%r8 +shr $1,%r9 +and $1,%r10d +and $1,%r11d +and $1,%r12d +and $1,%r13d +neg %r10 +neg %r11 +neg %r12 +neg %r13 +movl %r10d,0(%rsi) +movl %r11d,256(%rsi) +movl %r12d,512(%rsi) +movl %r13d,768(%rsi) +add $4,%rsi +sub $1,%rax +jne ._ladder_small_loop +mov $255,%rdx +add $760,%rsi + +.p2align 4 +._ladder_loop: +sub $1,%rdx +vbroadcastss 0(%rsi),%xmm10 +sub $4,%rsi +vmovdqa 0(%rsp),%xmm11 +vmovdqa 80(%rsp),%xmm12 +vpxor %xmm11,%xmm0,%xmm13 +vpand %xmm10,%xmm13,%xmm13 +vpxor %xmm13,%xmm0,%xmm0 +vpxor %xmm13,%xmm11,%xmm11 +vpxor %xmm12,%xmm1,%xmm13 +vpand %xmm10,%xmm13,%xmm13 +vpxor %xmm13,%xmm1,%xmm1 +vpxor %xmm13,%xmm12,%xmm12 +vmovdqa 16(%rsp),%xmm13 +vmovdqa 96(%rsp),%xmm14 +vpxor %xmm13,%xmm2,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm2,%xmm2 +vpxor %xmm15,%xmm13,%xmm13 +vpxor %xmm14,%xmm3,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm3,%xmm3 +vpxor %xmm15,%xmm14,%xmm14 +vmovdqa %xmm13,0(%rsp) +vmovdqa %xmm14,16(%rsp) +vmovdqa 32(%rsp),%xmm13 +vmovdqa 112(%rsp),%xmm14 +vpxor %xmm13,%xmm4,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm4,%xmm4 +vpxor %xmm15,%xmm13,%xmm13 +vpxor %xmm14,%xmm5,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm5,%xmm5 +vpxor %xmm15,%xmm14,%xmm14 +vmovdqa %xmm13,32(%rsp) +vmovdqa %xmm14,80(%rsp) +vmovdqa 48(%rsp),%xmm13 +vmovdqa 128(%rsp),%xmm14 +vpxor %xmm13,%xmm6,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm6,%xmm6 +vpxor %xmm15,%xmm13,%xmm13 +vpxor %xmm14,%xmm7,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm7,%xmm7 +vpxor %xmm15,%xmm14,%xmm14 +vmovdqa %xmm13,48(%rsp) +vmovdqa %xmm14,96(%rsp) +vmovdqa 64(%rsp),%xmm13 +vmovdqa 144(%rsp),%xmm14 +vpxor %xmm13,%xmm8,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm8,%xmm8 +vpxor %xmm15,%xmm13,%xmm13 +vpxor %xmm14,%xmm9,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm9,%xmm9 +vpxor %xmm15,%xmm14,%xmm14 +vmovdqa %xmm13,64(%rsp) +vmovdqa %xmm14,112(%rsp) +vpaddq subc0(%rip),%xmm11,%xmm10 +vpsubq %xmm12,%xmm10,%xmm10 +vpaddq %xmm12,%xmm11,%xmm11 +vpunpckhqdq %xmm10,%xmm11,%xmm12 +vpunpcklqdq %xmm10,%xmm11,%xmm10 +vpaddq %xmm1,%xmm0,%xmm11 +vpaddq subc0(%rip),%xmm0,%xmm0 +vpsubq %xmm1,%xmm0,%xmm0 +vpunpckhqdq %xmm11,%xmm0,%xmm1 +vpunpcklqdq %xmm11,%xmm0,%xmm0 +vpmuludq %xmm0,%xmm10,%xmm11 +vpmuludq %xmm1,%xmm10,%xmm13 +vmovdqa %xmm1,128(%rsp) +vpaddq %xmm1,%xmm1,%xmm1 +vpmuludq %xmm0,%xmm12,%xmm14 +vmovdqa %xmm0,144(%rsp) +vpaddq %xmm14,%xmm13,%xmm13 +vpmuludq %xmm1,%xmm12,%xmm0 +vmovdqa %xmm1,448(%rsp) +vpaddq %xmm3,%xmm2,%xmm1 +vpaddq subc2(%rip),%xmm2,%xmm2 +vpsubq %xmm3,%xmm2,%xmm2 +vpunpckhqdq %xmm1,%xmm2,%xmm3 +vpunpcklqdq %xmm1,%xmm2,%xmm1 +vpmuludq %xmm1,%xmm10,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpmuludq %xmm3,%xmm10,%xmm2 +vmovdqa %xmm3,464(%rsp) +vpaddq %xmm3,%xmm3,%xmm3 +vpmuludq %xmm1,%xmm12,%xmm14 +vmovdqa %xmm1,480(%rsp) +vpaddq %xmm14,%xmm2,%xmm2 +vpmuludq %xmm3,%xmm12,%xmm1 +vmovdqa %xmm3,496(%rsp) +vpaddq %xmm5,%xmm4,%xmm3 +vpaddq subc2(%rip),%xmm4,%xmm4 +vpsubq %xmm5,%xmm4,%xmm4 +vpunpckhqdq %xmm3,%xmm4,%xmm5 +vpunpcklqdq %xmm3,%xmm4,%xmm3 +vpmuludq %xmm3,%xmm10,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vpmuludq %xmm5,%xmm10,%xmm4 +vmovdqa %xmm5,512(%rsp) +vpaddq %xmm5,%xmm5,%xmm5 +vpmuludq %xmm3,%xmm12,%xmm14 +vmovdqa %xmm3,528(%rsp) +vpaddq %xmm14,%xmm4,%xmm4 +vpaddq %xmm7,%xmm6,%xmm3 +vpaddq subc2(%rip),%xmm6,%xmm6 +vpsubq %xmm7,%xmm6,%xmm6 +vpunpckhqdq %xmm3,%xmm6,%xmm7 +vpunpcklqdq %xmm3,%xmm6,%xmm3 +vpmuludq %xmm3,%xmm10,%xmm6 +vpmuludq %xmm5,%xmm12,%xmm14 +vmovdqa %xmm5,544(%rsp) +vpmuludq v19_19(%rip),%xmm5,%xmm5 +vmovdqa %xmm5,560(%rsp) +vpaddq %xmm14,%xmm6,%xmm6 +vpmuludq %xmm7,%xmm10,%xmm5 +vmovdqa %xmm7,576(%rsp) +vpaddq %xmm7,%xmm7,%xmm7 +vpmuludq %xmm3,%xmm12,%xmm14 +vmovdqa %xmm3,592(%rsp) +vpaddq %xmm14,%xmm5,%xmm5 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vmovdqa %xmm3,608(%rsp) +vpaddq %xmm9,%xmm8,%xmm3 +vpaddq subc2(%rip),%xmm8,%xmm8 +vpsubq %xmm9,%xmm8,%xmm8 +vpunpckhqdq %xmm3,%xmm8,%xmm9 +vpunpcklqdq %xmm3,%xmm8,%xmm3 +vmovdqa %xmm3,624(%rsp) +vpmuludq %xmm7,%xmm12,%xmm8 +vmovdqa %xmm7,640(%rsp) +vpmuludq v19_19(%rip),%xmm7,%xmm7 +vmovdqa %xmm7,656(%rsp) +vpmuludq %xmm3,%xmm10,%xmm7 +vpaddq %xmm7,%xmm8,%xmm8 +vpmuludq %xmm9,%xmm10,%xmm7 +vmovdqa %xmm9,672(%rsp) +vpaddq %xmm9,%xmm9,%xmm9 +vpmuludq %xmm3,%xmm12,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vmovdqa %xmm3,688(%rsp) +vpmuludq v19_19(%rip),%xmm12,%xmm12 +vpmuludq %xmm9,%xmm12,%xmm3 +vmovdqa %xmm9,704(%rsp) +vpaddq %xmm3,%xmm11,%xmm11 +vmovdqa 0(%rsp),%xmm3 +vmovdqa 16(%rsp),%xmm9 +vpaddq subc2(%rip),%xmm3,%xmm10 +vpsubq %xmm9,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm10,%xmm3,%xmm9 +vpunpcklqdq %xmm10,%xmm3,%xmm3 +vpmuludq 144(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpmuludq 128(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm2,%xmm2 +vpmuludq 480(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpmuludq 464(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm4,%xmm4 +vpmuludq 528(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpmuludq 512(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm5,%xmm5 +vpmuludq 592(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpmuludq 576(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vpmuludq 624(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpmuludq 672(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 144(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 448(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm1,%xmm1 +vpmuludq 480(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 496(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 528(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 544(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpmuludq 592(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm9,%xmm9 +vpmuludq 640(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 624(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 704(%rsp),%xmm9,%xmm9 +vpaddq %xmm9,%xmm0,%xmm0 +vmovdqa 32(%rsp),%xmm3 +vmovdqa 80(%rsp),%xmm9 +vpaddq subc2(%rip),%xmm3,%xmm10 +vpsubq %xmm9,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm10,%xmm3,%xmm9 +vpunpcklqdq %xmm10,%xmm3,%xmm3 +vpmuludq 144(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpmuludq 128(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm4,%xmm4 +vpmuludq 480(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpmuludq 464(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm5,%xmm5 +vpmuludq 528(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpmuludq 512(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vpmuludq 592(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpmuludq 576(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm13,%xmm13 +vpmuludq 624(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpmuludq 672(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 144(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 448(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 480(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 496(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpmuludq 528(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm9,%xmm9 +vpmuludq 544(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 592(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 640(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm0,%xmm0 +vpmuludq 624(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 704(%rsp),%xmm9,%xmm9 +vpaddq %xmm9,%xmm1,%xmm1 +vmovdqa 48(%rsp),%xmm3 +vmovdqa 96(%rsp),%xmm9 +vpaddq subc2(%rip),%xmm3,%xmm10 +vpsubq %xmm9,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm10,%xmm3,%xmm9 +vpunpcklqdq %xmm10,%xmm3,%xmm3 +vpmuludq 144(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpmuludq 128(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm5,%xmm5 +vpmuludq 480(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpmuludq 464(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vpmuludq 528(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpmuludq 512(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm13,%xmm13 +vpmuludq 592(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpmuludq 576(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm2,%xmm2 +vpmuludq 624(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpmuludq 672(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 144(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 448(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpmuludq 480(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm9,%xmm9 +vpmuludq 496(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 528(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 544(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm0,%xmm0 +vpmuludq 592(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 640(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm1,%xmm1 +vpmuludq 624(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 704(%rsp),%xmm9,%xmm9 +vpaddq %xmm9,%xmm6,%xmm6 +vmovdqa 64(%rsp),%xmm3 +vmovdqa 112(%rsp),%xmm9 +vpaddq subc2(%rip),%xmm3,%xmm10 +vpsubq %xmm9,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm10,%xmm3,%xmm9 +vpunpcklqdq %xmm10,%xmm3,%xmm3 +vpmuludq 144(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpmuludq 128(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vpmuludq 480(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpmuludq 464(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm13,%xmm13 +vpmuludq 528(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpmuludq 512(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm2,%xmm2 +vpmuludq 592(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpmuludq 576(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm4,%xmm4 +vpmuludq 624(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpmuludq 672(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 144(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm9,%xmm9 +vpmuludq 448(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 480(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 496(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm0,%xmm0 +vpmuludq 528(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 544(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm1,%xmm1 +vpmuludq 592(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 640(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 624(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 704(%rsp),%xmm9,%xmm9 +vpaddq %xmm9,%xmm8,%xmm8 +vpsrlq $25,%xmm4,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpand m25(%rip),%xmm4,%xmm4 +vpsrlq $26,%xmm11,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpand m26(%rip),%xmm11,%xmm11 +vpsrlq $26,%xmm6,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpand m26(%rip),%xmm6,%xmm6 +vpsrlq $25,%xmm13,%xmm3 +vpaddq %xmm3,%xmm0,%xmm0 +vpand m25(%rip),%xmm13,%xmm13 +vpsrlq $25,%xmm5,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpand m25(%rip),%xmm5,%xmm5 +vpsrlq $26,%xmm0,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpand m26(%rip),%xmm0,%xmm0 +vpsrlq $26,%xmm8,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpand m26(%rip),%xmm8,%xmm8 +vpsrlq $25,%xmm2,%xmm3 +vpaddq %xmm3,%xmm1,%xmm1 +vpand m25(%rip),%xmm2,%xmm2 +vpsrlq $25,%xmm7,%xmm3 +vpsllq $4,%xmm3,%xmm9 +vpaddq %xmm3,%xmm11,%xmm11 +vpsllq $1,%xmm3,%xmm3 +vpaddq %xmm3,%xmm9,%xmm9 +vpaddq %xmm9,%xmm11,%xmm11 +vpand m25(%rip),%xmm7,%xmm7 +vpsrlq $26,%xmm1,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpand m26(%rip),%xmm1,%xmm1 +vpsrlq $26,%xmm11,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpand m26(%rip),%xmm11,%xmm11 +vpsrlq $25,%xmm4,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpand m25(%rip),%xmm4,%xmm4 +vpunpcklqdq %xmm13,%xmm11,%xmm3 +vpunpckhqdq %xmm13,%xmm11,%xmm9 +vpaddq subc0(%rip),%xmm9,%xmm10 +vpsubq %xmm3,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm3,%xmm10,%xmm9 +vpunpcklqdq %xmm3,%xmm10,%xmm10 +vpmuludq %xmm10,%xmm10,%xmm3 +vpaddq %xmm10,%xmm10,%xmm10 +vpmuludq %xmm9,%xmm10,%xmm11 +vpunpcklqdq %xmm2,%xmm0,%xmm12 +vpunpckhqdq %xmm2,%xmm0,%xmm0 +vpaddq subc2(%rip),%xmm0,%xmm2 +vpsubq %xmm12,%xmm2,%xmm2 +vpaddq %xmm0,%xmm12,%xmm12 +vpunpckhqdq %xmm12,%xmm2,%xmm0 +vpunpcklqdq %xmm12,%xmm2,%xmm2 +vpmuludq %xmm2,%xmm10,%xmm12 +vpaddq %xmm9,%xmm9,%xmm13 +vpmuludq %xmm13,%xmm9,%xmm9 +vpaddq %xmm9,%xmm12,%xmm12 +vpmuludq %xmm0,%xmm10,%xmm9 +vpmuludq %xmm2,%xmm13,%xmm14 +vpaddq %xmm14,%xmm9,%xmm9 +vpunpcklqdq %xmm4,%xmm1,%xmm14 +vpunpckhqdq %xmm4,%xmm1,%xmm1 +vpaddq subc2(%rip),%xmm1,%xmm4 +vpsubq %xmm14,%xmm4,%xmm4 +vpaddq %xmm1,%xmm14,%xmm14 +vpunpckhqdq %xmm14,%xmm4,%xmm1 +vpunpcklqdq %xmm14,%xmm4,%xmm4 +vmovdqa %xmm1,0(%rsp) +vpaddq %xmm1,%xmm1,%xmm1 +vmovdqa %xmm1,16(%rsp) +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vmovdqa %xmm1,32(%rsp) +vpmuludq %xmm4,%xmm10,%xmm1 +vpmuludq %xmm2,%xmm2,%xmm14 +vpaddq %xmm14,%xmm1,%xmm1 +vpmuludq 0(%rsp),%xmm10,%xmm14 +vpmuludq %xmm4,%xmm13,%xmm15 +vpaddq %xmm15,%xmm14,%xmm14 +vpunpcklqdq %xmm5,%xmm6,%xmm15 +vpunpckhqdq %xmm5,%xmm6,%xmm5 +vpaddq subc2(%rip),%xmm5,%xmm6 +vpsubq %xmm15,%xmm6,%xmm6 +vpaddq %xmm5,%xmm15,%xmm15 +vpunpckhqdq %xmm15,%xmm6,%xmm5 +vpunpcklqdq %xmm15,%xmm6,%xmm6 +vmovdqa %xmm6,48(%rsp) +vpmuludq v19_19(%rip),%xmm6,%xmm6 +vmovdqa %xmm6,64(%rsp) +vmovdqa %xmm5,80(%rsp) +vpmuludq v38_38(%rip),%xmm5,%xmm5 +vmovdqa %xmm5,96(%rsp) +vpmuludq 48(%rsp),%xmm10,%xmm5 +vpaddq %xmm0,%xmm0,%xmm6 +vpmuludq %xmm6,%xmm0,%xmm0 +vpaddq %xmm0,%xmm5,%xmm5 +vpmuludq 80(%rsp),%xmm10,%xmm0 +vpmuludq %xmm4,%xmm6,%xmm15 +vpaddq %xmm15,%xmm0,%xmm0 +vpmuludq %xmm6,%xmm13,%xmm15 +vpaddq %xmm15,%xmm1,%xmm1 +vpmuludq %xmm6,%xmm2,%xmm15 +vpaddq %xmm15,%xmm14,%xmm14 +vpunpcklqdq %xmm7,%xmm8,%xmm15 +vpunpckhqdq %xmm7,%xmm8,%xmm7 +vpaddq subc2(%rip),%xmm7,%xmm8 +vpsubq %xmm15,%xmm8,%xmm8 +vpaddq %xmm7,%xmm15,%xmm15 +vpunpckhqdq %xmm15,%xmm8,%xmm7 +vpunpcklqdq %xmm15,%xmm8,%xmm8 +vmovdqa %xmm8,112(%rsp) +vpmuludq v19_19(%rip),%xmm8,%xmm8 +vmovdqa %xmm8,448(%rsp) +vpmuludq 112(%rsp),%xmm10,%xmm8 +vpmuludq %xmm7,%xmm10,%xmm10 +vpmuludq v38_38(%rip),%xmm7,%xmm15 +vpmuludq %xmm15,%xmm7,%xmm7 +vpaddq %xmm7,%xmm8,%xmm8 +vpmuludq %xmm15,%xmm13,%xmm7 +vpaddq %xmm7,%xmm3,%xmm3 +vpmuludq %xmm15,%xmm2,%xmm7 +vpaddq %xmm7,%xmm11,%xmm11 +vpmuludq 80(%rsp),%xmm13,%xmm7 +vpaddq %xmm7,%xmm7,%xmm7 +vpaddq %xmm7,%xmm8,%xmm8 +vpmuludq 16(%rsp),%xmm13,%xmm7 +vpaddq %xmm7,%xmm5,%xmm5 +vpmuludq 48(%rsp),%xmm13,%xmm7 +vpaddq %xmm7,%xmm0,%xmm0 +vpmuludq 112(%rsp),%xmm13,%xmm7 +vpaddq %xmm7,%xmm10,%xmm10 +vpmuludq %xmm15,%xmm6,%xmm7 +vpaddq %xmm7,%xmm12,%xmm12 +vpmuludq %xmm15,%xmm4,%xmm7 +vpaddq %xmm7,%xmm9,%xmm9 +vpaddq %xmm2,%xmm2,%xmm2 +vpmuludq %xmm4,%xmm2,%xmm7 +vpaddq %xmm7,%xmm5,%xmm5 +vpmuludq 448(%rsp),%xmm2,%xmm7 +vpaddq %xmm7,%xmm3,%xmm3 +vpmuludq 448(%rsp),%xmm6,%xmm7 +vpaddq %xmm7,%xmm11,%xmm11 +vpmuludq 0(%rsp),%xmm2,%xmm7 +vpaddq %xmm7,%xmm0,%xmm0 +vpmuludq 48(%rsp),%xmm2,%xmm7 +vpaddq %xmm7,%xmm8,%xmm8 +vpmuludq 80(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 96(%rsp),%xmm4,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq %xmm4,%xmm4,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpaddq %xmm4,%xmm4,%xmm2 +vpmuludq 448(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm12,%xmm12 +vpmuludq 16(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vpmuludq 48(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm14,%xmm14 +vpmuludq 96(%rsp),%xmm6,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vmovdqa 16(%rsp),%xmm4 +vpmuludq 448(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm9,%xmm9 +vpmuludq 16(%rsp),%xmm6,%xmm4 +vpaddq %xmm4,%xmm8,%xmm8 +vpmuludq 48(%rsp),%xmm6,%xmm4 +vpaddq %xmm4,%xmm10,%xmm10 +vpmuludq 80(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm4,%xmm4 +vpaddq %xmm4,%xmm5,%xmm5 +vpmuludq 112(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm0,%xmm0 +vmovdqa 48(%rsp),%xmm4 +vpaddq %xmm4,%xmm4,%xmm4 +vpmuludq 448(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vmovdqa 80(%rsp),%xmm4 +vpaddq %xmm4,%xmm4,%xmm4 +vpmuludq 448(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm14,%xmm14 +vpmuludq 64(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vmovdqa 16(%rsp),%xmm4 +vpmuludq 64(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm11,%xmm11 +vmovdqa 16(%rsp),%xmm4 +vpmuludq 96(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm12,%xmm12 +vmovdqa 48(%rsp),%xmm4 +vpmuludq 96(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm9,%xmm9 +vpmuludq 0(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vmovdqa 32(%rsp),%xmm2 +vpmuludq 0(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vmovdqa 64(%rsp),%xmm2 +vpmuludq 48(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vmovdqa 96(%rsp),%xmm2 +vpmuludq 80(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm1,%xmm1 +vmovdqa 448(%rsp),%xmm2 +vpmuludq 112(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpsrlq $26,%xmm3,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpand m26(%rip),%xmm3,%xmm3 +vpsrlq $25,%xmm14,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpand m25(%rip),%xmm14,%xmm14 +vpsrlq $25,%xmm11,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpand m25(%rip),%xmm11,%xmm11 +vpsrlq $26,%xmm5,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpand m26(%rip),%xmm5,%xmm5 +vpsrlq $26,%xmm12,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpand m26(%rip),%xmm12,%xmm12 +vpsrlq $25,%xmm0,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpand m25(%rip),%xmm0,%xmm0 +vpsrlq $25,%xmm9,%xmm2 +vpaddq %xmm2,%xmm1,%xmm1 +vpand m25(%rip),%xmm9,%xmm9 +vpsrlq $26,%xmm8,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpand m26(%rip),%xmm8,%xmm8 +vpsrlq $26,%xmm1,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpand m26(%rip),%xmm1,%xmm1 +vpsrlq $25,%xmm10,%xmm2 +vpsllq $4,%xmm2,%xmm4 +vpaddq %xmm2,%xmm3,%xmm3 +vpsllq $1,%xmm2,%xmm2 +vpaddq %xmm2,%xmm4,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $25,%xmm14,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpand m25(%rip),%xmm14,%xmm14 +vpsrlq $26,%xmm3,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpand m26(%rip),%xmm3,%xmm3 +vpunpckhqdq %xmm11,%xmm3,%xmm2 +vmovdqa %xmm2,0(%rsp) +vpshufd $0,%xmm3,%xmm2 +vpshufd $0,%xmm11,%xmm3 +vpmuludq 160(%rsp),%xmm2,%xmm4 +vpmuludq 432(%rsp),%xmm3,%xmm6 +vpaddq %xmm6,%xmm4,%xmm4 +vpmuludq 176(%rsp),%xmm2,%xmm6 +vpmuludq 304(%rsp),%xmm3,%xmm7 +vpaddq %xmm7,%xmm6,%xmm6 +vpmuludq 208(%rsp),%xmm2,%xmm7 +vpmuludq 336(%rsp),%xmm3,%xmm11 +vpaddq %xmm11,%xmm7,%xmm7 +vpmuludq 240(%rsp),%xmm2,%xmm11 +vpmuludq 368(%rsp),%xmm3,%xmm13 +vpaddq %xmm13,%xmm11,%xmm11 +vpmuludq 272(%rsp),%xmm2,%xmm2 +vpmuludq 400(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpunpckhqdq %xmm9,%xmm12,%xmm3 +vmovdqa %xmm3,16(%rsp) +vpshufd $0,%xmm12,%xmm3 +vpshufd $0,%xmm9,%xmm9 +vpmuludq 288(%rsp),%xmm3,%xmm12 +vpaddq %xmm12,%xmm4,%xmm4 +vpmuludq 416(%rsp),%xmm9,%xmm12 +vpaddq %xmm12,%xmm4,%xmm4 +vpmuludq 160(%rsp),%xmm3,%xmm12 +vpaddq %xmm12,%xmm6,%xmm6 +vpmuludq 432(%rsp),%xmm9,%xmm12 +vpaddq %xmm12,%xmm6,%xmm6 +vpmuludq 176(%rsp),%xmm3,%xmm12 +vpaddq %xmm12,%xmm7,%xmm7 +vpmuludq 304(%rsp),%xmm9,%xmm12 +vpaddq %xmm12,%xmm7,%xmm7 +vpmuludq 208(%rsp),%xmm3,%xmm12 +vpaddq %xmm12,%xmm11,%xmm11 +vpmuludq 336(%rsp),%xmm9,%xmm12 +vpaddq %xmm12,%xmm11,%xmm11 +vpmuludq 240(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 368(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpunpckhqdq %xmm14,%xmm1,%xmm3 +vmovdqa %xmm3,32(%rsp) +vpshufd $0,%xmm1,%xmm1 +vpshufd $0,%xmm14,%xmm3 +vpmuludq 256(%rsp),%xmm1,%xmm9 +vpaddq %xmm9,%xmm4,%xmm4 +vpmuludq 384(%rsp),%xmm3,%xmm9 +vpaddq %xmm9,%xmm4,%xmm4 +vpmuludq 288(%rsp),%xmm1,%xmm9 +vpaddq %xmm9,%xmm6,%xmm6 +vpmuludq 416(%rsp),%xmm3,%xmm9 +vpaddq %xmm9,%xmm6,%xmm6 +vpmuludq 160(%rsp),%xmm1,%xmm9 +vpaddq %xmm9,%xmm7,%xmm7 +vpmuludq 432(%rsp),%xmm3,%xmm9 +vpaddq %xmm9,%xmm7,%xmm7 +vpmuludq 176(%rsp),%xmm1,%xmm9 +vpaddq %xmm9,%xmm11,%xmm11 +vpmuludq 304(%rsp),%xmm3,%xmm9 +vpaddq %xmm9,%xmm11,%xmm11 +vpmuludq 208(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm2,%xmm2 +vpmuludq 336(%rsp),%xmm3,%xmm1 +vpaddq %xmm1,%xmm2,%xmm2 +vpunpckhqdq %xmm0,%xmm5,%xmm1 +vmovdqa %xmm1,48(%rsp) +vpshufd $0,%xmm5,%xmm1 +vpshufd $0,%xmm0,%xmm0 +vpmuludq 224(%rsp),%xmm1,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 352(%rsp),%xmm0,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 256(%rsp),%xmm1,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 384(%rsp),%xmm0,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 288(%rsp),%xmm1,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq 416(%rsp),%xmm0,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq 160(%rsp),%xmm1,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 432(%rsp),%xmm0,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 176(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm2,%xmm2 +vpmuludq 304(%rsp),%xmm0,%xmm0 +vpaddq %xmm0,%xmm2,%xmm2 +vpunpckhqdq %xmm10,%xmm8,%xmm0 +vmovdqa %xmm0,64(%rsp) +vpshufd $0,%xmm8,%xmm0 +vpshufd $0,%xmm10,%xmm1 +vpmuludq 192(%rsp),%xmm0,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 320(%rsp),%xmm1,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 224(%rsp),%xmm0,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 352(%rsp),%xmm1,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 256(%rsp),%xmm0,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq 384(%rsp),%xmm1,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq 288(%rsp),%xmm0,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 416(%rsp),%xmm1,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 160(%rsp),%xmm0,%xmm0 +vpaddq %xmm0,%xmm2,%xmm2 +vpmuludq 432(%rsp),%xmm1,%xmm0 +vpaddq %xmm0,%xmm2,%xmm2 +vmovdqa %xmm4,80(%rsp) +vmovdqa %xmm6,96(%rsp) +vmovdqa %xmm7,112(%rsp) +vmovdqa %xmm11,448(%rsp) +vmovdqa %xmm2,496(%rsp) +vmovdqa 144(%rsp),%xmm0 +vpmuludq %xmm0,%xmm0,%xmm1 +vpaddq %xmm0,%xmm0,%xmm0 +vmovdqa 128(%rsp),%xmm2 +vpmuludq %xmm2,%xmm0,%xmm3 +vmovdqa 480(%rsp),%xmm4 +vpmuludq %xmm4,%xmm0,%xmm5 +vmovdqa 464(%rsp),%xmm6 +vpmuludq %xmm6,%xmm0,%xmm7 +vmovdqa 528(%rsp),%xmm8 +vpmuludq %xmm8,%xmm0,%xmm9 +vpmuludq 512(%rsp),%xmm0,%xmm10 +vpmuludq 592(%rsp),%xmm0,%xmm11 +vpmuludq 576(%rsp),%xmm0,%xmm12 +vpmuludq 624(%rsp),%xmm0,%xmm13 +vmovdqa 672(%rsp),%xmm14 +vpmuludq %xmm14,%xmm0,%xmm0 +vpmuludq v38_38(%rip),%xmm14,%xmm15 +vpmuludq %xmm15,%xmm14,%xmm14 +vpaddq %xmm14,%xmm13,%xmm13 +vpaddq %xmm6,%xmm6,%xmm14 +vpmuludq %xmm14,%xmm6,%xmm6 +vpaddq %xmm6,%xmm11,%xmm11 +vpaddq %xmm2,%xmm2,%xmm6 +vpmuludq %xmm6,%xmm2,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq %xmm15,%xmm6,%xmm2 +vpaddq %xmm2,%xmm1,%xmm1 +vpmuludq %xmm15,%xmm4,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vpmuludq 544(%rsp),%xmm6,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq 592(%rsp),%xmm6,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 640(%rsp),%xmm6,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 624(%rsp),%xmm6,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpmuludq %xmm4,%xmm6,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq %xmm14,%xmm6,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq %xmm8,%xmm6,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq %xmm15,%xmm14,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq %xmm15,%xmm8,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq %xmm4,%xmm4,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq %xmm14,%xmm4,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpaddq %xmm4,%xmm4,%xmm2 +vpmuludq %xmm8,%xmm2,%xmm4 +vpaddq %xmm4,%xmm11,%xmm11 +vpmuludq 688(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vpmuludq 688(%rsp),%xmm14,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vpmuludq 512(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm12,%xmm12 +vpmuludq 592(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm13,%xmm13 +vpmuludq 576(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpmuludq 656(%rsp),%xmm8,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vpmuludq %xmm8,%xmm14,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq %xmm8,%xmm8,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpaddq %xmm8,%xmm8,%xmm2 +vpmuludq 688(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm5,%xmm5 +vpmuludq 544(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm9,%xmm9 +vpmuludq 592(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm10,%xmm10 +vpmuludq 656(%rsp),%xmm14,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vmovdqa 544(%rsp),%xmm4 +vpmuludq 688(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm7,%xmm7 +vpmuludq 544(%rsp),%xmm14,%xmm4 +vpaddq %xmm4,%xmm13,%xmm13 +vpmuludq 592(%rsp),%xmm14,%xmm4 +vpaddq %xmm4,%xmm0,%xmm0 +vpmuludq 640(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm11,%xmm11 +vpmuludq 624(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm12,%xmm12 +vmovdqa 592(%rsp),%xmm4 +vpaddq %xmm4,%xmm4,%xmm4 +vpmuludq 688(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm9,%xmm9 +vpmuludq 608(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vmovdqa 544(%rsp),%xmm4 +vpmuludq 608(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vmovdqa 544(%rsp),%xmm4 +vpmuludq 656(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm5,%xmm5 +vmovdqa 592(%rsp),%xmm4 +vpmuludq 656(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm7,%xmm7 +vmovdqa 640(%rsp),%xmm4 +vpmuludq 688(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm10,%xmm10 +vpmuludq 512(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vmovdqa 560(%rsp),%xmm2 +vpmuludq 512(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm1,%xmm1 +vmovdqa 608(%rsp),%xmm2 +vpmuludq 592(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vmovdqa 656(%rsp),%xmm2 +vpmuludq 576(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vmovdqa 688(%rsp),%xmm2 +vpmuludq 624(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpsrlq $26,%xmm1,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vpand m26(%rip),%xmm1,%xmm1 +vpsrlq $25,%xmm10,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $25,%xmm3,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpand m25(%rip),%xmm3,%xmm3 +vpsrlq $26,%xmm11,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpand m26(%rip),%xmm11,%xmm11 +vpsrlq $26,%xmm5,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpand m26(%rip),%xmm5,%xmm5 +vpsrlq $25,%xmm12,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpand m25(%rip),%xmm12,%xmm12 +vpsrlq $25,%xmm7,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpand m25(%rip),%xmm7,%xmm7 +vpsrlq $26,%xmm13,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpand m26(%rip),%xmm13,%xmm13 +vpsrlq $26,%xmm9,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpand m26(%rip),%xmm9,%xmm9 +vpsrlq $25,%xmm0,%xmm2 +vpsllq $4,%xmm2,%xmm4 +vpaddq %xmm2,%xmm1,%xmm1 +vpsllq $1,%xmm2,%xmm2 +vpaddq %xmm2,%xmm4,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vpand m25(%rip),%xmm0,%xmm0 +vpsrlq $25,%xmm10,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $26,%xmm1,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vpand m26(%rip),%xmm1,%xmm1 +vpunpckhqdq %xmm3,%xmm1,%xmm2 +vpunpcklqdq %xmm3,%xmm1,%xmm1 +vmovdqa %xmm1,464(%rsp) +vpaddq subc0(%rip),%xmm2,%xmm3 +vpsubq %xmm1,%xmm3,%xmm3 +vpunpckhqdq %xmm3,%xmm2,%xmm1 +vpunpcklqdq %xmm3,%xmm2,%xmm2 +vmovdqa %xmm2,480(%rsp) +vmovdqa %xmm1,512(%rsp) +vpsllq $1,%xmm1,%xmm1 +vmovdqa %xmm1,528(%rsp) +vpmuludq v121666_121666(%rip),%xmm3,%xmm3 +vmovdqa 80(%rsp),%xmm1 +vpunpcklqdq %xmm1,%xmm3,%xmm2 +vpunpckhqdq %xmm1,%xmm3,%xmm1 +vpunpckhqdq %xmm7,%xmm5,%xmm3 +vpunpcklqdq %xmm7,%xmm5,%xmm4 +vmovdqa %xmm4,544(%rsp) +vpaddq subc2(%rip),%xmm3,%xmm5 +vpsubq %xmm4,%xmm5,%xmm5 +vpunpckhqdq %xmm5,%xmm3,%xmm4 +vpunpcklqdq %xmm5,%xmm3,%xmm3 +vmovdqa %xmm3,560(%rsp) +vmovdqa %xmm4,576(%rsp) +vpsllq $1,%xmm4,%xmm4 +vmovdqa %xmm4,592(%rsp) +vpmuludq v121666_121666(%rip),%xmm5,%xmm5 +vmovdqa 96(%rsp),%xmm3 +vpunpcklqdq %xmm3,%xmm5,%xmm4 +vpunpckhqdq %xmm3,%xmm5,%xmm3 +vpunpckhqdq %xmm10,%xmm9,%xmm5 +vpunpcklqdq %xmm10,%xmm9,%xmm6 +vmovdqa %xmm6,608(%rsp) +vpaddq subc2(%rip),%xmm5,%xmm7 +vpsubq %xmm6,%xmm7,%xmm7 +vpunpckhqdq %xmm7,%xmm5,%xmm6 +vpunpcklqdq %xmm7,%xmm5,%xmm5 +vmovdqa %xmm5,624(%rsp) +vmovdqa %xmm6,640(%rsp) +vpsllq $1,%xmm6,%xmm6 +vmovdqa %xmm6,656(%rsp) +vpmuludq v121666_121666(%rip),%xmm7,%xmm7 +vmovdqa 112(%rsp),%xmm5 +vpunpcklqdq %xmm5,%xmm7,%xmm6 +vpunpckhqdq %xmm5,%xmm7,%xmm5 +vpunpckhqdq %xmm12,%xmm11,%xmm7 +vpunpcklqdq %xmm12,%xmm11,%xmm8 +vmovdqa %xmm8,672(%rsp) +vpaddq subc2(%rip),%xmm7,%xmm9 +vpsubq %xmm8,%xmm9,%xmm9 +vpunpckhqdq %xmm9,%xmm7,%xmm8 +vpunpcklqdq %xmm9,%xmm7,%xmm7 +vmovdqa %xmm7,688(%rsp) +vmovdqa %xmm8,704(%rsp) +vpsllq $1,%xmm8,%xmm8 +vmovdqa %xmm8,720(%rsp) +vpmuludq v121666_121666(%rip),%xmm9,%xmm9 +vmovdqa 448(%rsp),%xmm7 +vpunpcklqdq %xmm7,%xmm9,%xmm8 +vpunpckhqdq %xmm7,%xmm9,%xmm7 +vpunpckhqdq %xmm0,%xmm13,%xmm9 +vpunpcklqdq %xmm0,%xmm13,%xmm0 +vmovdqa %xmm0,448(%rsp) +vpaddq subc2(%rip),%xmm9,%xmm10 +vpsubq %xmm0,%xmm10,%xmm10 +vpunpckhqdq %xmm10,%xmm9,%xmm0 +vpunpcklqdq %xmm10,%xmm9,%xmm9 +vmovdqa %xmm9,736(%rsp) +vmovdqa %xmm0,752(%rsp) +vpsllq $1,%xmm0,%xmm0 +vmovdqa %xmm0,768(%rsp) +vpmuludq v121666_121666(%rip),%xmm10,%xmm10 +vmovdqa 496(%rsp),%xmm0 +vpunpcklqdq %xmm0,%xmm10,%xmm9 +vpunpckhqdq %xmm0,%xmm10,%xmm0 +vpsrlq $26,%xmm2,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpand m26(%rip),%xmm2,%xmm2 +vpsrlq $25,%xmm5,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpand m25(%rip),%xmm5,%xmm5 +vpsrlq $25,%xmm1,%xmm10 +vpaddq %xmm10,%xmm4,%xmm4 +vpand m25(%rip),%xmm1,%xmm1 +vpsrlq $26,%xmm8,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpand m26(%rip),%xmm8,%xmm8 +vpsrlq $26,%xmm4,%xmm10 +vpaddq %xmm10,%xmm3,%xmm3 +vpand m26(%rip),%xmm4,%xmm4 +vpsrlq $25,%xmm7,%xmm10 +vpaddq %xmm10,%xmm9,%xmm9 +vpand m25(%rip),%xmm7,%xmm7 +vpsrlq $25,%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpand m25(%rip),%xmm3,%xmm3 +vpsrlq $26,%xmm9,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpand m26(%rip),%xmm9,%xmm9 +vpsrlq $26,%xmm6,%xmm10 +vpaddq %xmm10,%xmm5,%xmm5 +vpand m26(%rip),%xmm6,%xmm6 +vpsrlq $25,%xmm0,%xmm10 +vpsllq $4,%xmm10,%xmm11 +vpaddq %xmm10,%xmm2,%xmm2 +vpsllq $1,%xmm10,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpaddq %xmm11,%xmm2,%xmm2 +vpand m25(%rip),%xmm0,%xmm0 +vpsrlq $25,%xmm5,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpand m25(%rip),%xmm5,%xmm5 +vpsrlq $26,%xmm2,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpand m26(%rip),%xmm2,%xmm2 +vpunpckhqdq %xmm1,%xmm2,%xmm10 +vmovdqa %xmm10,80(%rsp) +vpunpcklqdq %xmm1,%xmm2,%xmm1 +vpunpckhqdq %xmm3,%xmm4,%xmm2 +vmovdqa %xmm2,96(%rsp) +vpunpcklqdq %xmm3,%xmm4,%xmm2 +vpunpckhqdq %xmm5,%xmm6,%xmm3 +vmovdqa %xmm3,112(%rsp) +vpunpcklqdq %xmm5,%xmm6,%xmm3 +vpunpckhqdq %xmm7,%xmm8,%xmm4 +vmovdqa %xmm4,128(%rsp) +vpunpcklqdq %xmm7,%xmm8,%xmm4 +vpunpckhqdq %xmm0,%xmm9,%xmm5 +vmovdqa %xmm5,144(%rsp) +vpunpcklqdq %xmm0,%xmm9,%xmm0 +vmovdqa 464(%rsp),%xmm5 +vpaddq %xmm5,%xmm1,%xmm1 +vpunpcklqdq %xmm1,%xmm5,%xmm6 +vpunpckhqdq %xmm1,%xmm5,%xmm1 +vpmuludq 512(%rsp),%xmm6,%xmm5 +vpmuludq 480(%rsp),%xmm1,%xmm7 +vpaddq %xmm7,%xmm5,%xmm5 +vpmuludq 560(%rsp),%xmm6,%xmm7 +vpmuludq 528(%rsp),%xmm1,%xmm8 +vpaddq %xmm8,%xmm7,%xmm7 +vpmuludq 576(%rsp),%xmm6,%xmm8 +vpmuludq 560(%rsp),%xmm1,%xmm9 +vpaddq %xmm9,%xmm8,%xmm8 +vpmuludq 624(%rsp),%xmm6,%xmm9 +vpmuludq 592(%rsp),%xmm1,%xmm10 +vpaddq %xmm10,%xmm9,%xmm9 +vpmuludq 640(%rsp),%xmm6,%xmm10 +vpmuludq 624(%rsp),%xmm1,%xmm11 +vpaddq %xmm11,%xmm10,%xmm10 +vpmuludq 688(%rsp),%xmm6,%xmm11 +vpmuludq 656(%rsp),%xmm1,%xmm12 +vpaddq %xmm12,%xmm11,%xmm11 +vpmuludq 704(%rsp),%xmm6,%xmm12 +vpmuludq 688(%rsp),%xmm1,%xmm13 +vpaddq %xmm13,%xmm12,%xmm12 +vpmuludq 736(%rsp),%xmm6,%xmm13 +vpmuludq 720(%rsp),%xmm1,%xmm14 +vpaddq %xmm14,%xmm13,%xmm13 +vpmuludq 752(%rsp),%xmm6,%xmm14 +vpmuludq 736(%rsp),%xmm1,%xmm15 +vpaddq %xmm15,%xmm14,%xmm14 +vpmuludq 480(%rsp),%xmm6,%xmm6 +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vpmuludq 768(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm6,%xmm6 +vmovdqa 544(%rsp),%xmm1 +vpaddq %xmm1,%xmm2,%xmm2 +vpunpcklqdq %xmm2,%xmm1,%xmm15 +vpunpckhqdq %xmm2,%xmm1,%xmm1 +vpmuludq 480(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq 512(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 560(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq 576(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 624(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq 640(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 688(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 704(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm15,%xmm15 +vpmuludq 736(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm6,%xmm6 +vpmuludq 752(%rsp),%xmm15,%xmm15 +vpaddq %xmm15,%xmm5,%xmm5 +vpmuludq 480(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 528(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq 560(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 592(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq 624(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 656(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 688(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vpmuludq 720(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm6,%xmm6 +vpmuludq 736(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq 768(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm7,%xmm7 +vmovdqa 608(%rsp),%xmm1 +vpaddq %xmm1,%xmm3,%xmm3 +vpunpcklqdq %xmm3,%xmm1,%xmm2 +vpunpckhqdq %xmm3,%xmm1,%xmm1 +vpmuludq 480(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm9,%xmm9 +vpmuludq 512(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm10,%xmm10 +vpmuludq 560(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 576(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm12,%xmm12 +vpmuludq 624(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 640(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm2,%xmm2 +vpmuludq 688(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 704(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 736(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq 752(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 480(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 528(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq 560(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 592(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 624(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vpmuludq 656(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm6,%xmm6 +vpmuludq 688(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq 720(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq 736(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 768(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm9,%xmm9 +vmovdqa 672(%rsp),%xmm1 +vpaddq %xmm1,%xmm4,%xmm4 +vpunpcklqdq %xmm4,%xmm1,%xmm2 +vpunpckhqdq %xmm4,%xmm1,%xmm1 +vpmuludq 480(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 512(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm12,%xmm12 +vpmuludq 560(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 576(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm2,%xmm2 +vpmuludq 624(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 640(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 688(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq 704(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpmuludq 736(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm9,%xmm9 +vpmuludq 752(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 480(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 528(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 560(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vpmuludq 592(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm6,%xmm6 +vpmuludq 624(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq 656(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq 688(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 720(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq 736(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 768(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm11,%xmm11 +vmovdqa 448(%rsp),%xmm1 +vpaddq %xmm1,%xmm0,%xmm0 +vpunpcklqdq %xmm0,%xmm1,%xmm2 +vpunpckhqdq %xmm0,%xmm1,%xmm0 +vpmuludq 480(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm13,%xmm13 +vpmuludq 512(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm2,%xmm2 +vpmuludq 560(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm6,%xmm6 +vpmuludq 576(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm5,%xmm5 +vpmuludq 624(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm7,%xmm7 +vpmuludq 640(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm8,%xmm8 +vpmuludq 688(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm9,%xmm9 +vpmuludq 704(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm10,%xmm10 +vpmuludq 736(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm11,%xmm11 +vpmuludq 752(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 480(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm0,%xmm0 +vpmuludq 528(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm6,%xmm6 +vpmuludq 560(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm5,%xmm5 +vpmuludq 592(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm7,%xmm7 +vpmuludq 624(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm8,%xmm8 +vpmuludq 656(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm9,%xmm9 +vpmuludq 688(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm10,%xmm10 +vpmuludq 720(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm11,%xmm11 +vpmuludq 736(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm12,%xmm12 +vpmuludq 768(%rsp),%xmm0,%xmm0 +vpaddq %xmm0,%xmm13,%xmm13 +vpsrlq $26,%xmm6,%xmm0 +vpaddq %xmm0,%xmm5,%xmm5 +vpand m26(%rip),%xmm6,%xmm6 +vpsrlq $25,%xmm10,%xmm0 +vpaddq %xmm0,%xmm11,%xmm11 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $25,%xmm5,%xmm0 +vpaddq %xmm0,%xmm7,%xmm7 +vpand m25(%rip),%xmm5,%xmm5 +vpsrlq $26,%xmm11,%xmm0 +vpaddq %xmm0,%xmm12,%xmm12 +vpand m26(%rip),%xmm11,%xmm11 +vpsrlq $26,%xmm7,%xmm0 +vpaddq %xmm0,%xmm8,%xmm8 +vpand m26(%rip),%xmm7,%xmm7 +vpsrlq $25,%xmm12,%xmm0 +vpaddq %xmm0,%xmm13,%xmm13 +vpand m25(%rip),%xmm12,%xmm12 +vpsrlq $25,%xmm8,%xmm0 +vpaddq %xmm0,%xmm9,%xmm9 +vpand m25(%rip),%xmm8,%xmm8 +vpsrlq $26,%xmm13,%xmm0 +vpaddq %xmm0,%xmm14,%xmm14 +vpand m26(%rip),%xmm13,%xmm13 +vpsrlq $26,%xmm9,%xmm0 +vpaddq %xmm0,%xmm10,%xmm10 +vpand m26(%rip),%xmm9,%xmm9 +vpsrlq $25,%xmm14,%xmm0 +vpsllq $4,%xmm0,%xmm1 +vpaddq %xmm0,%xmm6,%xmm6 +vpsllq $1,%xmm0,%xmm0 +vpaddq %xmm0,%xmm1,%xmm1 +vpaddq %xmm1,%xmm6,%xmm6 +vpand m25(%rip),%xmm14,%xmm14 +vpsrlq $25,%xmm10,%xmm0 +vpaddq %xmm0,%xmm11,%xmm11 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $26,%xmm6,%xmm0 +vpaddq %xmm0,%xmm5,%xmm5 +vpand m26(%rip),%xmm6,%xmm6 +vpunpckhqdq %xmm5,%xmm6,%xmm1 +vpunpcklqdq %xmm5,%xmm6,%xmm0 +vpunpckhqdq %xmm8,%xmm7,%xmm3 +vpunpcklqdq %xmm8,%xmm7,%xmm2 +vpunpckhqdq %xmm10,%xmm9,%xmm5 +vpunpcklqdq %xmm10,%xmm9,%xmm4 +vpunpckhqdq %xmm12,%xmm11,%xmm7 +vpunpcklqdq %xmm12,%xmm11,%xmm6 +vpunpckhqdq %xmm14,%xmm13,%xmm9 +vpunpcklqdq %xmm14,%xmm13,%xmm8 +cmp $0,%rdx +jne ._ladder_loop +vmovdqu %xmm1,160(%rdi) +vmovdqu %xmm0,80(%rdi) +vmovdqu %xmm3,176(%rdi) +vmovdqu %xmm2,96(%rdi) +vmovdqu %xmm5,192(%rdi) +vmovdqu %xmm4,112(%rdi) +vmovdqu %xmm7,208(%rdi) +vmovdqu %xmm6,128(%rdi) +vmovdqu %xmm9,224(%rdi) +vmovdqu %xmm8,144(%rdi) +movq 1824(%rsp),%r11 +movq 1832(%rsp),%r12 +movq 1840(%rsp),%r13 +movq 1848(%rsp),%r14 +add %r11,%rsp +ret + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder.h b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder.h new file mode 100644 index 0000000000..ccf4ecaecd --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder.h @@ -0,0 +1,18 @@ +#ifndef ladder_H +#define ladder_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "fe.h" +#include "ladder_namespace.h" + +extern void ladder(fe *, const unsigned char *); + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef ladder_H */ + diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base.S b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base.S new file mode 100644 index 0000000000..f290d2565e --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base.S @@ -0,0 +1,1295 @@ +#ifdef IN_SANDY2X + +#include "ladder_base_namespace.h" +#include "consts_namespace.h" +.p2align 5 + +#ifdef ASM_HIDE_SYMBOL +ASM_HIDE_SYMBOL ladder_base +ASM_HIDE_SYMBOL _ladder_base +#endif +.globl ladder_base +.globl _ladder_base +#ifdef __ELF__ +.type ladder_base, @function +.type _ladder_base, @function +#endif +ladder_base: +_ladder_base: + +mov %rsp,%r11 +and $31,%r11 +add $1568,%r11 +sub %r11,%rsp +movq %r11,1536(%rsp) +movq %r12,1544(%rsp) +movq %r13,1552(%rsp) +vmovdqa v0_0(%rip),%xmm0 +vmovdqa v1_0(%rip),%xmm1 +vmovdqa v9_0(%rip),%xmm2 +vmovdqa %xmm2,0(%rsp) +vmovdqa %xmm0,16(%rsp) +vmovdqa %xmm0,32(%rsp) +vmovdqa %xmm0,48(%rsp) +vmovdqa %xmm0,64(%rsp) +vmovdqa %xmm1,80(%rsp) +vmovdqa %xmm0,96(%rsp) +vmovdqa %xmm0,112(%rsp) +vmovdqa %xmm0,128(%rsp) +vmovdqa %xmm0,144(%rsp) +vmovdqa %xmm1,%xmm0 +vpxor %xmm1,%xmm1,%xmm1 +vpxor %xmm2,%xmm2,%xmm2 +vpxor %xmm3,%xmm3,%xmm3 +vpxor %xmm4,%xmm4,%xmm4 +vpxor %xmm5,%xmm5,%xmm5 +vpxor %xmm6,%xmm6,%xmm6 +vpxor %xmm7,%xmm7,%xmm7 +vpxor %xmm8,%xmm8,%xmm8 +vpxor %xmm9,%xmm9,%xmm9 +movq 0(%rsi),%rdx +movq 8(%rsi),%rcx +movq 16(%rsi),%r8 +movq 24(%rsi),%r9 +shrd $1,%rcx,%rdx +shrd $1,%r8,%rcx +shrd $1,%r9,%r8 +shr $1,%r9 +xorq 0(%rsi),%rdx +xorq 8(%rsi),%rcx +xorq 16(%rsi),%r8 +xorq 24(%rsi),%r9 +leaq 512(%rsp),%rsi +mov $64,%rax + +.p2align 4 +._ladder_base_small_loop: +mov %rdx,%r10 +mov %rcx,%r11 +mov %r8,%r12 +mov %r9,%r13 +shr $1,%rdx +shr $1,%rcx +shr $1,%r8 +shr $1,%r9 +and $1,%r10d +and $1,%r11d +and $1,%r12d +and $1,%r13d +neg %r10 +neg %r11 +neg %r12 +neg %r13 +movl %r10d,0(%rsi) +movl %r11d,256(%rsi) +movl %r12d,512(%rsi) +movl %r13d,768(%rsi) +add $4,%rsi +sub $1,%rax +jne ._ladder_base_small_loop +mov $255,%rdx +add $760,%rsi + +.p2align 4 +._ladder_base_loop: +sub $1,%rdx +vbroadcastss 0(%rsi),%xmm10 +sub $4,%rsi +vmovdqa 0(%rsp),%xmm11 +vmovdqa 80(%rsp),%xmm12 +vpxor %xmm11,%xmm0,%xmm13 +vpand %xmm10,%xmm13,%xmm13 +vpxor %xmm13,%xmm0,%xmm0 +vpxor %xmm13,%xmm11,%xmm11 +vpxor %xmm12,%xmm1,%xmm13 +vpand %xmm10,%xmm13,%xmm13 +vpxor %xmm13,%xmm1,%xmm1 +vpxor %xmm13,%xmm12,%xmm12 +vmovdqa 16(%rsp),%xmm13 +vmovdqa 96(%rsp),%xmm14 +vpxor %xmm13,%xmm2,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm2,%xmm2 +vpxor %xmm15,%xmm13,%xmm13 +vpxor %xmm14,%xmm3,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm3,%xmm3 +vpxor %xmm15,%xmm14,%xmm14 +vmovdqa %xmm13,0(%rsp) +vmovdqa %xmm14,16(%rsp) +vmovdqa 32(%rsp),%xmm13 +vmovdqa 112(%rsp),%xmm14 +vpxor %xmm13,%xmm4,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm4,%xmm4 +vpxor %xmm15,%xmm13,%xmm13 +vpxor %xmm14,%xmm5,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm5,%xmm5 +vpxor %xmm15,%xmm14,%xmm14 +vmovdqa %xmm13,32(%rsp) +vmovdqa %xmm14,80(%rsp) +vmovdqa 48(%rsp),%xmm13 +vmovdqa 128(%rsp),%xmm14 +vpxor %xmm13,%xmm6,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm6,%xmm6 +vpxor %xmm15,%xmm13,%xmm13 +vpxor %xmm14,%xmm7,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm7,%xmm7 +vpxor %xmm15,%xmm14,%xmm14 +vmovdqa %xmm13,48(%rsp) +vmovdqa %xmm14,96(%rsp) +vmovdqa 64(%rsp),%xmm13 +vmovdqa 144(%rsp),%xmm14 +vpxor %xmm13,%xmm8,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm8,%xmm8 +vpxor %xmm15,%xmm13,%xmm13 +vpxor %xmm14,%xmm9,%xmm15 +vpand %xmm10,%xmm15,%xmm15 +vpxor %xmm15,%xmm9,%xmm9 +vpxor %xmm15,%xmm14,%xmm14 +vmovdqa %xmm13,64(%rsp) +vmovdqa %xmm14,112(%rsp) +vpaddq subc0(%rip),%xmm11,%xmm10 +vpsubq %xmm12,%xmm10,%xmm10 +vpaddq %xmm12,%xmm11,%xmm11 +vpunpckhqdq %xmm10,%xmm11,%xmm12 +vpunpcklqdq %xmm10,%xmm11,%xmm10 +vpaddq %xmm1,%xmm0,%xmm11 +vpaddq subc0(%rip),%xmm0,%xmm0 +vpsubq %xmm1,%xmm0,%xmm0 +vpunpckhqdq %xmm11,%xmm0,%xmm1 +vpunpcklqdq %xmm11,%xmm0,%xmm0 +vpmuludq %xmm0,%xmm10,%xmm11 +vpmuludq %xmm1,%xmm10,%xmm13 +vmovdqa %xmm1,128(%rsp) +vpaddq %xmm1,%xmm1,%xmm1 +vpmuludq %xmm0,%xmm12,%xmm14 +vmovdqa %xmm0,144(%rsp) +vpaddq %xmm14,%xmm13,%xmm13 +vpmuludq %xmm1,%xmm12,%xmm0 +vmovdqa %xmm1,160(%rsp) +vpaddq %xmm3,%xmm2,%xmm1 +vpaddq subc2(%rip),%xmm2,%xmm2 +vpsubq %xmm3,%xmm2,%xmm2 +vpunpckhqdq %xmm1,%xmm2,%xmm3 +vpunpcklqdq %xmm1,%xmm2,%xmm1 +vpmuludq %xmm1,%xmm10,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpmuludq %xmm3,%xmm10,%xmm2 +vmovdqa %xmm3,176(%rsp) +vpaddq %xmm3,%xmm3,%xmm3 +vpmuludq %xmm1,%xmm12,%xmm14 +vmovdqa %xmm1,192(%rsp) +vpaddq %xmm14,%xmm2,%xmm2 +vpmuludq %xmm3,%xmm12,%xmm1 +vmovdqa %xmm3,208(%rsp) +vpaddq %xmm5,%xmm4,%xmm3 +vpaddq subc2(%rip),%xmm4,%xmm4 +vpsubq %xmm5,%xmm4,%xmm4 +vpunpckhqdq %xmm3,%xmm4,%xmm5 +vpunpcklqdq %xmm3,%xmm4,%xmm3 +vpmuludq %xmm3,%xmm10,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vpmuludq %xmm5,%xmm10,%xmm4 +vmovdqa %xmm5,224(%rsp) +vpaddq %xmm5,%xmm5,%xmm5 +vpmuludq %xmm3,%xmm12,%xmm14 +vmovdqa %xmm3,240(%rsp) +vpaddq %xmm14,%xmm4,%xmm4 +vpaddq %xmm7,%xmm6,%xmm3 +vpaddq subc2(%rip),%xmm6,%xmm6 +vpsubq %xmm7,%xmm6,%xmm6 +vpunpckhqdq %xmm3,%xmm6,%xmm7 +vpunpcklqdq %xmm3,%xmm6,%xmm3 +vpmuludq %xmm3,%xmm10,%xmm6 +vpmuludq %xmm5,%xmm12,%xmm14 +vmovdqa %xmm5,256(%rsp) +vpmuludq v19_19(%rip),%xmm5,%xmm5 +vmovdqa %xmm5,272(%rsp) +vpaddq %xmm14,%xmm6,%xmm6 +vpmuludq %xmm7,%xmm10,%xmm5 +vmovdqa %xmm7,288(%rsp) +vpaddq %xmm7,%xmm7,%xmm7 +vpmuludq %xmm3,%xmm12,%xmm14 +vmovdqa %xmm3,304(%rsp) +vpaddq %xmm14,%xmm5,%xmm5 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vmovdqa %xmm3,320(%rsp) +vpaddq %xmm9,%xmm8,%xmm3 +vpaddq subc2(%rip),%xmm8,%xmm8 +vpsubq %xmm9,%xmm8,%xmm8 +vpunpckhqdq %xmm3,%xmm8,%xmm9 +vpunpcklqdq %xmm3,%xmm8,%xmm3 +vmovdqa %xmm3,336(%rsp) +vpmuludq %xmm7,%xmm12,%xmm8 +vmovdqa %xmm7,352(%rsp) +vpmuludq v19_19(%rip),%xmm7,%xmm7 +vmovdqa %xmm7,368(%rsp) +vpmuludq %xmm3,%xmm10,%xmm7 +vpaddq %xmm7,%xmm8,%xmm8 +vpmuludq %xmm9,%xmm10,%xmm7 +vmovdqa %xmm9,384(%rsp) +vpaddq %xmm9,%xmm9,%xmm9 +vpmuludq %xmm3,%xmm12,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vmovdqa %xmm3,400(%rsp) +vpmuludq v19_19(%rip),%xmm12,%xmm12 +vpmuludq %xmm9,%xmm12,%xmm3 +vmovdqa %xmm9,416(%rsp) +vpaddq %xmm3,%xmm11,%xmm11 +vmovdqa 0(%rsp),%xmm3 +vmovdqa 16(%rsp),%xmm9 +vpaddq subc2(%rip),%xmm3,%xmm10 +vpsubq %xmm9,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm10,%xmm3,%xmm9 +vpunpcklqdq %xmm10,%xmm3,%xmm3 +vpmuludq 144(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpmuludq 128(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm2,%xmm2 +vpmuludq 192(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpmuludq 176(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm4,%xmm4 +vpmuludq 240(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpmuludq 224(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm5,%xmm5 +vpmuludq 304(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpmuludq 288(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vpmuludq 336(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpmuludq 384(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 144(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 160(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm1,%xmm1 +vpmuludq 192(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 208(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 240(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 256(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpmuludq 304(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm9,%xmm9 +vpmuludq 352(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 336(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 416(%rsp),%xmm9,%xmm9 +vpaddq %xmm9,%xmm0,%xmm0 +vmovdqa 32(%rsp),%xmm3 +vmovdqa 80(%rsp),%xmm9 +vpaddq subc2(%rip),%xmm3,%xmm10 +vpsubq %xmm9,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm10,%xmm3,%xmm9 +vpunpcklqdq %xmm10,%xmm3,%xmm3 +vpmuludq 144(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpmuludq 128(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm4,%xmm4 +vpmuludq 192(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpmuludq 176(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm5,%xmm5 +vpmuludq 240(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpmuludq 224(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vpmuludq 304(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpmuludq 288(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm13,%xmm13 +vpmuludq 336(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpmuludq 384(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 144(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 160(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 192(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 208(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpmuludq 240(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm9,%xmm9 +vpmuludq 256(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 304(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 352(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm0,%xmm0 +vpmuludq 336(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 416(%rsp),%xmm9,%xmm9 +vpaddq %xmm9,%xmm1,%xmm1 +vmovdqa 48(%rsp),%xmm3 +vmovdqa 96(%rsp),%xmm9 +vpaddq subc2(%rip),%xmm3,%xmm10 +vpsubq %xmm9,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm10,%xmm3,%xmm9 +vpunpcklqdq %xmm10,%xmm3,%xmm3 +vpmuludq 144(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpmuludq 128(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm5,%xmm5 +vpmuludq 192(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpmuludq 176(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vpmuludq 240(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpmuludq 224(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm13,%xmm13 +vpmuludq 304(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpmuludq 288(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm2,%xmm2 +vpmuludq 336(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpmuludq 384(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 144(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 160(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpmuludq 192(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm9,%xmm9 +vpmuludq 208(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 240(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 256(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm0,%xmm0 +vpmuludq 304(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 352(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm1,%xmm1 +vpmuludq 336(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 416(%rsp),%xmm9,%xmm9 +vpaddq %xmm9,%xmm6,%xmm6 +vmovdqa 64(%rsp),%xmm3 +vmovdqa 112(%rsp),%xmm9 +vpaddq subc2(%rip),%xmm3,%xmm10 +vpsubq %xmm9,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm10,%xmm3,%xmm9 +vpunpcklqdq %xmm10,%xmm3,%xmm3 +vpmuludq 144(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpmuludq 128(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm3,%xmm3 +vpmuludq 192(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpmuludq 176(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm13,%xmm13 +vpmuludq 240(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpmuludq 224(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm2,%xmm2 +vpmuludq 304(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpmuludq 288(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm4,%xmm4 +vpmuludq 336(%rsp),%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpmuludq 384(%rsp),%xmm3,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 144(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq v19_19(%rip),%xmm9,%xmm9 +vpmuludq 160(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 192(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 208(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm0,%xmm0 +vpmuludq 240(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpmuludq 256(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm1,%xmm1 +vpmuludq 304(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpmuludq 352(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 336(%rsp),%xmm9,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 416(%rsp),%xmm9,%xmm9 +vpaddq %xmm9,%xmm8,%xmm8 +vpsrlq $25,%xmm4,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpand m25(%rip),%xmm4,%xmm4 +vpsrlq $26,%xmm11,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpand m26(%rip),%xmm11,%xmm11 +vpsrlq $26,%xmm6,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpand m26(%rip),%xmm6,%xmm6 +vpsrlq $25,%xmm13,%xmm3 +vpaddq %xmm3,%xmm0,%xmm0 +vpand m25(%rip),%xmm13,%xmm13 +vpsrlq $25,%xmm5,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpand m25(%rip),%xmm5,%xmm5 +vpsrlq $26,%xmm0,%xmm3 +vpaddq %xmm3,%xmm2,%xmm2 +vpand m26(%rip),%xmm0,%xmm0 +vpsrlq $26,%xmm8,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpand m26(%rip),%xmm8,%xmm8 +vpsrlq $25,%xmm2,%xmm3 +vpaddq %xmm3,%xmm1,%xmm1 +vpand m25(%rip),%xmm2,%xmm2 +vpsrlq $25,%xmm7,%xmm3 +vpsllq $4,%xmm3,%xmm9 +vpaddq %xmm3,%xmm11,%xmm11 +vpsllq $1,%xmm3,%xmm3 +vpaddq %xmm3,%xmm9,%xmm9 +vpaddq %xmm9,%xmm11,%xmm11 +vpand m25(%rip),%xmm7,%xmm7 +vpsrlq $26,%xmm1,%xmm3 +vpaddq %xmm3,%xmm4,%xmm4 +vpand m26(%rip),%xmm1,%xmm1 +vpsrlq $26,%xmm11,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpand m26(%rip),%xmm11,%xmm11 +vpsrlq $25,%xmm4,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpand m25(%rip),%xmm4,%xmm4 +vpunpcklqdq %xmm13,%xmm11,%xmm3 +vpunpckhqdq %xmm13,%xmm11,%xmm9 +vpaddq subc0(%rip),%xmm9,%xmm10 +vpsubq %xmm3,%xmm10,%xmm10 +vpaddq %xmm9,%xmm3,%xmm3 +vpunpckhqdq %xmm3,%xmm10,%xmm9 +vpunpcklqdq %xmm3,%xmm10,%xmm10 +vpmuludq %xmm10,%xmm10,%xmm3 +vpaddq %xmm10,%xmm10,%xmm10 +vpmuludq %xmm9,%xmm10,%xmm11 +vpunpcklqdq %xmm2,%xmm0,%xmm12 +vpunpckhqdq %xmm2,%xmm0,%xmm0 +vpaddq subc2(%rip),%xmm0,%xmm2 +vpsubq %xmm12,%xmm2,%xmm2 +vpaddq %xmm0,%xmm12,%xmm12 +vpunpckhqdq %xmm12,%xmm2,%xmm0 +vpunpcklqdq %xmm12,%xmm2,%xmm2 +vpmuludq %xmm2,%xmm10,%xmm12 +vpaddq %xmm9,%xmm9,%xmm13 +vpmuludq %xmm13,%xmm9,%xmm9 +vpaddq %xmm9,%xmm12,%xmm12 +vpmuludq %xmm0,%xmm10,%xmm9 +vpmuludq %xmm2,%xmm13,%xmm14 +vpaddq %xmm14,%xmm9,%xmm9 +vpunpcklqdq %xmm4,%xmm1,%xmm14 +vpunpckhqdq %xmm4,%xmm1,%xmm1 +vpaddq subc2(%rip),%xmm1,%xmm4 +vpsubq %xmm14,%xmm4,%xmm4 +vpaddq %xmm1,%xmm14,%xmm14 +vpunpckhqdq %xmm14,%xmm4,%xmm1 +vpunpcklqdq %xmm14,%xmm4,%xmm4 +vmovdqa %xmm1,0(%rsp) +vpaddq %xmm1,%xmm1,%xmm1 +vmovdqa %xmm1,16(%rsp) +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vmovdqa %xmm1,32(%rsp) +vpmuludq %xmm4,%xmm10,%xmm1 +vpmuludq %xmm2,%xmm2,%xmm14 +vpaddq %xmm14,%xmm1,%xmm1 +vpmuludq 0(%rsp),%xmm10,%xmm14 +vpmuludq %xmm4,%xmm13,%xmm15 +vpaddq %xmm15,%xmm14,%xmm14 +vpunpcklqdq %xmm5,%xmm6,%xmm15 +vpunpckhqdq %xmm5,%xmm6,%xmm5 +vpaddq subc2(%rip),%xmm5,%xmm6 +vpsubq %xmm15,%xmm6,%xmm6 +vpaddq %xmm5,%xmm15,%xmm15 +vpunpckhqdq %xmm15,%xmm6,%xmm5 +vpunpcklqdq %xmm15,%xmm6,%xmm6 +vmovdqa %xmm6,48(%rsp) +vpmuludq v19_19(%rip),%xmm6,%xmm6 +vmovdqa %xmm6,64(%rsp) +vmovdqa %xmm5,80(%rsp) +vpmuludq v38_38(%rip),%xmm5,%xmm5 +vmovdqa %xmm5,96(%rsp) +vpmuludq 48(%rsp),%xmm10,%xmm5 +vpaddq %xmm0,%xmm0,%xmm6 +vpmuludq %xmm6,%xmm0,%xmm0 +vpaddq %xmm0,%xmm5,%xmm5 +vpmuludq 80(%rsp),%xmm10,%xmm0 +vpmuludq %xmm4,%xmm6,%xmm15 +vpaddq %xmm15,%xmm0,%xmm0 +vpmuludq %xmm6,%xmm13,%xmm15 +vpaddq %xmm15,%xmm1,%xmm1 +vpmuludq %xmm6,%xmm2,%xmm15 +vpaddq %xmm15,%xmm14,%xmm14 +vpunpcklqdq %xmm7,%xmm8,%xmm15 +vpunpckhqdq %xmm7,%xmm8,%xmm7 +vpaddq subc2(%rip),%xmm7,%xmm8 +vpsubq %xmm15,%xmm8,%xmm8 +vpaddq %xmm7,%xmm15,%xmm15 +vpunpckhqdq %xmm15,%xmm8,%xmm7 +vpunpcklqdq %xmm15,%xmm8,%xmm8 +vmovdqa %xmm8,112(%rsp) +vpmuludq v19_19(%rip),%xmm8,%xmm8 +vmovdqa %xmm8,160(%rsp) +vpmuludq 112(%rsp),%xmm10,%xmm8 +vpmuludq %xmm7,%xmm10,%xmm10 +vpmuludq v38_38(%rip),%xmm7,%xmm15 +vpmuludq %xmm15,%xmm7,%xmm7 +vpaddq %xmm7,%xmm8,%xmm8 +vpmuludq %xmm15,%xmm13,%xmm7 +vpaddq %xmm7,%xmm3,%xmm3 +vpmuludq %xmm15,%xmm2,%xmm7 +vpaddq %xmm7,%xmm11,%xmm11 +vpmuludq 80(%rsp),%xmm13,%xmm7 +vpaddq %xmm7,%xmm7,%xmm7 +vpaddq %xmm7,%xmm8,%xmm8 +vpmuludq 16(%rsp),%xmm13,%xmm7 +vpaddq %xmm7,%xmm5,%xmm5 +vpmuludq 48(%rsp),%xmm13,%xmm7 +vpaddq %xmm7,%xmm0,%xmm0 +vpmuludq 112(%rsp),%xmm13,%xmm7 +vpaddq %xmm7,%xmm10,%xmm10 +vpmuludq %xmm15,%xmm6,%xmm7 +vpaddq %xmm7,%xmm12,%xmm12 +vpmuludq %xmm15,%xmm4,%xmm7 +vpaddq %xmm7,%xmm9,%xmm9 +vpaddq %xmm2,%xmm2,%xmm2 +vpmuludq %xmm4,%xmm2,%xmm7 +vpaddq %xmm7,%xmm5,%xmm5 +vpmuludq 160(%rsp),%xmm2,%xmm7 +vpaddq %xmm7,%xmm3,%xmm3 +vpmuludq 160(%rsp),%xmm6,%xmm7 +vpaddq %xmm7,%xmm11,%xmm11 +vpmuludq 0(%rsp),%xmm2,%xmm7 +vpaddq %xmm7,%xmm0,%xmm0 +vpmuludq 48(%rsp),%xmm2,%xmm7 +vpaddq %xmm7,%xmm8,%xmm8 +vpmuludq 80(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 96(%rsp),%xmm4,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq %xmm4,%xmm4,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpaddq %xmm4,%xmm4,%xmm2 +vpmuludq 160(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm12,%xmm12 +vpmuludq 16(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vpmuludq 48(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm14,%xmm14 +vpmuludq 96(%rsp),%xmm6,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vmovdqa 16(%rsp),%xmm4 +vpmuludq 160(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm9,%xmm9 +vpmuludq 16(%rsp),%xmm6,%xmm4 +vpaddq %xmm4,%xmm8,%xmm8 +vpmuludq 48(%rsp),%xmm6,%xmm4 +vpaddq %xmm4,%xmm10,%xmm10 +vpmuludq 80(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm4,%xmm4 +vpaddq %xmm4,%xmm5,%xmm5 +vpmuludq 112(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm0,%xmm0 +vmovdqa 48(%rsp),%xmm4 +vpaddq %xmm4,%xmm4,%xmm4 +vpmuludq 160(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vmovdqa 80(%rsp),%xmm4 +vpaddq %xmm4,%xmm4,%xmm4 +vpmuludq 160(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm14,%xmm14 +vpmuludq 64(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vmovdqa 16(%rsp),%xmm4 +vpmuludq 64(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm11,%xmm11 +vmovdqa 16(%rsp),%xmm4 +vpmuludq 96(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm12,%xmm12 +vmovdqa 48(%rsp),%xmm4 +vpmuludq 96(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm9,%xmm9 +vpmuludq 0(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vmovdqa 32(%rsp),%xmm2 +vpmuludq 0(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vmovdqa 64(%rsp),%xmm2 +vpmuludq 48(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vmovdqa 96(%rsp),%xmm2 +vpmuludq 80(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm1,%xmm1 +vmovdqa 160(%rsp),%xmm2 +vpmuludq 112(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpsrlq $26,%xmm3,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpand m26(%rip),%xmm3,%xmm3 +vpsrlq $25,%xmm14,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpand m25(%rip),%xmm14,%xmm14 +vpsrlq $25,%xmm11,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpand m25(%rip),%xmm11,%xmm11 +vpsrlq $26,%xmm5,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpand m26(%rip),%xmm5,%xmm5 +vpsrlq $26,%xmm12,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpand m26(%rip),%xmm12,%xmm12 +vpsrlq $25,%xmm0,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpand m25(%rip),%xmm0,%xmm0 +vpsrlq $25,%xmm9,%xmm2 +vpaddq %xmm2,%xmm1,%xmm1 +vpand m25(%rip),%xmm9,%xmm9 +vpsrlq $26,%xmm8,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpand m26(%rip),%xmm8,%xmm8 +vpsrlq $26,%xmm1,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpand m26(%rip),%xmm1,%xmm1 +vpsrlq $25,%xmm10,%xmm2 +vpsllq $4,%xmm2,%xmm4 +vpaddq %xmm2,%xmm3,%xmm3 +vpsllq $1,%xmm2,%xmm2 +vpaddq %xmm2,%xmm4,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $25,%xmm14,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpand m25(%rip),%xmm14,%xmm14 +vpsrlq $26,%xmm3,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpand m26(%rip),%xmm3,%xmm3 +vpunpckhqdq %xmm11,%xmm3,%xmm2 +vmovdqa %xmm2,0(%rsp) +vpunpcklqdq %xmm11,%xmm3,%xmm2 +vpmuludq v9_9(%rip),%xmm2,%xmm2 +vmovdqa %xmm2,80(%rsp) +vpunpckhqdq %xmm9,%xmm12,%xmm2 +vmovdqa %xmm2,16(%rsp) +vpunpcklqdq %xmm9,%xmm12,%xmm2 +vpmuludq v9_9(%rip),%xmm2,%xmm2 +vmovdqa %xmm2,96(%rsp) +vpunpckhqdq %xmm14,%xmm1,%xmm2 +vmovdqa %xmm2,32(%rsp) +vpunpcklqdq %xmm14,%xmm1,%xmm1 +vpmuludq v9_9(%rip),%xmm1,%xmm1 +vmovdqa %xmm1,112(%rsp) +vpunpckhqdq %xmm0,%xmm5,%xmm1 +vmovdqa %xmm1,48(%rsp) +vpunpcklqdq %xmm0,%xmm5,%xmm0 +vpmuludq v9_9(%rip),%xmm0,%xmm0 +vmovdqa %xmm0,160(%rsp) +vpunpckhqdq %xmm10,%xmm8,%xmm0 +vmovdqa %xmm0,64(%rsp) +vpunpcklqdq %xmm10,%xmm8,%xmm0 +vpmuludq v9_9(%rip),%xmm0,%xmm0 +vmovdqa %xmm0,208(%rsp) +vmovdqa 144(%rsp),%xmm0 +vpmuludq %xmm0,%xmm0,%xmm1 +vpaddq %xmm0,%xmm0,%xmm0 +vmovdqa 128(%rsp),%xmm2 +vpmuludq %xmm2,%xmm0,%xmm3 +vmovdqa 192(%rsp),%xmm4 +vpmuludq %xmm4,%xmm0,%xmm5 +vmovdqa 176(%rsp),%xmm6 +vpmuludq %xmm6,%xmm0,%xmm7 +vmovdqa 240(%rsp),%xmm8 +vpmuludq %xmm8,%xmm0,%xmm9 +vpmuludq 224(%rsp),%xmm0,%xmm10 +vpmuludq 304(%rsp),%xmm0,%xmm11 +vpmuludq 288(%rsp),%xmm0,%xmm12 +vpmuludq 336(%rsp),%xmm0,%xmm13 +vmovdqa 384(%rsp),%xmm14 +vpmuludq %xmm14,%xmm0,%xmm0 +vpmuludq v38_38(%rip),%xmm14,%xmm15 +vpmuludq %xmm15,%xmm14,%xmm14 +vpaddq %xmm14,%xmm13,%xmm13 +vpaddq %xmm6,%xmm6,%xmm14 +vpmuludq %xmm14,%xmm6,%xmm6 +vpaddq %xmm6,%xmm11,%xmm11 +vpaddq %xmm2,%xmm2,%xmm6 +vpmuludq %xmm6,%xmm2,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq %xmm15,%xmm6,%xmm2 +vpaddq %xmm2,%xmm1,%xmm1 +vpmuludq %xmm15,%xmm4,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vpmuludq 256(%rsp),%xmm6,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq 304(%rsp),%xmm6,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 352(%rsp),%xmm6,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 336(%rsp),%xmm6,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpmuludq %xmm4,%xmm6,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq %xmm14,%xmm6,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq %xmm8,%xmm6,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq %xmm15,%xmm14,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq %xmm15,%xmm8,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq %xmm4,%xmm4,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq %xmm14,%xmm4,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpaddq %xmm4,%xmm4,%xmm2 +vpmuludq %xmm8,%xmm2,%xmm4 +vpaddq %xmm4,%xmm11,%xmm11 +vpmuludq 400(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vpmuludq 400(%rsp),%xmm14,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vpmuludq 224(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm12,%xmm12 +vpmuludq 304(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm13,%xmm13 +vpmuludq 288(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpmuludq 368(%rsp),%xmm8,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vpmuludq %xmm8,%xmm14,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq %xmm8,%xmm8,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpaddq %xmm8,%xmm8,%xmm2 +vpmuludq 400(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm5,%xmm5 +vpmuludq 256(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm9,%xmm9 +vpmuludq 304(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm10,%xmm10 +vpmuludq 368(%rsp),%xmm14,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vmovdqa 256(%rsp),%xmm4 +vpmuludq 400(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm7,%xmm7 +vpmuludq 256(%rsp),%xmm14,%xmm4 +vpaddq %xmm4,%xmm13,%xmm13 +vpmuludq 304(%rsp),%xmm14,%xmm4 +vpaddq %xmm4,%xmm0,%xmm0 +vpmuludq 352(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm11,%xmm11 +vpmuludq 336(%rsp),%xmm15,%xmm4 +vpaddq %xmm4,%xmm12,%xmm12 +vmovdqa 304(%rsp),%xmm4 +vpaddq %xmm4,%xmm4,%xmm4 +vpmuludq 400(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm9,%xmm9 +vpmuludq 320(%rsp),%xmm2,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vmovdqa 256(%rsp),%xmm4 +vpmuludq 320(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm3,%xmm3 +vmovdqa 256(%rsp),%xmm4 +vpmuludq 368(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm5,%xmm5 +vmovdqa 304(%rsp),%xmm4 +vpmuludq 368(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm7,%xmm7 +vmovdqa 352(%rsp),%xmm4 +vpmuludq 400(%rsp),%xmm4,%xmm4 +vpaddq %xmm4,%xmm10,%xmm10 +vpmuludq 224(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vmovdqa 272(%rsp),%xmm2 +vpmuludq 224(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm1,%xmm1 +vmovdqa 320(%rsp),%xmm2 +vpmuludq 304(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vmovdqa 368(%rsp),%xmm2 +vpmuludq 288(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vmovdqa 400(%rsp),%xmm2 +vpmuludq 336(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpsrlq $26,%xmm1,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vpand m26(%rip),%xmm1,%xmm1 +vpsrlq $25,%xmm10,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $25,%xmm3,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpand m25(%rip),%xmm3,%xmm3 +vpsrlq $26,%xmm11,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpand m26(%rip),%xmm11,%xmm11 +vpsrlq $26,%xmm5,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpand m26(%rip),%xmm5,%xmm5 +vpsrlq $25,%xmm12,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpand m25(%rip),%xmm12,%xmm12 +vpsrlq $25,%xmm7,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpand m25(%rip),%xmm7,%xmm7 +vpsrlq $26,%xmm13,%xmm2 +vpaddq %xmm2,%xmm0,%xmm0 +vpand m26(%rip),%xmm13,%xmm13 +vpsrlq $26,%xmm9,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpand m26(%rip),%xmm9,%xmm9 +vpsrlq $25,%xmm0,%xmm2 +vpsllq $4,%xmm2,%xmm4 +vpaddq %xmm2,%xmm1,%xmm1 +vpsllq $1,%xmm2,%xmm2 +vpaddq %xmm2,%xmm4,%xmm4 +vpaddq %xmm4,%xmm1,%xmm1 +vpand m25(%rip),%xmm0,%xmm0 +vpsrlq $25,%xmm10,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $26,%xmm1,%xmm2 +vpaddq %xmm2,%xmm3,%xmm3 +vpand m26(%rip),%xmm1,%xmm1 +vpunpckhqdq %xmm3,%xmm1,%xmm2 +vpunpcklqdq %xmm3,%xmm1,%xmm1 +vmovdqa %xmm1,176(%rsp) +vpaddq subc0(%rip),%xmm2,%xmm3 +vpsubq %xmm1,%xmm3,%xmm3 +vpunpckhqdq %xmm3,%xmm2,%xmm1 +vpunpcklqdq %xmm3,%xmm2,%xmm2 +vmovdqa %xmm2,192(%rsp) +vmovdqa %xmm1,224(%rsp) +vpsllq $1,%xmm1,%xmm1 +vmovdqa %xmm1,240(%rsp) +vpmuludq v121666_121666(%rip),%xmm3,%xmm3 +vmovdqa 80(%rsp),%xmm1 +vpunpcklqdq %xmm1,%xmm3,%xmm2 +vpunpckhqdq %xmm1,%xmm3,%xmm1 +vpunpckhqdq %xmm7,%xmm5,%xmm3 +vpunpcklqdq %xmm7,%xmm5,%xmm4 +vmovdqa %xmm4,256(%rsp) +vpaddq subc2(%rip),%xmm3,%xmm5 +vpsubq %xmm4,%xmm5,%xmm5 +vpunpckhqdq %xmm5,%xmm3,%xmm4 +vpunpcklqdq %xmm5,%xmm3,%xmm3 +vmovdqa %xmm3,272(%rsp) +vmovdqa %xmm4,288(%rsp) +vpsllq $1,%xmm4,%xmm4 +vmovdqa %xmm4,304(%rsp) +vpmuludq v121666_121666(%rip),%xmm5,%xmm5 +vmovdqa 96(%rsp),%xmm3 +vpunpcklqdq %xmm3,%xmm5,%xmm4 +vpunpckhqdq %xmm3,%xmm5,%xmm3 +vpunpckhqdq %xmm10,%xmm9,%xmm5 +vpunpcklqdq %xmm10,%xmm9,%xmm6 +vmovdqa %xmm6,320(%rsp) +vpaddq subc2(%rip),%xmm5,%xmm7 +vpsubq %xmm6,%xmm7,%xmm7 +vpunpckhqdq %xmm7,%xmm5,%xmm6 +vpunpcklqdq %xmm7,%xmm5,%xmm5 +vmovdqa %xmm5,336(%rsp) +vmovdqa %xmm6,352(%rsp) +vpsllq $1,%xmm6,%xmm6 +vmovdqa %xmm6,368(%rsp) +vpmuludq v121666_121666(%rip),%xmm7,%xmm7 +vmovdqa 112(%rsp),%xmm5 +vpunpcklqdq %xmm5,%xmm7,%xmm6 +vpunpckhqdq %xmm5,%xmm7,%xmm5 +vpunpckhqdq %xmm12,%xmm11,%xmm7 +vpunpcklqdq %xmm12,%xmm11,%xmm8 +vmovdqa %xmm8,384(%rsp) +vpaddq subc2(%rip),%xmm7,%xmm9 +vpsubq %xmm8,%xmm9,%xmm9 +vpunpckhqdq %xmm9,%xmm7,%xmm8 +vpunpcklqdq %xmm9,%xmm7,%xmm7 +vmovdqa %xmm7,400(%rsp) +vmovdqa %xmm8,416(%rsp) +vpsllq $1,%xmm8,%xmm8 +vmovdqa %xmm8,432(%rsp) +vpmuludq v121666_121666(%rip),%xmm9,%xmm9 +vmovdqa 160(%rsp),%xmm7 +vpunpcklqdq %xmm7,%xmm9,%xmm8 +vpunpckhqdq %xmm7,%xmm9,%xmm7 +vpunpckhqdq %xmm0,%xmm13,%xmm9 +vpunpcklqdq %xmm0,%xmm13,%xmm0 +vmovdqa %xmm0,160(%rsp) +vpaddq subc2(%rip),%xmm9,%xmm10 +vpsubq %xmm0,%xmm10,%xmm10 +vpunpckhqdq %xmm10,%xmm9,%xmm0 +vpunpcklqdq %xmm10,%xmm9,%xmm9 +vmovdqa %xmm9,448(%rsp) +vmovdqa %xmm0,464(%rsp) +vpsllq $1,%xmm0,%xmm0 +vmovdqa %xmm0,480(%rsp) +vpmuludq v121666_121666(%rip),%xmm10,%xmm10 +vmovdqa 208(%rsp),%xmm0 +vpunpcklqdq %xmm0,%xmm10,%xmm9 +vpunpckhqdq %xmm0,%xmm10,%xmm0 +vpsrlq $26,%xmm2,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpand m26(%rip),%xmm2,%xmm2 +vpsrlq $25,%xmm5,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpand m25(%rip),%xmm5,%xmm5 +vpsrlq $25,%xmm1,%xmm10 +vpaddq %xmm10,%xmm4,%xmm4 +vpand m25(%rip),%xmm1,%xmm1 +vpsrlq $26,%xmm8,%xmm10 +vpaddq %xmm10,%xmm7,%xmm7 +vpand m26(%rip),%xmm8,%xmm8 +vpsrlq $26,%xmm4,%xmm10 +vpaddq %xmm10,%xmm3,%xmm3 +vpand m26(%rip),%xmm4,%xmm4 +vpsrlq $25,%xmm7,%xmm10 +vpaddq %xmm10,%xmm9,%xmm9 +vpand m25(%rip),%xmm7,%xmm7 +vpsrlq $25,%xmm3,%xmm10 +vpaddq %xmm10,%xmm6,%xmm6 +vpand m25(%rip),%xmm3,%xmm3 +vpsrlq $26,%xmm9,%xmm10 +vpaddq %xmm10,%xmm0,%xmm0 +vpand m26(%rip),%xmm9,%xmm9 +vpsrlq $26,%xmm6,%xmm10 +vpaddq %xmm10,%xmm5,%xmm5 +vpand m26(%rip),%xmm6,%xmm6 +vpsrlq $25,%xmm0,%xmm10 +vpsllq $4,%xmm10,%xmm11 +vpaddq %xmm10,%xmm2,%xmm2 +vpsllq $1,%xmm10,%xmm10 +vpaddq %xmm10,%xmm11,%xmm11 +vpaddq %xmm11,%xmm2,%xmm2 +vpand m25(%rip),%xmm0,%xmm0 +vpsrlq $25,%xmm5,%xmm10 +vpaddq %xmm10,%xmm8,%xmm8 +vpand m25(%rip),%xmm5,%xmm5 +vpsrlq $26,%xmm2,%xmm10 +vpaddq %xmm10,%xmm1,%xmm1 +vpand m26(%rip),%xmm2,%xmm2 +vpunpckhqdq %xmm1,%xmm2,%xmm10 +vmovdqa %xmm10,80(%rsp) +vpunpcklqdq %xmm1,%xmm2,%xmm1 +vpunpckhqdq %xmm3,%xmm4,%xmm2 +vmovdqa %xmm2,96(%rsp) +vpunpcklqdq %xmm3,%xmm4,%xmm2 +vpunpckhqdq %xmm5,%xmm6,%xmm3 +vmovdqa %xmm3,112(%rsp) +vpunpcklqdq %xmm5,%xmm6,%xmm3 +vpunpckhqdq %xmm7,%xmm8,%xmm4 +vmovdqa %xmm4,128(%rsp) +vpunpcklqdq %xmm7,%xmm8,%xmm4 +vpunpckhqdq %xmm0,%xmm9,%xmm5 +vmovdqa %xmm5,144(%rsp) +vpunpcklqdq %xmm0,%xmm9,%xmm0 +vmovdqa 176(%rsp),%xmm5 +vpaddq %xmm5,%xmm1,%xmm1 +vpunpcklqdq %xmm1,%xmm5,%xmm6 +vpunpckhqdq %xmm1,%xmm5,%xmm1 +vpmuludq 224(%rsp),%xmm6,%xmm5 +vpmuludq 192(%rsp),%xmm1,%xmm7 +vpaddq %xmm7,%xmm5,%xmm5 +vpmuludq 272(%rsp),%xmm6,%xmm7 +vpmuludq 240(%rsp),%xmm1,%xmm8 +vpaddq %xmm8,%xmm7,%xmm7 +vpmuludq 288(%rsp),%xmm6,%xmm8 +vpmuludq 272(%rsp),%xmm1,%xmm9 +vpaddq %xmm9,%xmm8,%xmm8 +vpmuludq 336(%rsp),%xmm6,%xmm9 +vpmuludq 304(%rsp),%xmm1,%xmm10 +vpaddq %xmm10,%xmm9,%xmm9 +vpmuludq 352(%rsp),%xmm6,%xmm10 +vpmuludq 336(%rsp),%xmm1,%xmm11 +vpaddq %xmm11,%xmm10,%xmm10 +vpmuludq 400(%rsp),%xmm6,%xmm11 +vpmuludq 368(%rsp),%xmm1,%xmm12 +vpaddq %xmm12,%xmm11,%xmm11 +vpmuludq 416(%rsp),%xmm6,%xmm12 +vpmuludq 400(%rsp),%xmm1,%xmm13 +vpaddq %xmm13,%xmm12,%xmm12 +vpmuludq 448(%rsp),%xmm6,%xmm13 +vpmuludq 432(%rsp),%xmm1,%xmm14 +vpaddq %xmm14,%xmm13,%xmm13 +vpmuludq 464(%rsp),%xmm6,%xmm14 +vpmuludq 448(%rsp),%xmm1,%xmm15 +vpaddq %xmm15,%xmm14,%xmm14 +vpmuludq 192(%rsp),%xmm6,%xmm6 +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vpmuludq 480(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm6,%xmm6 +vmovdqa 256(%rsp),%xmm1 +vpaddq %xmm1,%xmm2,%xmm2 +vpunpcklqdq %xmm2,%xmm1,%xmm15 +vpunpckhqdq %xmm2,%xmm1,%xmm1 +vpmuludq 192(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq 224(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 272(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq 288(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 336(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq 352(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 400(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 416(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm15,%xmm15 +vpmuludq 448(%rsp),%xmm15,%xmm2 +vpaddq %xmm2,%xmm6,%xmm6 +vpmuludq 464(%rsp),%xmm15,%xmm15 +vpaddq %xmm15,%xmm5,%xmm5 +vpmuludq 192(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 240(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq 272(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 304(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq 336(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 368(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 400(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vpmuludq 432(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm6,%xmm6 +vpmuludq 448(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq 480(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm7,%xmm7 +vmovdqa 320(%rsp),%xmm1 +vpaddq %xmm1,%xmm3,%xmm3 +vpunpcklqdq %xmm3,%xmm1,%xmm2 +vpunpckhqdq %xmm3,%xmm1,%xmm1 +vpmuludq 192(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm9,%xmm9 +vpmuludq 224(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm10,%xmm10 +vpmuludq 272(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 288(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm12,%xmm12 +vpmuludq 336(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 352(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm2,%xmm2 +vpmuludq 400(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 416(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 448(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq 464(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 192(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 240(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm11,%xmm11 +vpmuludq 272(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 304(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 336(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vpmuludq 368(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm6,%xmm6 +vpmuludq 400(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq 432(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq 448(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 480(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm9,%xmm9 +vmovdqa 384(%rsp),%xmm1 +vpaddq %xmm1,%xmm4,%xmm4 +vpunpcklqdq %xmm4,%xmm1,%xmm2 +vpunpckhqdq %xmm4,%xmm1,%xmm1 +vpmuludq 192(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm11,%xmm11 +vpmuludq 224(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm12,%xmm12 +vpmuludq 272(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm13,%xmm13 +vpmuludq 288(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm2,%xmm2 +vpmuludq 336(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm6,%xmm6 +vpmuludq 352(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm5,%xmm5 +vpmuludq 400(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm7,%xmm7 +vpmuludq 416(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm8,%xmm8 +vpmuludq 448(%rsp),%xmm2,%xmm3 +vpaddq %xmm3,%xmm9,%xmm9 +vpmuludq 464(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 192(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 240(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm13,%xmm13 +vpmuludq 272(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm1,%xmm1 +vpmuludq 304(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm6,%xmm6 +vpmuludq 336(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm5,%xmm5 +vpmuludq 368(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm7,%xmm7 +vpmuludq 400(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm8,%xmm8 +vpmuludq 432(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm9,%xmm9 +vpmuludq 448(%rsp),%xmm1,%xmm2 +vpaddq %xmm2,%xmm10,%xmm10 +vpmuludq 480(%rsp),%xmm1,%xmm1 +vpaddq %xmm1,%xmm11,%xmm11 +vmovdqa 160(%rsp),%xmm1 +vpaddq %xmm1,%xmm0,%xmm0 +vpunpcklqdq %xmm0,%xmm1,%xmm2 +vpunpckhqdq %xmm0,%xmm1,%xmm0 +vpmuludq 192(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm13,%xmm13 +vpmuludq 224(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm2,%xmm2 +vpmuludq 272(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm6,%xmm6 +vpmuludq 288(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm5,%xmm5 +vpmuludq 336(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm7,%xmm7 +vpmuludq 352(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm8,%xmm8 +vpmuludq 400(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm9,%xmm9 +vpmuludq 416(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm10,%xmm10 +vpmuludq 448(%rsp),%xmm2,%xmm1 +vpaddq %xmm1,%xmm11,%xmm11 +vpmuludq 464(%rsp),%xmm2,%xmm2 +vpaddq %xmm2,%xmm12,%xmm12 +vpmuludq 192(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm14,%xmm14 +vpmuludq v19_19(%rip),%xmm0,%xmm0 +vpmuludq 240(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm6,%xmm6 +vpmuludq 272(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm5,%xmm5 +vpmuludq 304(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm7,%xmm7 +vpmuludq 336(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm8,%xmm8 +vpmuludq 368(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm9,%xmm9 +vpmuludq 400(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm10,%xmm10 +vpmuludq 432(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm11,%xmm11 +vpmuludq 448(%rsp),%xmm0,%xmm1 +vpaddq %xmm1,%xmm12,%xmm12 +vpmuludq 480(%rsp),%xmm0,%xmm0 +vpaddq %xmm0,%xmm13,%xmm13 +vpsrlq $26,%xmm6,%xmm0 +vpaddq %xmm0,%xmm5,%xmm5 +vpand m26(%rip),%xmm6,%xmm6 +vpsrlq $25,%xmm10,%xmm0 +vpaddq %xmm0,%xmm11,%xmm11 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $25,%xmm5,%xmm0 +vpaddq %xmm0,%xmm7,%xmm7 +vpand m25(%rip),%xmm5,%xmm5 +vpsrlq $26,%xmm11,%xmm0 +vpaddq %xmm0,%xmm12,%xmm12 +vpand m26(%rip),%xmm11,%xmm11 +vpsrlq $26,%xmm7,%xmm0 +vpaddq %xmm0,%xmm8,%xmm8 +vpand m26(%rip),%xmm7,%xmm7 +vpsrlq $25,%xmm12,%xmm0 +vpaddq %xmm0,%xmm13,%xmm13 +vpand m25(%rip),%xmm12,%xmm12 +vpsrlq $25,%xmm8,%xmm0 +vpaddq %xmm0,%xmm9,%xmm9 +vpand m25(%rip),%xmm8,%xmm8 +vpsrlq $26,%xmm13,%xmm0 +vpaddq %xmm0,%xmm14,%xmm14 +vpand m26(%rip),%xmm13,%xmm13 +vpsrlq $26,%xmm9,%xmm0 +vpaddq %xmm0,%xmm10,%xmm10 +vpand m26(%rip),%xmm9,%xmm9 +vpsrlq $25,%xmm14,%xmm0 +vpsllq $4,%xmm0,%xmm1 +vpaddq %xmm0,%xmm6,%xmm6 +vpsllq $1,%xmm0,%xmm0 +vpaddq %xmm0,%xmm1,%xmm1 +vpaddq %xmm1,%xmm6,%xmm6 +vpand m25(%rip),%xmm14,%xmm14 +vpsrlq $25,%xmm10,%xmm0 +vpaddq %xmm0,%xmm11,%xmm11 +vpand m25(%rip),%xmm10,%xmm10 +vpsrlq $26,%xmm6,%xmm0 +vpaddq %xmm0,%xmm5,%xmm5 +vpand m26(%rip),%xmm6,%xmm6 +vpunpckhqdq %xmm5,%xmm6,%xmm1 +vpunpcklqdq %xmm5,%xmm6,%xmm0 +vpunpckhqdq %xmm8,%xmm7,%xmm3 +vpunpcklqdq %xmm8,%xmm7,%xmm2 +vpunpckhqdq %xmm10,%xmm9,%xmm5 +vpunpcklqdq %xmm10,%xmm9,%xmm4 +vpunpckhqdq %xmm12,%xmm11,%xmm7 +vpunpcklqdq %xmm12,%xmm11,%xmm6 +vpunpckhqdq %xmm14,%xmm13,%xmm9 +vpunpcklqdq %xmm14,%xmm13,%xmm8 +cmp $0,%rdx +jne ._ladder_base_loop +vmovdqu %xmm1,80(%rdi) +vmovdqu %xmm0,0(%rdi) +vmovdqu %xmm3,96(%rdi) +vmovdqu %xmm2,16(%rdi) +vmovdqu %xmm5,112(%rdi) +vmovdqu %xmm4,32(%rdi) +vmovdqu %xmm7,128(%rdi) +vmovdqu %xmm6,48(%rdi) +vmovdqu %xmm9,144(%rdi) +vmovdqu %xmm8,64(%rdi) +movq 1536(%rsp),%r11 +movq 1544(%rsp),%r12 +movq 1552(%rsp),%r13 +add %r11,%rsp +ret + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base.h b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base.h new file mode 100644 index 0000000000..a69be13f0d --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base.h @@ -0,0 +1,18 @@ +#ifndef ladder_base_H +#define ladder_base_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "fe.h" +#include "ladder_base_namespace.h" + +extern void ladder_base(fe *, const unsigned char *); + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef ladder_base_H */ + diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base_namespace.h b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base_namespace.h new file mode 100644 index 0000000000..304546a185 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_base_namespace.h @@ -0,0 +1,8 @@ +#ifndef ladder_base_namespace_H +#define ladder_base_namespace_H + +#define ladder_base crypto_scalarmult_curve25519_sandy2x_ladder_base +#define _ladder_base _crypto_scalarmult_curve25519_sandy2x_ladder_base + +#endif /* ifndef ladder_base_namespace_H */ + diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_namespace.h b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_namespace.h new file mode 100644 index 0000000000..6637074bec --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/ladder_namespace.h @@ -0,0 +1,8 @@ +#ifndef ladder_namespace_H +#define ladder_namespace_H + +#define ladder crypto_scalarmult_curve25519_sandy2x_ladder +#define _ladder _crypto_scalarmult_curve25519_sandy2x_ladder + +#endif /* ifndef ladder_namespace_H */ + diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/sandy2x.S b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/sandy2x.S new file mode 100644 index 0000000000..1fd632057b --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/sandy2x/sandy2x.S @@ -0,0 +1,17 @@ + +#ifdef HAVE_AVX_ASM + +#define IN_SANDY2X + +#include "consts.S" +#include "fe51_mul.S" +#include "fe51_nsquare.S" +#include "fe51_pack.S" +#include "ladder.S" +#include "ladder_base.S" + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/scalarmult_curve25519.c b/libs/libsodium/src/crypto_scalarmult/curve25519/scalarmult_curve25519.c new file mode 100644 index 0000000000..2d3ffc0563 --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/scalarmult_curve25519.c @@ -0,0 +1,59 @@ + +#include "crypto_scalarmult_curve25519.h" +#include "private/implementations.h" +#include "scalarmult_curve25519.h" +#include "runtime.h" + +#ifdef HAVE_AVX_ASM +# include "sandy2x/curve25519_sandy2x.h" +#endif +#include "ref10/x25519_ref10.h" +static const crypto_scalarmult_curve25519_implementation *implementation = + &crypto_scalarmult_curve25519_ref10_implementation; + +int +crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n, + const unsigned char *p) +{ + size_t i; + volatile unsigned char d = 0; + + if (implementation->mult(q, n, p) != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + for (i = 0; i < crypto_scalarmult_curve25519_BYTES; i++) { + d |= q[i]; + } + return -(1 & ((d - 1) >> 8)); +} + +int +crypto_scalarmult_curve25519_base(unsigned char *q, const unsigned char *n) +{ + return implementation->mult_base(q, n); +} + +size_t +crypto_scalarmult_curve25519_bytes(void) +{ + return crypto_scalarmult_curve25519_BYTES; +} + +size_t +crypto_scalarmult_curve25519_scalarbytes(void) +{ + return crypto_scalarmult_curve25519_SCALARBYTES; +} + +int +_crypto_scalarmult_curve25519_pick_best_implementation(void) +{ + implementation = &crypto_scalarmult_curve25519_ref10_implementation; + +#ifdef HAVE_AVX_ASM + if (sodium_runtime_has_avx()) { + implementation = &crypto_scalarmult_curve25519_sandy2x_implementation; + } +#endif + return 0; +} diff --git a/libs/libsodium/src/crypto_scalarmult/curve25519/scalarmult_curve25519.h b/libs/libsodium/src/crypto_scalarmult/curve25519/scalarmult_curve25519.h new file mode 100644 index 0000000000..66edbf6a8a --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/curve25519/scalarmult_curve25519.h @@ -0,0 +1,11 @@ + +#ifndef scalarmult_poly1305_H +#define scalarmult_poly1305_H + +typedef struct crypto_scalarmult_curve25519_implementation { + int (*mult)(unsigned char *q, const unsigned char *n, + const unsigned char *p); + int (*mult_base)(unsigned char *q, const unsigned char *n); +} crypto_scalarmult_curve25519_implementation; + +#endif diff --git a/libs/libsodium/src/crypto_scalarmult/ed25519/ref10/scalarmult_ed25519_ref10.c b/libs/libsodium/src/crypto_scalarmult/ed25519/ref10/scalarmult_ed25519_ref10.c new file mode 100644 index 0000000000..0e317cf7cc --- /dev/null +++ b/libs/libsodium/src/crypto_scalarmult/ed25519/ref10/scalarmult_ed25519_ref10.c @@ -0,0 +1,86 @@ + +#include + +#include "crypto_scalarmult_ed25519.h" +#include "private/ed25519_ref10.h" +#include "utils.h" + +static int +_crypto_scalarmult_ed25519_is_inf(const unsigned char s[32]) +{ + unsigned char c; + unsigned int i; + + c = s[0] ^ 0x01; + for (i = 1; i < 31; i++) { + c |= s[i]; + } + c |= s[31] & 0x7f; + + return ((((unsigned int) c) - 1U) >> 8) & 1; +} + +static inline void +_crypto_scalarmult_ed25519_clamp(unsigned char k[32]) +{ + k[0] &= 248; + k[31] &= 127; + k[31] |= 64; +} + +int +crypto_scalarmult_ed25519(unsigned char *q, const unsigned char *n, + const unsigned char *p) +{ + unsigned char *t = q; + ge25519_p3 Q; + ge25519_p3 P; + unsigned int i; + + if (ge25519_is_canonical(p) == 0 || ge25519_has_small_order(p) != 0 || + ge25519_frombytes(&P, p) != 0 || ge25519_is_on_main_subgroup(&P) == 0) { + return -1; + } + for (i = 0; i < 32; ++i) { + t[i] = n[i]; + } + _crypto_scalarmult_ed25519_clamp(t); + ge25519_scalarmult(&Q, t, &P); + ge25519_p3_tobytes(q, &Q); + if (_crypto_scalarmult_ed25519_is_inf(q) != 0 || sodium_is_zero(n, 32)) { + return -1; + } + return 0; +} + +int +crypto_scalarmult_ed25519_base(unsigned char *q, + const unsigned char *n) +{ + unsigned char *t = q; + ge25519_p3 Q; + unsigned int i; + + for (i = 0; i < 32; ++i) { + t[i] = n[i]; + } + _crypto_scalarmult_ed25519_clamp(t); + ge25519_scalarmult_base(&Q, t); + ge25519_p3_tobytes(q, &Q); + if (sodium_is_zero(n, 32) != 0) { + return -1; + } + return 0; +} + +size_t +crypto_scalarmult_ed25519_bytes(void) +{ + return crypto_scalarmult_ed25519_BYTES; +} + +size_t +crypto_scalarmult_ed25519_scalarbytes(void) +{ + return crypto_scalarmult_ed25519_SCALARBYTES; +} diff --git a/libs/libsodium/src/crypto_secretbox/crypto_secretbox.c b/libs/libsodium/src/crypto_secretbox/crypto_secretbox.c new file mode 100644 index 0000000000..45f678ecdf --- /dev/null +++ b/libs/libsodium/src/crypto_secretbox/crypto_secretbox.c @@ -0,0 +1,67 @@ + +#include "crypto_secretbox.h" +#include "randombytes.h" + +size_t +crypto_secretbox_keybytes(void) +{ + return crypto_secretbox_KEYBYTES; +} + +size_t +crypto_secretbox_noncebytes(void) +{ + return crypto_secretbox_NONCEBYTES; +} + +size_t +crypto_secretbox_zerobytes(void) +{ + return crypto_secretbox_ZEROBYTES; +} + +size_t +crypto_secretbox_boxzerobytes(void) +{ + return crypto_secretbox_BOXZEROBYTES; +} + +size_t +crypto_secretbox_macbytes(void) +{ + return crypto_secretbox_MACBYTES; +} + +size_t +crypto_secretbox_messagebytes_max(void) +{ + return crypto_secretbox_MESSAGEBYTES_MAX; +} + +const char * +crypto_secretbox_primitive(void) +{ + return crypto_secretbox_PRIMITIVE; +} + +int +crypto_secretbox(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + return crypto_secretbox_xsalsa20poly1305(c, m, mlen, n, k); +} + +int +crypto_secretbox_open(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + return crypto_secretbox_xsalsa20poly1305_open(m, c, clen, n, k); +} + +void +crypto_secretbox_keygen(unsigned char k[crypto_secretbox_KEYBYTES]) +{ + randombytes_buf(k, crypto_secretbox_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_secretbox/crypto_secretbox_easy.c b/libs/libsodium/src/crypto_secretbox/crypto_secretbox_easy.c new file mode 100644 index 0000000000..b1203849f2 --- /dev/null +++ b/libs/libsodium/src/crypto_secretbox/crypto_secretbox_easy.c @@ -0,0 +1,144 @@ + +#include +#include +#include +#include +#include + +#include "core.h" +#include "crypto_core_hsalsa20.h" +#include "crypto_onetimeauth_poly1305.h" +#include "crypto_secretbox.h" +#include "crypto_stream_salsa20.h" +#include "private/common.h" +#include "utils.h" + +int +crypto_secretbox_detached(unsigned char *c, unsigned char *mac, + const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + crypto_onetimeauth_poly1305_state state; + unsigned char block0[64U]; + unsigned char subkey[crypto_stream_salsa20_KEYBYTES]; + unsigned long long i; + unsigned long long mlen0; + + crypto_core_hsalsa20(subkey, n, k, NULL); + + if (((uintptr_t) c > (uintptr_t) m && + (uintptr_t) c - (uintptr_t) m < mlen) || + ((uintptr_t) m > (uintptr_t) c && + (uintptr_t) m - (uintptr_t) c < mlen)) { /* LCOV_EXCL_LINE */ + memmove(c, m, mlen); + m = c; + } + memset(block0, 0U, crypto_secretbox_ZEROBYTES); + COMPILER_ASSERT(64U >= crypto_secretbox_ZEROBYTES); + mlen0 = mlen; + if (mlen0 > 64U - crypto_secretbox_ZEROBYTES) { + mlen0 = 64U - crypto_secretbox_ZEROBYTES; + } + for (i = 0U; i < mlen0; i++) { + block0[i + crypto_secretbox_ZEROBYTES] = m[i]; + } + crypto_stream_salsa20_xor(block0, block0, + mlen0 + crypto_secretbox_ZEROBYTES, + n + 16, subkey); + COMPILER_ASSERT(crypto_secretbox_ZEROBYTES >= + crypto_onetimeauth_poly1305_KEYBYTES); + crypto_onetimeauth_poly1305_init(&state, block0); + + for (i = 0U; i < mlen0; i++) { + c[i] = block0[crypto_secretbox_ZEROBYTES + i]; + } + sodium_memzero(block0, sizeof block0); + if (mlen > mlen0) { + crypto_stream_salsa20_xor_ic(c + mlen0, m + mlen0, mlen - mlen0, + n + 16, 1U, subkey); + } + sodium_memzero(subkey, sizeof subkey); + + crypto_onetimeauth_poly1305_update(&state, c, mlen); + crypto_onetimeauth_poly1305_final(&state, mac); + sodium_memzero(&state, sizeof state); + + return 0; +} + +int +crypto_secretbox_easy(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + if (mlen > crypto_secretbox_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + return crypto_secretbox_detached(c + crypto_secretbox_MACBYTES, + c, m, mlen, n, k); +} + +int +crypto_secretbox_open_detached(unsigned char *m, const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) +{ + unsigned char block0[64U]; + unsigned char subkey[crypto_stream_salsa20_KEYBYTES]; + unsigned long long i; + unsigned long long mlen0; + + crypto_core_hsalsa20(subkey, n, k, NULL); + crypto_stream_salsa20(block0, crypto_stream_salsa20_KEYBYTES, + n + 16, subkey); + if (crypto_onetimeauth_poly1305_verify(mac, c, clen, block0) != 0) { + sodium_memzero(subkey, sizeof subkey); + return -1; + } + if (m == NULL) { + return 0; + } + if (((uintptr_t) c >= (uintptr_t) m && + (uintptr_t) c - (uintptr_t) m < clen) || + ((uintptr_t) m >= (uintptr_t) c && + (uintptr_t) m - (uintptr_t) c < clen)) { /* LCOV_EXCL_LINE */ + memmove(m, c, clen); + c = m; + } + mlen0 = clen; + if (mlen0 > 64U - crypto_secretbox_ZEROBYTES) { + mlen0 = 64U - crypto_secretbox_ZEROBYTES; + } + for (i = 0U; i < mlen0; i++) { + block0[crypto_secretbox_ZEROBYTES + i] = c[i]; + } + crypto_stream_salsa20_xor(block0, block0, + crypto_secretbox_ZEROBYTES + mlen0, + n + 16, subkey); + for (i = 0U; i < mlen0; i++) { + m[i] = block0[i + crypto_secretbox_ZEROBYTES]; + } + if (clen > mlen0) { + crypto_stream_salsa20_xor_ic(m + mlen0, c + mlen0, clen - mlen0, + n + 16, 1U, subkey); + } + sodium_memzero(subkey, sizeof subkey); + + return 0; +} + +int +crypto_secretbox_open_easy(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + if (clen < crypto_secretbox_MACBYTES) { + return -1; + } + return crypto_secretbox_open_detached(m, c + crypto_secretbox_MACBYTES, c, + clen - crypto_secretbox_MACBYTES, + n, k); +} diff --git a/libs/libsodium/src/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c b/libs/libsodium/src/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c new file mode 100644 index 0000000000..e76167d2ee --- /dev/null +++ b/libs/libsodium/src/crypto_secretbox/xchacha20poly1305/secretbox_xchacha20poly1305.c @@ -0,0 +1,177 @@ + +#include +#include +#include +#include +#include + +#include "core.h" +#include "crypto_core_hchacha20.h" +#include "crypto_onetimeauth_poly1305.h" +#include "crypto_secretbox_xchacha20poly1305.h" +#include "crypto_stream_chacha20.h" +#include "private/common.h" +#include "utils.h" + +#define crypto_secretbox_xchacha20poly1305_ZEROBYTES 32U + +int +crypto_secretbox_xchacha20poly1305_detached(unsigned char *c, + unsigned char *mac, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k) +{ + crypto_onetimeauth_poly1305_state state; + unsigned char block0[64U]; + unsigned char subkey[crypto_stream_chacha20_KEYBYTES]; + unsigned long long i; + unsigned long long mlen0; + + crypto_core_hchacha20(subkey, n, k, NULL); + + if (((uintptr_t) c > (uintptr_t) m && + (uintptr_t) c - (uintptr_t) m < mlen) || + ((uintptr_t) m > (uintptr_t) c && + (uintptr_t) m - (uintptr_t) c < mlen)) { /* LCOV_EXCL_LINE */ + memmove(c, m, mlen); + m = c; + } + memset(block0, 0U, crypto_secretbox_xchacha20poly1305_ZEROBYTES); + COMPILER_ASSERT(64U >= crypto_secretbox_xchacha20poly1305_ZEROBYTES); + mlen0 = mlen; + if (mlen0 > 64U - crypto_secretbox_xchacha20poly1305_ZEROBYTES) { + mlen0 = 64U - crypto_secretbox_xchacha20poly1305_ZEROBYTES; + } + for (i = 0U; i < mlen0; i++) { + block0[i + crypto_secretbox_xchacha20poly1305_ZEROBYTES] = m[i]; + } + crypto_stream_chacha20_xor(block0, block0, + mlen0 + crypto_secretbox_xchacha20poly1305_ZEROBYTES, + n + 16, subkey); + COMPILER_ASSERT(crypto_secretbox_xchacha20poly1305_ZEROBYTES >= + crypto_onetimeauth_poly1305_KEYBYTES); + crypto_onetimeauth_poly1305_init(&state, block0); + + for (i = 0U; i < mlen0; i++) { + c[i] = block0[crypto_secretbox_xchacha20poly1305_ZEROBYTES + i]; + } + sodium_memzero(block0, sizeof block0); + if (mlen > mlen0) { + crypto_stream_chacha20_xor_ic(c + mlen0, m + mlen0, mlen - mlen0, + n + 16, 1U, subkey); + } + sodium_memzero(subkey, sizeof subkey); + + crypto_onetimeauth_poly1305_update(&state, c, mlen); + crypto_onetimeauth_poly1305_final(&state, mac); + sodium_memzero(&state, sizeof state); + + return 0; +} + +int +crypto_secretbox_xchacha20poly1305_easy(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k) +{ + if (mlen > crypto_secretbox_xchacha20poly1305_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + return crypto_secretbox_xchacha20poly1305_detached + (c + crypto_secretbox_xchacha20poly1305_MACBYTES, c, m, mlen, n, k); +} + +int +crypto_secretbox_xchacha20poly1305_open_detached(unsigned char *m, + const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) +{ + unsigned char block0[64U]; + unsigned char subkey[crypto_stream_chacha20_KEYBYTES]; + unsigned long long i; + unsigned long long mlen0; + + crypto_core_hchacha20(subkey, n, k, NULL); + crypto_stream_chacha20(block0, crypto_stream_chacha20_KEYBYTES, + n + 16, subkey); + if (crypto_onetimeauth_poly1305_verify(mac, c, clen, block0) != 0) { + sodium_memzero(subkey, sizeof subkey); + return -1; + } + if (m == NULL) { + return 0; + } + if (((uintptr_t) c >= (uintptr_t) m && + (uintptr_t) c - (uintptr_t) m < clen) || + ((uintptr_t) m >= (uintptr_t) c && + (uintptr_t) m - (uintptr_t) c < clen)) { /* LCOV_EXCL_LINE */ + memmove(m, c, clen); + c = m; + } + mlen0 = clen; + if (mlen0 > 64U - crypto_secretbox_xchacha20poly1305_ZEROBYTES) { + mlen0 = 64U - crypto_secretbox_xchacha20poly1305_ZEROBYTES; + } + for (i = 0U; i < mlen0; i++) { + block0[crypto_secretbox_xchacha20poly1305_ZEROBYTES + i] = c[i]; + } + crypto_stream_chacha20_xor(block0, block0, + crypto_secretbox_xchacha20poly1305_ZEROBYTES + mlen0, + n + 16, subkey); + for (i = 0U; i < mlen0; i++) { + m[i] = block0[i + crypto_secretbox_xchacha20poly1305_ZEROBYTES]; + } + if (clen > mlen0) { + crypto_stream_chacha20_xor_ic(m + mlen0, c + mlen0, clen - mlen0, + n + 16, 1U, subkey); + } + sodium_memzero(subkey, sizeof subkey); + + return 0; +} + +int +crypto_secretbox_xchacha20poly1305_open_easy(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) +{ + if (clen < crypto_secretbox_xchacha20poly1305_MACBYTES) { + return -1; + } + return crypto_secretbox_xchacha20poly1305_open_detached + (m, c + crypto_secretbox_xchacha20poly1305_MACBYTES, c, + clen - crypto_secretbox_xchacha20poly1305_MACBYTES, n, k); +} + +size_t +crypto_secretbox_xchacha20poly1305_keybytes(void) +{ + return crypto_secretbox_xchacha20poly1305_KEYBYTES; +} + +size_t +crypto_secretbox_xchacha20poly1305_noncebytes(void) +{ + return crypto_secretbox_xchacha20poly1305_NONCEBYTES; +} + +size_t +crypto_secretbox_xchacha20poly1305_macbytes(void) +{ + return crypto_secretbox_xchacha20poly1305_MACBYTES; +} + +size_t +crypto_secretbox_xchacha20poly1305_messagebytes_max(void) +{ + return crypto_secretbox_xchacha20poly1305_MESSAGEBYTES_MAX; +} diff --git a/libs/libsodium/src/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c b/libs/libsodium/src/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c new file mode 100644 index 0000000000..7240050dfd --- /dev/null +++ b/libs/libsodium/src/crypto_secretbox/xsalsa20poly1305/secretbox_xsalsa20poly1305.c @@ -0,0 +1,89 @@ +#include "crypto_onetimeauth_poly1305.h" +#include "crypto_secretbox_xsalsa20poly1305.h" +#include "crypto_stream_xsalsa20.h" +#include "randombytes.h" + +int +crypto_secretbox_xsalsa20poly1305(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k) +{ + int i; + + if (mlen < 32) { + return -1; + } + crypto_stream_xsalsa20_xor(c, m, mlen, n, k); + crypto_onetimeauth_poly1305(c + 16, c + 32, mlen - 32, c); + for (i = 0; i < 16; ++i) { + c[i] = 0; + } + return 0; +} + +int +crypto_secretbox_xsalsa20poly1305_open(unsigned char *m, const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) +{ + unsigned char subkey[32]; + int i; + + if (clen < 32) { + return -1; + } + crypto_stream_xsalsa20(subkey, 32, n, k); + if (crypto_onetimeauth_poly1305_verify(c + 16, c + 32, + clen - 32, subkey) != 0) { + return -1; + } + crypto_stream_xsalsa20_xor(m, c, clen, n, k); + for (i = 0; i < 32; ++i) { + m[i] = 0; + } + return 0; +} + +size_t +crypto_secretbox_xsalsa20poly1305_keybytes(void) +{ + return crypto_secretbox_xsalsa20poly1305_KEYBYTES; +} + +size_t +crypto_secretbox_xsalsa20poly1305_noncebytes(void) +{ + return crypto_secretbox_xsalsa20poly1305_NONCEBYTES; +} + +size_t +crypto_secretbox_xsalsa20poly1305_zerobytes(void) +{ + return crypto_secretbox_xsalsa20poly1305_ZEROBYTES; +} + +size_t +crypto_secretbox_xsalsa20poly1305_boxzerobytes(void) +{ + return crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES; +} + +size_t +crypto_secretbox_xsalsa20poly1305_macbytes(void) +{ + return crypto_secretbox_xsalsa20poly1305_MACBYTES; +} + +size_t +crypto_secretbox_xsalsa20poly1305_messagebytes_max(void) +{ + return crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX; +} + +void +crypto_secretbox_xsalsa20poly1305_keygen(unsigned char k[crypto_secretbox_xsalsa20poly1305_KEYBYTES]) +{ + randombytes_buf(k, crypto_secretbox_xsalsa20poly1305_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c b/libs/libsodium/src/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c new file mode 100644 index 0000000000..ef000d16c7 --- /dev/null +++ b/libs/libsodium/src/crypto_secretstream/xchacha20poly1305/secretstream_xchacha20poly1305.c @@ -0,0 +1,311 @@ +#include +#include +#include +#include + +#include "core.h" +#include "crypto_aead_chacha20poly1305.h" +#include "crypto_aead_xchacha20poly1305.h" +#include "crypto_core_hchacha20.h" +#include "crypto_onetimeauth_poly1305.h" +#include "crypto_secretstream_xchacha20poly1305.h" +#include "randombytes.h" +#include "utils.h" + +#include "private/common.h" + +#define crypto_secretstream_xchacha20poly1305_COUNTERBYTES 4U +#define crypto_secretstream_xchacha20poly1305_INONCEBYTES 8U + +#define STATE_COUNTER(STATE) ((STATE)->nonce) +#define STATE_INONCE(STATE) ((STATE)->nonce + \ + crypto_secretstream_xchacha20poly1305_COUNTERBYTES) + +static const unsigned char _pad0[16] = { 0 }; + +static inline void +_crypto_secretstream_xchacha20poly1305_counter_reset + (crypto_secretstream_xchacha20poly1305_state *state) +{ + memset(STATE_COUNTER(state), 0, + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + STATE_COUNTER(state)[0] = 1; +} + +void +crypto_secretstream_xchacha20poly1305_keygen + (unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) +{ + randombytes_buf(k, crypto_secretstream_xchacha20poly1305_KEYBYTES); +} + +int +crypto_secretstream_xchacha20poly1305_init_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char out[crypto_secretstream_xchacha20poly1305_HEADERBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) +{ + COMPILER_ASSERT(crypto_secretstream_xchacha20poly1305_HEADERBYTES == + crypto_core_hchacha20_INPUTBYTES + + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + COMPILER_ASSERT(crypto_secretstream_xchacha20poly1305_HEADERBYTES == + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES); + COMPILER_ASSERT(sizeof state->nonce == + crypto_secretstream_xchacha20poly1305_INONCEBYTES + + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + + randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES); + crypto_core_hchacha20(state->k, out, k, NULL); + _crypto_secretstream_xchacha20poly1305_counter_reset(state); + memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + memset(state->_pad, 0, sizeof state->_pad); + + return 0; +} + +int +crypto_secretstream_xchacha20poly1305_init_pull + (crypto_secretstream_xchacha20poly1305_state *state, + const unsigned char in[crypto_secretstream_xchacha20poly1305_HEADERBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]) +{ + crypto_core_hchacha20(state->k, in, k, NULL); + _crypto_secretstream_xchacha20poly1305_counter_reset(state); + memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + memset(state->_pad, 0, sizeof state->_pad); + + return 0; +} + +void +crypto_secretstream_xchacha20poly1305_rekey + (crypto_secretstream_xchacha20poly1305_state *state) +{ + unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + + crypto_secretstream_xchacha20poly1305_INONCEBYTES]; + size_t i; + + for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { + new_key_and_inonce[i] = state->k[i]; + } + for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { + new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] = + STATE_INONCE(state)[i]; + } + crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce, + sizeof new_key_and_inonce, + state->nonce, state->k); + for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { + state->k[i] = new_key_and_inonce[i]; + } + for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { + STATE_INONCE(state)[i] = + new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i]; + } + _crypto_secretstream_xchacha20poly1305_counter_reset(state); +} + +int +crypto_secretstream_xchacha20poly1305_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *out, unsigned long long *outlen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, unsigned char tag) +{ + crypto_onetimeauth_poly1305_state poly1305_state; + unsigned char block[64U]; + unsigned char slen[8U]; + unsigned char *c; + unsigned char *mac; + + if (outlen_p != NULL) { + *outlen_p = 0U; + } + if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); + crypto_onetimeauth_poly1305_init(&poly1305_state, block); + sodium_memzero(block, sizeof block); + + crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, + (0x10 - adlen) & 0xf); + memset(block, 0, sizeof block); + block[0] = tag; + + crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, + state->nonce, 1U, state->k); + crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); + out[0] = block[0]; + + c = out + (sizeof tag); + crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k); + crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); + crypto_onetimeauth_poly1305_update + (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); + + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + STORE64_LE(slen, (sizeof block) + mlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + + mac = c + mlen; + crypto_onetimeauth_poly1305_final(&poly1305_state, mac); + sodium_memzero(&poly1305_state, sizeof poly1305_state); + + COMPILER_ASSERT(crypto_onetimeauth_poly1305_BYTES >= + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + XOR_BUF(STATE_INONCE(state), mac, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + sodium_increment(STATE_COUNTER(state), + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || + sodium_is_zero(STATE_COUNTER(state), + crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { + crypto_secretstream_xchacha20poly1305_rekey(state); + } + if (outlen_p != NULL) { + *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen; + } + return 0; +} + +int +crypto_secretstream_xchacha20poly1305_pull + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p, + const unsigned char *in, unsigned long long inlen, + const unsigned char *ad, unsigned long long adlen) +{ + crypto_onetimeauth_poly1305_state poly1305_state; + unsigned char block[64U]; + unsigned char slen[8U]; + unsigned char mac[crypto_onetimeauth_poly1305_BYTES]; + const unsigned char *c; + const unsigned char *stored_mac; + unsigned long long mlen; + unsigned char tag; + + if (mlen_p != NULL) { + *mlen_p = 0U; + } + if (tag_p != NULL) { + *tag_p = 0xff; + } + if (inlen < crypto_secretstream_xchacha20poly1305_ABYTES) { + return -1; + } + mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES; + if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); + crypto_onetimeauth_poly1305_init(&poly1305_state, block); + sodium_memzero(block, sizeof block); + + crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, + (0x10 - adlen) & 0xf); + + memset(block, 0, sizeof block); + block[0] = in[0]; + crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, + state->nonce, 1U, state->k); + tag = block[0]; + block[0] = in[0]; + crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); + + c = in + (sizeof tag); + crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); + crypto_onetimeauth_poly1305_update + (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); + + STORE64_LE(slen, (uint64_t) adlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + STORE64_LE(slen, (sizeof block) + mlen); + crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); + + crypto_onetimeauth_poly1305_final(&poly1305_state, mac); + sodium_memzero(&poly1305_state, sizeof poly1305_state); + + stored_mac = c + mlen; + if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) { + sodium_memzero(mac, sizeof mac); + return -1; + } + + crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k); + XOR_BUF(STATE_INONCE(state), mac, + crypto_secretstream_xchacha20poly1305_INONCEBYTES); + sodium_increment(STATE_COUNTER(state), + crypto_secretstream_xchacha20poly1305_COUNTERBYTES); + if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || + sodium_is_zero(STATE_COUNTER(state), + crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { + crypto_secretstream_xchacha20poly1305_rekey(state); + } + if (mlen_p != NULL) { + *mlen_p = mlen; + } + if (tag_p != NULL) { + *tag_p = tag; + } + return 0; +} + +size_t +crypto_secretstream_xchacha20poly1305_statebytes(void) +{ + return sizeof(crypto_secretstream_xchacha20poly1305_state); +} + +size_t +crypto_secretstream_xchacha20poly1305_abytes(void) +{ + return crypto_secretstream_xchacha20poly1305_ABYTES; +} + +size_t +crypto_secretstream_xchacha20poly1305_headerbytes(void) +{ + return crypto_secretstream_xchacha20poly1305_HEADERBYTES; +} + +size_t +crypto_secretstream_xchacha20poly1305_keybytes(void) +{ + return crypto_secretstream_xchacha20poly1305_KEYBYTES; +} + +size_t +crypto_secretstream_xchacha20poly1305_messagebytes_max(void) +{ + return crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX; +} + +unsigned char +crypto_secretstream_xchacha20poly1305_tag_message(void) +{ + return crypto_secretstream_xchacha20poly1305_TAG_MESSAGE; +} + +unsigned char +crypto_secretstream_xchacha20poly1305_tag_push(void) +{ + return crypto_secretstream_xchacha20poly1305_TAG_PUSH; +} + +unsigned char +crypto_secretstream_xchacha20poly1305_tag_rekey(void) +{ + return crypto_secretstream_xchacha20poly1305_TAG_REKEY; +} + +unsigned char +crypto_secretstream_xchacha20poly1305_tag_final(void) +{ + return crypto_secretstream_xchacha20poly1305_TAG_FINAL; +} diff --git a/libs/libsodium/src/crypto_shorthash/crypto_shorthash.c b/libs/libsodium/src/crypto_shorthash/crypto_shorthash.c new file mode 100644 index 0000000000..95f52f83ba --- /dev/null +++ b/libs/libsodium/src/crypto_shorthash/crypto_shorthash.c @@ -0,0 +1,34 @@ + +#include "crypto_shorthash.h" +#include "randombytes.h" + +size_t +crypto_shorthash_bytes(void) +{ + return crypto_shorthash_BYTES; +} + +size_t +crypto_shorthash_keybytes(void) +{ + return crypto_shorthash_KEYBYTES; +} + +const char * +crypto_shorthash_primitive(void) +{ + return crypto_shorthash_PRIMITIVE; +} + +int +crypto_shorthash(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + return crypto_shorthash_siphash24(out, in, inlen, k); +} + +void +crypto_shorthash_keygen(unsigned char k[crypto_shorthash_KEYBYTES]) +{ + randombytes_buf(k, crypto_shorthash_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c b/libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c new file mode 100644 index 0000000000..0c173d4c89 --- /dev/null +++ b/libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphash24_ref.c @@ -0,0 +1,65 @@ +#include "crypto_shorthash_siphash24.h" +#include "private/common.h" +#include "shorthash_siphash_ref.h" + +int +crypto_shorthash_siphash24(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + /* "somepseudorandomlygeneratedbytes" */ + uint64_t v0 = 0x736f6d6570736575ULL; + uint64_t v1 = 0x646f72616e646f6dULL; + uint64_t v2 = 0x6c7967656e657261ULL; + uint64_t v3 = 0x7465646279746573ULL; + uint64_t b; + uint64_t k0 = LOAD64_LE(k); + uint64_t k1 = LOAD64_LE(k + 8); + uint64_t m; + const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); + const int left = inlen & 7; + + b = ((uint64_t) inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + for (; in != end; in += 8) { + m = LOAD64_LE(in); + v3 ^= m; + SIPROUND; + SIPROUND; + v0 ^= m; + } + switch (left) { + case 7: + b |= ((uint64_t) in[6]) << 48; + case 6: + b |= ((uint64_t) in[5]) << 40; + case 5: + b |= ((uint64_t) in[4]) << 32; + case 4: + b |= ((uint64_t) in[3]) << 24; + case 3: + b |= ((uint64_t) in[2]) << 16; + case 2: + b |= ((uint64_t) in[1]) << 8; + case 1: + b |= ((uint64_t) in[0]); + break; + case 0: + break; + } + v3 ^= b; + SIPROUND; + SIPROUND; + v0 ^= b; + v2 ^= 0xff; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + b = v0 ^ v1 ^ v2 ^ v3; + STORE64_LE(out, b); + + return 0; +} diff --git a/libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphash_ref.h b/libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphash_ref.h new file mode 100644 index 0000000000..3f9a38b510 --- /dev/null +++ b/libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphash_ref.h @@ -0,0 +1,24 @@ +#ifndef shorthash_siphash_H +#define shorthash_siphash_H + +#include "private/common.h" + +#define SIPROUND \ + do { \ + v0 += v1; \ + v1 = ROTL64(v1, 13); \ + v1 ^= v0; \ + v0 = ROTL64(v0, 32); \ + v2 += v3; \ + v3 = ROTL64(v3, 16); \ + v3 ^= v2; \ + v0 += v3; \ + v3 = ROTL64(v3, 21); \ + v3 ^= v0; \ + v2 += v1; \ + v1 = ROTL64(v1, 17); \ + v1 ^= v2; \ + v2 = ROTL64(v2, 32); \ + } while (0) + +#endif diff --git a/libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c b/libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c new file mode 100644 index 0000000000..20480d0d5f --- /dev/null +++ b/libs/libsodium/src/crypto_shorthash/siphash24/ref/shorthash_siphashx24_ref.c @@ -0,0 +1,71 @@ +#include "crypto_shorthash_siphash24.h" +#include "private/common.h" +#include "shorthash_siphash_ref.h" + +int +crypto_shorthash_siphashx24(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) +{ + uint64_t v0 = 0x736f6d6570736575ULL; + uint64_t v1 = 0x646f72616e646f83ULL; + uint64_t v2 = 0x6c7967656e657261ULL; + uint64_t v3 = 0x7465646279746573ULL; + uint64_t b; + uint64_t k0 = LOAD64_LE(k); + uint64_t k1 = LOAD64_LE(k + 8); + uint64_t m; + const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); + const int left = inlen & 7; + + b = ((uint64_t) inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + for (; in != end; in += 8) { + m = LOAD64_LE(in); + v3 ^= m; + SIPROUND; + SIPROUND; + v0 ^= m; + } + switch (left) { + case 7: + b |= ((uint64_t) in[6]) << 48; + case 6: + b |= ((uint64_t) in[5]) << 40; + case 5: + b |= ((uint64_t) in[4]) << 32; + case 4: + b |= ((uint64_t) in[3]) << 24; + case 3: + b |= ((uint64_t) in[2]) << 16; + case 2: + b |= ((uint64_t) in[1]) << 8; + case 1: + b |= ((uint64_t) in[0]); + break; + case 0: + break; + } + v3 ^= b; + SIPROUND; + SIPROUND; + v0 ^= b; + v2 ^= 0xee; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + b = v0 ^ v1 ^ v2 ^ v3; + STORE64_LE(out, b); + v1 ^= 0xdd; + SIPROUND; + SIPROUND; + SIPROUND; + SIPROUND; + b = v0 ^ v1 ^ v2 ^ v3; + STORE64_LE(out + 8, b); + + return 0; +} diff --git a/libs/libsodium/src/crypto_shorthash/siphash24/shorthash_siphash24.c b/libs/libsodium/src/crypto_shorthash/siphash24/shorthash_siphash24.c new file mode 100644 index 0000000000..e2cea7761e --- /dev/null +++ b/libs/libsodium/src/crypto_shorthash/siphash24/shorthash_siphash24.c @@ -0,0 +1,11 @@ +#include "crypto_shorthash_siphash24.h" + +size_t +crypto_shorthash_siphash24_bytes(void) { + return crypto_shorthash_siphash24_BYTES; +} + +size_t +crypto_shorthash_siphash24_keybytes(void) { + return crypto_shorthash_siphash24_KEYBYTES; +} diff --git a/libs/libsodium/src/crypto_shorthash/siphash24/shorthash_siphashx24.c b/libs/libsodium/src/crypto_shorthash/siphash24/shorthash_siphashx24.c new file mode 100644 index 0000000000..2d487dbb6f --- /dev/null +++ b/libs/libsodium/src/crypto_shorthash/siphash24/shorthash_siphashx24.c @@ -0,0 +1,11 @@ +#include "crypto_shorthash_siphash24.h" + +size_t +crypto_shorthash_siphashx24_bytes(void) { + return crypto_shorthash_siphashx24_BYTES; +} + +size_t +crypto_shorthash_siphashx24_keybytes(void) { + return crypto_shorthash_siphashx24_KEYBYTES; +} diff --git a/libs/libsodium/src/crypto_sign/crypto_sign.c b/libs/libsodium/src/crypto_sign/crypto_sign.c new file mode 100644 index 0000000000..127072f726 --- /dev/null +++ b/libs/libsodium/src/crypto_sign/crypto_sign.c @@ -0,0 +1,115 @@ + +#include "crypto_sign.h" + +size_t +crypto_sign_statebytes(void) +{ + return sizeof(crypto_sign_state); +} + +size_t +crypto_sign_bytes(void) +{ + return crypto_sign_BYTES; +} + +size_t +crypto_sign_seedbytes(void) +{ + return crypto_sign_SEEDBYTES; +} + +size_t +crypto_sign_publickeybytes(void) +{ + return crypto_sign_PUBLICKEYBYTES; +} + +size_t +crypto_sign_secretkeybytes(void) +{ + return crypto_sign_SECRETKEYBYTES; +} + +size_t +crypto_sign_messagebytes_max(void) +{ + return crypto_sign_MESSAGEBYTES_MAX; +} + +const char * +crypto_sign_primitive(void) +{ + return crypto_sign_PRIMITIVE; +} + +int +crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, + const unsigned char *seed) +{ + return crypto_sign_ed25519_seed_keypair(pk, sk, seed); +} + +int +crypto_sign_keypair(unsigned char *pk, unsigned char *sk) +{ + return crypto_sign_ed25519_keypair(pk, sk); +} + +int +crypto_sign(unsigned char *sm, unsigned long long *smlen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk) +{ + return crypto_sign_ed25519(sm, smlen_p, m, mlen, sk); +} + +int +crypto_sign_open(unsigned char *m, unsigned long long *mlen_p, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk) +{ + return crypto_sign_ed25519_open(m, mlen_p, sm, smlen, pk); +} + +int +crypto_sign_detached(unsigned char *sig, unsigned long long *siglen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk) +{ + return crypto_sign_ed25519_detached(sig, siglen_p, m, mlen, sk); +} + +int +crypto_sign_verify_detached(const unsigned char *sig, const unsigned char *m, + unsigned long long mlen, const unsigned char *pk) +{ + return crypto_sign_ed25519_verify_detached(sig, m, mlen, pk); +} + +int +crypto_sign_init(crypto_sign_state *state) +{ + return crypto_sign_ed25519ph_init(state); +} + +int +crypto_sign_update(crypto_sign_state *state, const unsigned char *m, + unsigned long long mlen) +{ + return crypto_sign_ed25519ph_update(state, m, mlen); +} + +int +crypto_sign_final_create(crypto_sign_state *state, unsigned char *sig, + unsigned long long *siglen_p, const unsigned char *sk) +{ + return crypto_sign_ed25519ph_final_create(state, sig, siglen_p, sk); +} + +int +crypto_sign_final_verify(crypto_sign_state *state, unsigned char *sig, + const unsigned char *pk) +{ + return crypto_sign_ed25519ph_final_verify(state, sig, pk); +} diff --git a/libs/libsodium/src/crypto_sign/ed25519/ref10/keypair.c b/libs/libsodium/src/crypto_sign/ed25519/ref10/keypair.c new file mode 100644 index 0000000000..8bf3cec8fd --- /dev/null +++ b/libs/libsodium/src/crypto_sign/ed25519/ref10/keypair.c @@ -0,0 +1,91 @@ + +#include + +#include "crypto_hash_sha512.h" +#include "crypto_scalarmult_curve25519.h" +#include "crypto_sign_ed25519.h" +#include "sign_ed25519_ref10.h" +#include "private/ed25519_ref10.h" +#include "randombytes.h" +#include "utils.h" + +int +crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk, + const unsigned char *seed) +{ + ge25519_p3 A; + +#ifdef ED25519_NONDETERMINISTIC + memmove(sk, seed, 32); +#else + crypto_hash_sha512(sk, seed, 32); +#endif + sk[0] &= 248; + sk[31] &= 127; + sk[31] |= 64; + + ge25519_scalarmult_base(&A, sk); + ge25519_p3_tobytes(pk, &A); + + memmove(sk, seed, 32); + memmove(sk + 32, pk, 32); + + return 0; +} + +int +crypto_sign_ed25519_keypair(unsigned char *pk, unsigned char *sk) +{ + unsigned char seed[32]; + int ret; + + randombytes_buf(seed, sizeof seed); + ret = crypto_sign_ed25519_seed_keypair(pk, sk, seed); + sodium_memzero(seed, sizeof seed); + + return ret; +} + +int +crypto_sign_ed25519_pk_to_curve25519(unsigned char *curve25519_pk, + const unsigned char *ed25519_pk) +{ + ge25519_p3 A; + fe25519 x; + fe25519 one_minus_y; + + if (ge25519_has_small_order(ed25519_pk) != 0 || + ge25519_frombytes_negate_vartime(&A, ed25519_pk) != 0 || + ge25519_is_on_main_subgroup(&A) == 0) { + return -1; + } + fe25519_1(one_minus_y); + fe25519_sub(one_minus_y, one_minus_y, A.Y); + fe25519_invert(one_minus_y, one_minus_y); + fe25519_1(x); + fe25519_add(x, x, A.Y); + fe25519_mul(x, x, one_minus_y); + fe25519_tobytes(curve25519_pk, x); + + return 0; +} + +int +crypto_sign_ed25519_sk_to_curve25519(unsigned char *curve25519_sk, + const unsigned char *ed25519_sk) +{ + unsigned char h[crypto_hash_sha512_BYTES]; + +#ifdef ED25519_NONDETERMINISTIC + memcpy(h, ed25519_sk, 32); +#else + crypto_hash_sha512(h, ed25519_sk, 32); +#endif + h[0] &= 248; + h[31] &= 127; + h[31] |= 64; + memcpy(curve25519_sk, h, crypto_scalarmult_curve25519_BYTES); + sodium_memzero(h, sizeof h); + + return 0; +} diff --git a/libs/libsodium/src/crypto_sign/ed25519/ref10/obsolete.c b/libs/libsodium/src/crypto_sign/ed25519/ref10/obsolete.c new file mode 100644 index 0000000000..03440cfa75 --- /dev/null +++ b/libs/libsodium/src/crypto_sign/ed25519/ref10/obsolete.c @@ -0,0 +1,116 @@ + +#include +#include +#include + +#include "crypto_hash_sha512.h" +#include "crypto_sign_edwards25519sha512batch.h" +#include "crypto_verify_32.h" +#include "private/ed25519_ref10.h" +#include "randombytes.h" +#include "utils.h" + +int +crypto_sign_edwards25519sha512batch_keypair(unsigned char *pk, + unsigned char *sk) +{ + ge25519_p3 A; + + randombytes_buf(sk, 32); + crypto_hash_sha512(sk, sk, 32); + sk[0] &= 248; + sk[31] &= 127; + sk[31] |= 64; + ge25519_scalarmult_base(&A, sk); + ge25519_p3_tobytes(pk, &A); + + return 0; +} + +int +crypto_sign_edwards25519sha512batch(unsigned char *sm, + unsigned long long *smlen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *sk) +{ + crypto_hash_sha512_state hs; + unsigned char nonce[64]; + unsigned char hram[64]; + unsigned char sig[64]; + ge25519_p3 A; + ge25519_p3 R; + + crypto_hash_sha512_init(&hs); + crypto_hash_sha512_update(&hs, sk + 32, 32); + crypto_hash_sha512_update(&hs, m, mlen); + crypto_hash_sha512_final(&hs, nonce); + ge25519_scalarmult_base(&A, sk); + ge25519_p3_tobytes(sig + 32, &A); + sc25519_reduce(nonce); + ge25519_scalarmult_base(&R, nonce); + ge25519_p3_tobytes(sig, &R); + crypto_hash_sha512_init(&hs); + crypto_hash_sha512_update(&hs, sig, 32); + crypto_hash_sha512_update(&hs, m, mlen); + crypto_hash_sha512_final(&hs, hram); + sc25519_reduce(hram); + sc25519_muladd(sig + 32, hram, nonce, sk); + sodium_memzero(hram, sizeof hram); + memmove(sm + 32, m, (size_t) mlen); + memcpy(sm, sig, 32); + memcpy(sm + 32 + mlen, sig + 32, 32); + *smlen_p = mlen + 64U; + + return 0; +} + +int +crypto_sign_edwards25519sha512batch_open(unsigned char *m, + unsigned long long *mlen_p, + const unsigned char *sm, + unsigned long long smlen, + const unsigned char *pk) +{ + unsigned char h[64]; + unsigned char t1[32], t2[32]; + unsigned long long mlen; + ge25519_cached Ai; + ge25519_p1p1 csa; + ge25519_p2 cs; + ge25519_p3 A; + ge25519_p3 R; + ge25519_p3 cs3; + + *mlen_p = 0; + if (smlen < 64 || smlen - 64 > crypto_sign_edwards25519sha512batch_MESSAGEBYTES_MAX) { + return -1; + } + mlen = smlen - 64; + if (sm[smlen - 1] & 224) { + return -1; + } + if (ge25519_has_small_order(pk) != 0 || + ge25519_frombytes_negate_vartime(&A, pk) != 0 || + ge25519_has_small_order(sm) != 0 || + ge25519_frombytes_negate_vartime(&R, sm) != 0) { + return -1; + } + ge25519_p3_to_cached(&Ai, &A); + crypto_hash_sha512(h, sm, mlen + 32); + sc25519_reduce(h); + ge25519_scalarmult(&cs3, h, &R); + ge25519_add(&csa, &cs3, &Ai); + ge25519_p1p1_to_p2(&cs, &csa); + ge25519_tobytes(t1, &cs); + t1[31] ^= 1 << 7; + ge25519_scalarmult_base(&R, sm + 32 + mlen); + ge25519_p3_tobytes(t2, &R); + if (crypto_verify_32(t1, t2) != 0) { + return -1; + } + *mlen_p = mlen; + memmove(m, sm + 32, mlen); + + return 0; +} diff --git a/libs/libsodium/src/crypto_sign/ed25519/ref10/open.c b/libs/libsodium/src/crypto_sign/ed25519/ref10/open.c new file mode 100644 index 0000000000..c9e8843c1e --- /dev/null +++ b/libs/libsodium/src/crypto_sign/ed25519/ref10/open.c @@ -0,0 +1,93 @@ + +#include +#include +#include + +#include "crypto_hash_sha512.h" +#include "crypto_sign_ed25519.h" +#include "crypto_verify_32.h" +#include "sign_ed25519_ref10.h" +#include "private/ed25519_ref10.h" +#include "utils.h" + +int +_crypto_sign_ed25519_verify_detached(const unsigned char *sig, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk, + int prehashed) +{ + crypto_hash_sha512_state hs; + unsigned char h[64]; + unsigned char rcheck[32]; + ge25519_p3 A; + ge25519_p2 R; + +#ifndef ED25519_COMPAT + if (sc25519_is_canonical(sig + 32) == 0 || + ge25519_has_small_order(sig) != 0) { + return -1; + } + if (ge25519_is_canonical(pk) == 0) { + return -1; + } +#else + if (sig[63] & 224) { + return -1; + } +#endif + if (ge25519_has_small_order(pk) != 0 || + ge25519_frombytes_negate_vartime(&A, pk) != 0) { + return -1; + } + _crypto_sign_ed25519_ref10_hinit(&hs, prehashed); + crypto_hash_sha512_update(&hs, sig, 32); + crypto_hash_sha512_update(&hs, pk, 32); + crypto_hash_sha512_update(&hs, m, mlen); + crypto_hash_sha512_final(&hs, h); + sc25519_reduce(h); + + ge25519_double_scalarmult_vartime(&R, h, &A, sig + 32); + ge25519_tobytes(rcheck, &R); + + return crypto_verify_32(rcheck, sig) | (-(rcheck == sig)) | + sodium_memcmp(sig, rcheck, 32); +} + +int +crypto_sign_ed25519_verify_detached(const unsigned char *sig, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk) +{ + return _crypto_sign_ed25519_verify_detached(sig, m, mlen, pk, 0); +} + +int +crypto_sign_ed25519_open(unsigned char *m, unsigned long long *mlen_p, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk) +{ + unsigned long long mlen; + + if (smlen < 64 || smlen - 64 > crypto_sign_ed25519_MESSAGEBYTES_MAX) { + goto badsig; + } + mlen = smlen - 64; + if (crypto_sign_ed25519_verify_detached(sm, sm + 64, mlen, pk) != 0) { + memset(m, 0, mlen); + goto badsig; + } + if (mlen_p != NULL) { + *mlen_p = mlen; + } + memmove(m, sm + 64, mlen); + + return 0; + +badsig: + if (mlen_p != NULL) { + *mlen_p = 0; + } + return -1; +} diff --git a/libs/libsodium/src/crypto_sign/ed25519/ref10/sign.c b/libs/libsodium/src/crypto_sign/ed25519/ref10/sign.c new file mode 100644 index 0000000000..4df90bddd9 --- /dev/null +++ b/libs/libsodium/src/crypto_sign/ed25519/ref10/sign.c @@ -0,0 +1,144 @@ + +#include + +#include "crypto_hash_sha512.h" +#include "crypto_sign_ed25519.h" +#include "sign_ed25519_ref10.h" +#include "private/ed25519_ref10.h" +#include "randombytes.h" +#include "utils.h" + +void +_crypto_sign_ed25519_ref10_hinit(crypto_hash_sha512_state *hs, int prehashed) +{ + static const unsigned char DOM2PREFIX[32 + 2] = { + 'S', 'i', 'g', 'E', 'd', '2', '5', '5', '1', '9', ' ', + 'n', 'o', ' ', + 'E', 'd', '2', '5', '5', '1', '9', ' ', + 'c', 'o', 'l', 'l', 'i', 's', 'i', 'o', 'n', 's', 1, 0 + }; + + crypto_hash_sha512_init(hs); + if (prehashed) { + crypto_hash_sha512_update(hs, DOM2PREFIX, sizeof DOM2PREFIX); + } +} + +static inline void +_crypto_sign_ed25519_clamp(unsigned char k[32]) +{ + k[0] &= 248; + k[31] &= 127; + k[31] |= 64; +} + +#ifdef ED25519_NONDETERMINISTIC +/* r = hash(B || empty_labelset || Z || pad1 || k || pad2 || empty_labelset || K || extra || M) (mod q) */ +static void +_crypto_sign_ed25519_synthetic_r_hv(crypto_hash_sha512_state *hs, + unsigned char Z[32], + const unsigned char sk[64]) +{ + static const unsigned char B[32] = { + 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + }; + static const unsigned char zeros[128] = { 0x00 }; + static const unsigned char empty_labelset[3] = { 0x02, 0x00, 0x00 }; + + crypto_hash_sha512_update(hs, B, 32); + crypto_hash_sha512_update(hs, empty_labelset, 3); + randombytes_buf(Z, 32); + crypto_hash_sha512_update(hs, Z, 32); + crypto_hash_sha512_update(hs, zeros, 128 - (32 + 3 + 32) % 128); + crypto_hash_sha512_update(hs, sk, 32); + crypto_hash_sha512_update(hs, zeros, 128 - 32 % 128); + crypto_hash_sha512_update(hs, empty_labelset, 3); + crypto_hash_sha512_update(hs, sk + 32, 32); + /* empty extra */ +} +#endif + +int +_crypto_sign_ed25519_detached(unsigned char *sig, unsigned long long *siglen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk, int prehashed) +{ + crypto_hash_sha512_state hs; + unsigned char az[64]; + unsigned char nonce[64]; + unsigned char hram[64]; + ge25519_p3 R; + + _crypto_sign_ed25519_ref10_hinit(&hs, prehashed); + +#ifdef ED25519_NONDETERMINISTIC + memcpy(az, sk, 32); + _crypto_sign_ed25519_synthetic_r_hv(&hs, nonce, az); +#else + crypto_hash_sha512(az, sk, 32); + crypto_hash_sha512_update(&hs, az + 32, 32); +#endif + + crypto_hash_sha512_update(&hs, m, mlen); + crypto_hash_sha512_final(&hs, nonce); + + memmove(sig + 32, sk + 32, 32); + + sc25519_reduce(nonce); + ge25519_scalarmult_base(&R, nonce); + ge25519_p3_tobytes(sig, &R); + + _crypto_sign_ed25519_ref10_hinit(&hs, prehashed); + crypto_hash_sha512_update(&hs, sig, 64); + crypto_hash_sha512_update(&hs, m, mlen); + crypto_hash_sha512_final(&hs, hram); + + sc25519_reduce(hram); + _crypto_sign_ed25519_clamp(az); + sc25519_muladd(sig + 32, hram, az, nonce); + + sodium_memzero(az, sizeof az); + sodium_memzero(nonce, sizeof nonce); + + if (siglen_p != NULL) { + *siglen_p = 64U; + } + return 0; +} + +int +crypto_sign_ed25519_detached(unsigned char *sig, unsigned long long *siglen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk) +{ + return _crypto_sign_ed25519_detached(sig, siglen_p, m, mlen, sk, 0); +} + +int +crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk) +{ + unsigned long long siglen; + + memmove(sm + crypto_sign_ed25519_BYTES, m, mlen); + /* LCOV_EXCL_START */ + if (crypto_sign_ed25519_detached( + sm, &siglen, sm + crypto_sign_ed25519_BYTES, mlen, sk) != 0 || + siglen != crypto_sign_ed25519_BYTES) { + if (smlen_p != NULL) { + *smlen_p = 0; + } + memset(sm, 0, mlen + crypto_sign_ed25519_BYTES); + return -1; + } + /* LCOV_EXCL_STOP */ + + if (smlen_p != NULL) { + *smlen_p = mlen + siglen; + } + return 0; +} diff --git a/libs/libsodium/src/crypto_sign/ed25519/ref10/sign_ed25519_ref10.h b/libs/libsodium/src/crypto_sign/ed25519/ref10/sign_ed25519_ref10.h new file mode 100644 index 0000000000..29f45a8544 --- /dev/null +++ b/libs/libsodium/src/crypto_sign/ed25519/ref10/sign_ed25519_ref10.h @@ -0,0 +1,18 @@ +#ifndef sign_ed25519_ref10_H +#define sign_ed25519_ref10_H + +void _crypto_sign_ed25519_ref10_hinit(crypto_hash_sha512_state *hs, + int prehashed); + +int _crypto_sign_ed25519_detached(unsigned char *sig, + unsigned long long *siglen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *sk, int prehashed); + +int _crypto_sign_ed25519_verify_detached(const unsigned char *sig, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk, + int prehashed); +#endif diff --git a/libs/libsodium/src/crypto_sign/ed25519/sign_ed25519.c b/libs/libsodium/src/crypto_sign/ed25519/sign_ed25519.c new file mode 100644 index 0000000000..8a69513ede --- /dev/null +++ b/libs/libsodium/src/crypto_sign/ed25519/sign_ed25519.c @@ -0,0 +1,97 @@ + +#include + +#include "crypto_hash_sha512.h" +#include "crypto_sign_ed25519.h" +#include "ref10/sign_ed25519_ref10.h" + +size_t +crypto_sign_ed25519ph_statebytes(void) +{ + return sizeof(crypto_sign_ed25519ph_state); +} + +size_t +crypto_sign_ed25519_bytes(void) +{ + return crypto_sign_ed25519_BYTES; +} + +size_t +crypto_sign_ed25519_seedbytes(void) +{ + return crypto_sign_ed25519_SEEDBYTES; +} + +size_t +crypto_sign_ed25519_publickeybytes(void) +{ + return crypto_sign_ed25519_PUBLICKEYBYTES; +} + +size_t +crypto_sign_ed25519_secretkeybytes(void) +{ + return crypto_sign_ed25519_SECRETKEYBYTES; +} + +size_t +crypto_sign_ed25519_messagebytes_max(void) +{ + return crypto_sign_ed25519_MESSAGEBYTES_MAX; +} + +int +crypto_sign_ed25519_sk_to_seed(unsigned char *seed, const unsigned char *sk) +{ + memmove(seed, sk, crypto_sign_ed25519_SEEDBYTES); + + return 0; +} + +int +crypto_sign_ed25519_sk_to_pk(unsigned char *pk, const unsigned char *sk) +{ + memmove(pk, sk + crypto_sign_ed25519_SEEDBYTES, + crypto_sign_ed25519_PUBLICKEYBYTES); + return 0; +} + +int +crypto_sign_ed25519ph_init(crypto_sign_ed25519ph_state *state) +{ + crypto_hash_sha512_init(&state->hs); + return 0; +} + +int +crypto_sign_ed25519ph_update(crypto_sign_ed25519ph_state *state, + const unsigned char *m, unsigned long long mlen) +{ + return crypto_hash_sha512_update(&state->hs, m, mlen); +} + +int +crypto_sign_ed25519ph_final_create(crypto_sign_ed25519ph_state *state, + unsigned char *sig, + unsigned long long *siglen_p, + const unsigned char *sk) +{ + unsigned char ph[crypto_hash_sha512_BYTES]; + + crypto_hash_sha512_final(&state->hs, ph); + + return _crypto_sign_ed25519_detached(sig, siglen_p, ph, sizeof ph, sk, 1); +} + +int +crypto_sign_ed25519ph_final_verify(crypto_sign_ed25519ph_state *state, + unsigned char *sig, + const unsigned char *pk) +{ + unsigned char ph[crypto_hash_sha512_BYTES]; + + crypto_hash_sha512_final(&state->hs, ph); + + return _crypto_sign_ed25519_verify_detached(sig, ph, sizeof ph, pk, 1); +} diff --git a/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c new file mode 100644 index 0000000000..6149af3942 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.c @@ -0,0 +1,180 @@ + +#include +#include +#include + +#include "core.h" +#include "crypto_stream_chacha20.h" +#include "private/common.h" +#include "private/sse2_64_32.h" +#include "utils.h" + +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_EMMINTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# pragma GCC target("sse4.1") +# pragma GCC target("avx2") +# endif + +# include +# include +# include +# include + +# include "../stream_chacha20.h" +# include "chacha20_dolbeau-avx2.h" + +# define ROUNDS 20 + +typedef struct chacha_ctx { + uint32_t input[16]; +} chacha_ctx; + +static void +chacha_keysetup(chacha_ctx *ctx, const uint8_t *k) +{ + ctx->input[0] = 0x61707865; + ctx->input[1] = 0x3320646e; + ctx->input[2] = 0x79622d32; + ctx->input[3] = 0x6b206574; + ctx->input[4] = LOAD32_LE(k + 0); + ctx->input[5] = LOAD32_LE(k + 4); + ctx->input[6] = LOAD32_LE(k + 8); + ctx->input[7] = LOAD32_LE(k + 12); + ctx->input[8] = LOAD32_LE(k + 16); + ctx->input[9] = LOAD32_LE(k + 20); + ctx->input[10] = LOAD32_LE(k + 24); + ctx->input[11] = LOAD32_LE(k + 28); +} + +static void +chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter + 0); + ctx->input[13] = counter == NULL ? 0 : LOAD32_LE(counter + 4); + ctx->input[14] = LOAD32_LE(iv + 0); + ctx->input[15] = LOAD32_LE(iv + 4); +} + +static void +chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter); + ctx->input[13] = LOAD32_LE(iv + 0); + ctx->input[14] = LOAD32_LE(iv + 4); + ctx->input[15] = LOAD32_LE(iv + 8); +} + +static void +chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t * const x = &ctx->input[0]; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } + if (bytes > crypto_stream_chacha20_MESSAGEBYTES_MAX) { + sodium_misuse(); + } +# include "u8.h" +# include "u4.h" +# include "u1.h" +# include "u0.h" +} + +static int +stream_ref(unsigned char *c, unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + struct chacha_ctx ctx; + + if (!clen) { + return 0; + } + COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8); + chacha_keysetup(&ctx, k); + chacha_ivsetup(&ctx, n, NULL); + memset(c, 0, clen); + chacha20_encrypt_bytes(&ctx, c, c, clen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_ietf_ref(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + struct chacha_ctx ctx; + + if (!clen) { + return 0; + } + COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8); + chacha_keysetup(&ctx, k); + chacha_ietf_ivsetup(&ctx, n, NULL); + memset(c, 0, clen); + chacha20_encrypt_bytes(&ctx, c, c, clen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (!mlen) { + return 0; + } + ic_high = (uint32_t) (ic >> 32); + ic_low = (uint32_t) ic; + STORE32_LE(&ic_bytes[0], ic_low); + STORE32_LE(&ic_bytes[4], ic_high); + chacha_keysetup(&ctx, k); + chacha_ivsetup(&ctx, n, ic_bytes); + chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_ietf_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint32_t ic, const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[4]; + + if (!mlen) { + return 0; + } + STORE32_LE(ic_bytes, ic); + chacha_keysetup(&ctx, k); + chacha_ietf_ivsetup(&ctx, n, ic_bytes); + chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_avx2_implementation = { + SODIUM_C99(.stream =) stream_ref, + SODIUM_C99(.stream_ietf =) stream_ietf_ref, + SODIUM_C99(.stream_xor_ic =) stream_ref_xor_ic, + SODIUM_C99(.stream_ietf_xor_ic =) stream_ietf_ref_xor_ic + }; + +#endif diff --git a/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.h b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.h new file mode 100644 index 0000000000..45eb98d797 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-avx2.h @@ -0,0 +1,8 @@ + +#include + +#include "../stream_chacha20.h" +#include "crypto_stream_chacha20.h" + +extern struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_avx2_implementation; diff --git a/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c new file mode 100644 index 0000000000..b7b9aa4ad3 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.c @@ -0,0 +1,174 @@ + +#include +#include +#include + +#include "core.h" +#include "crypto_stream_chacha20.h" +#include "private/common.h" +#include "private/sse2_64_32.h" +#include "utils.h" + +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# endif + +# include +# include + +# include "../stream_chacha20.h" +# include "chacha20_dolbeau-ssse3.h" + +# define ROUNDS 20 + +typedef struct chacha_ctx { + uint32_t input[16]; +} chacha_ctx; + +static void +chacha_keysetup(chacha_ctx *ctx, const uint8_t *k) +{ + ctx->input[0] = 0x61707865; + ctx->input[1] = 0x3320646e; + ctx->input[2] = 0x79622d32; + ctx->input[3] = 0x6b206574; + ctx->input[4] = LOAD32_LE(k + 0); + ctx->input[5] = LOAD32_LE(k + 4); + ctx->input[6] = LOAD32_LE(k + 8); + ctx->input[7] = LOAD32_LE(k + 12); + ctx->input[8] = LOAD32_LE(k + 16); + ctx->input[9] = LOAD32_LE(k + 20); + ctx->input[10] = LOAD32_LE(k + 24); + ctx->input[11] = LOAD32_LE(k + 28); +} + +static void +chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter + 0); + ctx->input[13] = counter == NULL ? 0 : LOAD32_LE(counter + 4); + ctx->input[14] = LOAD32_LE(iv + 0); + ctx->input[15] = LOAD32_LE(iv + 4); +} + +static void +chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter); + ctx->input[13] = LOAD32_LE(iv + 0); + ctx->input[14] = LOAD32_LE(iv + 4); + ctx->input[15] = LOAD32_LE(iv + 8); +} + +static void +chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t * const x = &ctx->input[0]; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } + if (bytes > crypto_stream_chacha20_MESSAGEBYTES_MAX) { + sodium_misuse(); + } +# include "u4.h" +# include "u1.h" +# include "u0.h" +} + +static int +stream_ref(unsigned char *c, unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + struct chacha_ctx ctx; + + if (!clen) { + return 0; + } + COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8); + chacha_keysetup(&ctx, k); + chacha_ivsetup(&ctx, n, NULL); + memset(c, 0, clen); + chacha20_encrypt_bytes(&ctx, c, c, clen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_ietf_ref(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + struct chacha_ctx ctx; + + if (!clen) { + return 0; + } + COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8); + chacha_keysetup(&ctx, k); + chacha_ietf_ivsetup(&ctx, n, NULL); + memset(c, 0, clen); + chacha20_encrypt_bytes(&ctx, c, c, clen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (!mlen) { + return 0; + } + ic_high = (uint32_t) (ic >> 32); + ic_low = (uint32_t) ic; + STORE32_LE(&ic_bytes[0], ic_low); + STORE32_LE(&ic_bytes[4], ic_high); + chacha_keysetup(&ctx, k); + chacha_ivsetup(&ctx, n, ic_bytes); + chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_ietf_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint32_t ic, const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[4]; + + if (!mlen) { + return 0; + } + STORE32_LE(ic_bytes, ic); + chacha_keysetup(&ctx, k); + chacha_ietf_ivsetup(&ctx, n, ic_bytes); + chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_ssse3_implementation = { + SODIUM_C99(.stream =) stream_ref, + SODIUM_C99(.stream_ietf =) stream_ietf_ref, + SODIUM_C99(.stream_xor_ic =) stream_ref_xor_ic, + SODIUM_C99(.stream_ietf_xor_ic =) stream_ietf_ref_xor_ic + }; + +#endif diff --git a/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.h b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.h new file mode 100644 index 0000000000..d67630f6a9 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/chacha20_dolbeau-ssse3.h @@ -0,0 +1,8 @@ + +#include + +#include "../stream_chacha20.h" +#include "crypto_stream_chacha20.h" + +extern struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_dolbeau_ssse3_implementation; diff --git a/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u0.h b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u0.h new file mode 100644 index 0000000000..17c3ff8e08 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u0.h @@ -0,0 +1,86 @@ +if (bytes > 0) { + __m128i x_0, x_1, x_2, x_3; + __m128i t_1; + const __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + const __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + uint8_t partialblock[64]; + + unsigned int i; + + x_0 = _mm_loadu_si128((__m128i*) (x + 0)); + x_1 = _mm_loadu_si128((__m128i*) (x + 4)); + x_2 = _mm_loadu_si128((__m128i*) (x + 8)); + x_3 = _mm_loadu_si128((__m128i*) (x + 12)); + + for (i = 0; i < ROUNDS; i += 2) { + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x93); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x39); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x39); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x93); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + } + x_0 = _mm_add_epi32(x_0, _mm_loadu_si128((__m128i*) (x + 0))); + x_1 = _mm_add_epi32(x_1, _mm_loadu_si128((__m128i*) (x + 4))); + x_2 = _mm_add_epi32(x_2, _mm_loadu_si128((__m128i*) (x + 8))); + x_3 = _mm_add_epi32(x_3, _mm_loadu_si128((__m128i*) (x + 12))); + _mm_storeu_si128((__m128i*) (partialblock + 0), x_0); + _mm_storeu_si128((__m128i*) (partialblock + 16), x_1); + _mm_storeu_si128((__m128i*) (partialblock + 32), x_2); + _mm_storeu_si128((__m128i*) (partialblock + 48), x_3); + + for (i = 0; i < bytes; i++) { + c[i] = m[i] ^ partialblock[i]; + } + + sodium_memzero(partialblock, sizeof partialblock); +} diff --git a/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u1.h b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u1.h new file mode 100644 index 0000000000..867b44bcf2 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u1.h @@ -0,0 +1,98 @@ +while (bytes >= 64) { + __m128i x_0, x_1, x_2, x_3; + __m128i t_1; + const __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + const __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + + uint32_t in12; + uint32_t in13; + int i; + + x_0 = _mm_loadu_si128((__m128i*) (x + 0)); + x_1 = _mm_loadu_si128((__m128i*) (x + 4)); + x_2 = _mm_loadu_si128((__m128i*) (x + 8)); + x_3 = _mm_loadu_si128((__m128i*) (x + 12)); + + for (i = 0; i < ROUNDS; i += 2) { + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x93); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x39); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_3 = _mm_shuffle_epi8(x_3, rot16); + + x_2 = _mm_add_epi32(x_2, x_3); + x_1 = _mm_xor_si128(x_1, x_2); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 12); + t_1 = _mm_srli_epi32(t_1, 20); + x_1 = _mm_xor_si128(x_1, t_1); + + x_0 = _mm_add_epi32(x_0, x_1); + x_3 = _mm_xor_si128(x_3, x_0); + x_0 = _mm_shuffle_epi32(x_0, 0x39); + x_3 = _mm_shuffle_epi8(x_3, rot8); + + x_2 = _mm_add_epi32(x_2, x_3); + x_3 = _mm_shuffle_epi32(x_3, 0x4e); + x_1 = _mm_xor_si128(x_1, x_2); + x_2 = _mm_shuffle_epi32(x_2, 0x93); + + t_1 = x_1; + x_1 = _mm_slli_epi32(x_1, 7); + t_1 = _mm_srli_epi32(t_1, 25); + x_1 = _mm_xor_si128(x_1, t_1); + } + x_0 = _mm_add_epi32(x_0, _mm_loadu_si128((__m128i*) (x + 0))); + x_1 = _mm_add_epi32(x_1, _mm_loadu_si128((__m128i*) (x + 4))); + x_2 = _mm_add_epi32(x_2, _mm_loadu_si128((__m128i*) (x + 8))); + x_3 = _mm_add_epi32(x_3, _mm_loadu_si128((__m128i*) (x + 12))); + x_0 = _mm_xor_si128(x_0, _mm_loadu_si128((__m128i*) (m + 0))); + x_1 = _mm_xor_si128(x_1, _mm_loadu_si128((__m128i*) (m + 16))); + x_2 = _mm_xor_si128(x_2, _mm_loadu_si128((__m128i*) (m + 32))); + x_3 = _mm_xor_si128(x_3, _mm_loadu_si128((__m128i*) (m + 48))); + _mm_storeu_si128((__m128i*) (c + 0), x_0); + _mm_storeu_si128((__m128i*) (c + 16), x_1); + _mm_storeu_si128((__m128i*) (c + 32), x_2); + _mm_storeu_si128((__m128i*) (c + 48), x_3); + + in12 = x[12]; + in13 = x[13]; + in12++; + if (in12 == 0) { + in13++; + } + x[12] = in12; + x[13] = in13; + + bytes -= 64; + c += 64; + m += 64; +} diff --git a/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u4.h b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u4.h new file mode 100644 index 0000000000..3ff8342609 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u4.h @@ -0,0 +1,175 @@ + +#define VEC4_ROT(A, IMM) \ + _mm_or_si128(_mm_slli_epi32(A, IMM), _mm_srli_epi32(A, (32 - IMM))) + +/* same, but replace 2 of the shift/shift/or "rotation" by byte shuffles (8 & + * 16) (better) */ +#define VEC4_QUARTERROUND_SHUFFLE(A, B, C, D) \ + x_##A = _mm_add_epi32(x_##A, x_##B); \ + t_##A = _mm_xor_si128(x_##D, x_##A); \ + x_##D = _mm_shuffle_epi8(t_##A, rot16); \ + x_##C = _mm_add_epi32(x_##C, x_##D); \ + t_##C = _mm_xor_si128(x_##B, x_##C); \ + x_##B = VEC4_ROT(t_##C, 12); \ + x_##A = _mm_add_epi32(x_##A, x_##B); \ + t_##A = _mm_xor_si128(x_##D, x_##A); \ + x_##D = _mm_shuffle_epi8(t_##A, rot8); \ + x_##C = _mm_add_epi32(x_##C, x_##D); \ + t_##C = _mm_xor_si128(x_##B, x_##C); \ + x_##B = VEC4_ROT(t_##C, 7) + +#define VEC4_QUARTERROUND(A, B, C, D) VEC4_QUARTERROUND_SHUFFLE(A, B, C, D) + +if (bytes >= 256) { + /* constant for shuffling bytes (replacing multiple-of-8 rotates) */ + __m128i rot16 = + _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + __m128i rot8 = + _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + + __m128i x_0 = _mm_set1_epi32(x[0]); + __m128i x_1 = _mm_set1_epi32(x[1]); + __m128i x_2 = _mm_set1_epi32(x[2]); + __m128i x_3 = _mm_set1_epi32(x[3]); + __m128i x_4 = _mm_set1_epi32(x[4]); + __m128i x_5 = _mm_set1_epi32(x[5]); + __m128i x_6 = _mm_set1_epi32(x[6]); + __m128i x_7 = _mm_set1_epi32(x[7]); + __m128i x_8 = _mm_set1_epi32(x[8]); + __m128i x_9 = _mm_set1_epi32(x[9]); + __m128i x_10 = _mm_set1_epi32(x[10]); + __m128i x_11 = _mm_set1_epi32(x[11]); + __m128i x_12; + __m128i x_13; + __m128i x_14 = _mm_set1_epi32(x[14]); + __m128i x_15 = _mm_set1_epi32(x[15]); + __m128i orig0 = x_0; + __m128i orig1 = x_1; + __m128i orig2 = x_2; + __m128i orig3 = x_3; + __m128i orig4 = x_4; + __m128i orig5 = x_5; + __m128i orig6 = x_6; + __m128i orig7 = x_7; + __m128i orig8 = x_8; + __m128i orig9 = x_9; + __m128i orig10 = x_10; + __m128i orig11 = x_11; + __m128i orig12; + __m128i orig13; + __m128i orig14 = x_14; + __m128i orig15 = x_15; + __m128i t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9, t_10, t_11, t_12, + t_13, t_14, t_15; + + uint32_t in12, in13; + int i; + + while (bytes >= 256) { + const __m128i addv12 = _mm_set_epi64x(1, 0); + const __m128i addv13 = _mm_set_epi64x(3, 2); + __m128i t12, t13; + uint64_t in1213; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + x_4 = orig4; + x_5 = orig5; + x_6 = orig6; + x_7 = orig7; + x_8 = orig8; + x_9 = orig9; + x_10 = orig10; + x_11 = orig11; + x_14 = orig14; + x_15 = orig15; + + in12 = x[12]; + in13 = x[13]; + in1213 = ((uint64_t) in12) | (((uint64_t) in13) << 32); + t12 = _mm_set1_epi64x(in1213); + t13 = _mm_set1_epi64x(in1213); + + x_12 = _mm_add_epi64(addv12, t12); + x_13 = _mm_add_epi64(addv13, t13); + + t12 = _mm_unpacklo_epi32(x_12, x_13); + t13 = _mm_unpackhi_epi32(x_12, x_13); + + x_12 = _mm_unpacklo_epi32(t12, t13); + x_13 = _mm_unpackhi_epi32(t12, t13); + + orig12 = x_12; + orig13 = x_13; + + in1213 += 4; + + x[12] = in1213 & 0xFFFFFFFF; + x[13] = (in1213 >> 32) & 0xFFFFFFFF; + + for (i = 0; i < ROUNDS; i += 2) { + VEC4_QUARTERROUND(0, 4, 8, 12); + VEC4_QUARTERROUND(1, 5, 9, 13); + VEC4_QUARTERROUND(2, 6, 10, 14); + VEC4_QUARTERROUND(3, 7, 11, 15); + VEC4_QUARTERROUND(0, 5, 10, 15); + VEC4_QUARTERROUND(1, 6, 11, 12); + VEC4_QUARTERROUND(2, 7, 8, 13); + VEC4_QUARTERROUND(3, 4, 9, 14); + } + +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + { \ + __m128i t0, t1, t2, t3; \ + \ + x_##A = _mm_add_epi32(x_##A, orig##A); \ + x_##B = _mm_add_epi32(x_##B, orig##B); \ + x_##C = _mm_add_epi32(x_##C, orig##C); \ + x_##D = _mm_add_epi32(x_##D, orig##D); \ + t_##A = _mm_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm_unpackhi_epi64(t_##C, t_##D); \ + \ + t0 = _mm_xor_si128(x_##A, _mm_loadu_si128((__m128i*) (m + 0))); \ + _mm_storeu_si128((__m128i*) (c + 0), t0); \ + t1 = _mm_xor_si128(x_##B, _mm_loadu_si128((__m128i*) (m + 64))); \ + _mm_storeu_si128((__m128i*) (c + 64), t1); \ + t2 = _mm_xor_si128(x_##C, _mm_loadu_si128((__m128i*) (m + 128))); \ + _mm_storeu_si128((__m128i*) (c + 128), t2); \ + t3 = _mm_xor_si128(x_##D, _mm_loadu_si128((__m128i*) (m + 192))); \ + _mm_storeu_si128((__m128i*) (c + 192), t3); \ + } + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + + ONEQUAD(0, 1, 2, 3); + m += 16; + c += 16; + ONEQUAD(4, 5, 6, 7); + m += 16; + c += 16; + ONEQUAD(8, 9, 10, 11); + m += 16; + c += 16; + ONEQUAD(12, 13, 14, 15); + m -= 48; + c -= 48; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE + + bytes -= 256; + c += 256; + m += 256; + } +} +#undef VEC4_ROT +#undef VEC4_QUARTERROUND +#undef VEC4_QUARTERROUND_SHUFFLE diff --git a/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u8.h b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u8.h new file mode 100644 index 0000000000..22bf9fcfa1 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/dolbeau/u8.h @@ -0,0 +1,357 @@ + +#define VEC8_ROT(A, IMM) \ + _mm256_or_si256(_mm256_slli_epi32(A, IMM), _mm256_srli_epi32(A, (32 - IMM))) + +/* implements a vector quarter round by-the-book (naive!) */ +#define VEC8_QUARTERROUND_NAIVE(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = VEC8_ROT(t_##A, 16); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 12); \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = VEC8_ROT(t_##A, 8); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 7) + +/* same, but replace 2 of the shift/shift/or "rotation" by byte shuffles (8 & + * 16) (better) */ +#define VEC8_QUARTERROUND_SHUFFLE(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = _mm256_shuffle_epi8(t_##A, rot16); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 12); \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = _mm256_shuffle_epi8(t_##A, rot8); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 7) + +/* same, but replace 2 of the shift/shift/or "rotation" by byte & word shuffles + * (8 & 16) (not as good as previous) */ +#define VEC8_QUARTERROUND_SHUFFLE2(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = _mm256_shufflehi_epi16(_mm256_shufflelo_epi16(t_##A, 0xb1), 0xb1); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 12); \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + t_##A = _mm256_xor_si256(x_##D, x_##A); \ + x_##D = _mm256_shuffle_epi8(t_##A, rot8); \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + t_##C = _mm256_xor_si256(x_##B, x_##C); \ + x_##B = VEC8_ROT(t_##C, 7) + +#define VEC8_QUARTERROUND(A, B, C, D) VEC8_QUARTERROUND_SHUFFLE(A, B, C, D) + +#define VEC8_LINE1(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + x_##D = _mm256_shuffle_epi8(_mm256_xor_si256(x_##D, x_##A), rot16) +#define VEC8_LINE2(A, B, C, D) \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + x_##B = VEC8_ROT(_mm256_xor_si256(x_##B, x_##C), 12) +#define VEC8_LINE3(A, B, C, D) \ + x_##A = _mm256_add_epi32(x_##A, x_##B); \ + x_##D = _mm256_shuffle_epi8(_mm256_xor_si256(x_##D, x_##A), rot8) +#define VEC8_LINE4(A, B, C, D) \ + x_##C = _mm256_add_epi32(x_##C, x_##D); \ + x_##B = VEC8_ROT(_mm256_xor_si256(x_##B, x_##C), 7) + +#define VEC8_ROUND_SEQ(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, \ + C4, D4) \ + VEC8_LINE1(A1, B1, C1, D1); \ + VEC8_LINE1(A2, B2, C2, D2); \ + VEC8_LINE1(A3, B3, C3, D3); \ + VEC8_LINE1(A4, B4, C4, D4); \ + VEC8_LINE2(A1, B1, C1, D1); \ + VEC8_LINE2(A2, B2, C2, D2); \ + VEC8_LINE2(A3, B3, C3, D3); \ + VEC8_LINE2(A4, B4, C4, D4); \ + VEC8_LINE3(A1, B1, C1, D1); \ + VEC8_LINE3(A2, B2, C2, D2); \ + VEC8_LINE3(A3, B3, C3, D3); \ + VEC8_LINE3(A4, B4, C4, D4); \ + VEC8_LINE4(A1, B1, C1, D1); \ + VEC8_LINE4(A2, B2, C2, D2); \ + VEC8_LINE4(A3, B3, C3, D3); \ + VEC8_LINE4(A4, B4, C4, D4) + +#define VEC8_ROUND_HALF(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, \ + B4, C4, D4) \ + VEC8_LINE1(A1, B1, C1, D1); \ + VEC8_LINE1(A2, B2, C2, D2); \ + VEC8_LINE2(A1, B1, C1, D1); \ + VEC8_LINE2(A2, B2, C2, D2); \ + VEC8_LINE3(A1, B1, C1, D1); \ + VEC8_LINE3(A2, B2, C2, D2); \ + VEC8_LINE4(A1, B1, C1, D1); \ + VEC8_LINE4(A2, B2, C2, D2); \ + VEC8_LINE1(A3, B3, C3, D3); \ + VEC8_LINE1(A4, B4, C4, D4); \ + VEC8_LINE2(A3, B3, C3, D3); \ + VEC8_LINE2(A4, B4, C4, D4); \ + VEC8_LINE3(A3, B3, C3, D3); \ + VEC8_LINE3(A4, B4, C4, D4); \ + VEC8_LINE4(A3, B3, C3, D3); \ + VEC8_LINE4(A4, B4, C4, D4) + +#define VEC8_ROUND_HALFANDHALF(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, \ + A4, B4, C4, D4) \ + VEC8_LINE1(A1, B1, C1, D1); \ + VEC8_LINE1(A2, B2, C2, D2); \ + VEC8_LINE2(A1, B1, C1, D1); \ + VEC8_LINE2(A2, B2, C2, D2); \ + VEC8_LINE1(A3, B3, C3, D3); \ + VEC8_LINE1(A4, B4, C4, D4); \ + VEC8_LINE2(A3, B3, C3, D3); \ + VEC8_LINE2(A4, B4, C4, D4); \ + VEC8_LINE3(A1, B1, C1, D1); \ + VEC8_LINE3(A2, B2, C2, D2); \ + VEC8_LINE4(A1, B1, C1, D1); \ + VEC8_LINE4(A2, B2, C2, D2); \ + VEC8_LINE3(A3, B3, C3, D3); \ + VEC8_LINE3(A4, B4, C4, D4); \ + VEC8_LINE4(A3, B3, C3, D3); \ + VEC8_LINE4(A4, B4, C4, D4) + +#define VEC8_ROUND(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, C4, \ + D4) \ + VEC8_ROUND_SEQ(A1, B1, C1, D1, A2, B2, C2, D2, A3, B3, C3, D3, A4, B4, C4, \ + D4) + +if (bytes >= 512) { + /* constant for shuffling bytes (replacing multiple-of-8 rotates) */ + __m256i rot16 = + _mm256_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2, + 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + __m256i rot8 = + _mm256_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3, + 14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3); + uint32_t in12, in13; + + /* the naive way seems as fast (if not a bit faster) than the vector way */ + __m256i x_0 = _mm256_set1_epi32(x[0]); + __m256i x_1 = _mm256_set1_epi32(x[1]); + __m256i x_2 = _mm256_set1_epi32(x[2]); + __m256i x_3 = _mm256_set1_epi32(x[3]); + __m256i x_4 = _mm256_set1_epi32(x[4]); + __m256i x_5 = _mm256_set1_epi32(x[5]); + __m256i x_6 = _mm256_set1_epi32(x[6]); + __m256i x_7 = _mm256_set1_epi32(x[7]); + __m256i x_8 = _mm256_set1_epi32(x[8]); + __m256i x_9 = _mm256_set1_epi32(x[9]); + __m256i x_10 = _mm256_set1_epi32(x[10]); + __m256i x_11 = _mm256_set1_epi32(x[11]); + __m256i x_12; + __m256i x_13; + __m256i x_14 = _mm256_set1_epi32(x[14]); + __m256i x_15 = _mm256_set1_epi32(x[15]); + + __m256i orig0 = x_0; + __m256i orig1 = x_1; + __m256i orig2 = x_2; + __m256i orig3 = x_3; + __m256i orig4 = x_4; + __m256i orig5 = x_5; + __m256i orig6 = x_6; + __m256i orig7 = x_7; + __m256i orig8 = x_8; + __m256i orig9 = x_9; + __m256i orig10 = x_10; + __m256i orig11 = x_11; + __m256i orig12; + __m256i orig13; + __m256i orig14 = x_14; + __m256i orig15 = x_15; + __m256i t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9, t_10, t_11, t_12, + t_13, t_14, t_15; + + while (bytes >= 512) { + const __m256i addv12 = _mm256_set_epi64x(3, 2, 1, 0); + const __m256i addv13 = _mm256_set_epi64x(7, 6, 5, 4); + const __m256i permute = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + __m256i t12, t13; + + uint64_t in1213; + int i; + + x_0 = orig0; + x_1 = orig1; + x_2 = orig2; + x_3 = orig3; + x_4 = orig4; + x_5 = orig5; + x_6 = orig6; + x_7 = orig7; + x_8 = orig8; + x_9 = orig9; + x_10 = orig10; + x_11 = orig11; + x_14 = orig14; + x_15 = orig15; + + in12 = x[12]; + in13 = x[13]; + in1213 = ((uint64_t) in12) | (((uint64_t) in13) << 32); + x_12 = x_13 = _mm256_broadcastq_epi64(_mm_cvtsi64_si128(in1213)); + + t12 = _mm256_add_epi64(addv12, x_12); + t13 = _mm256_add_epi64(addv13, x_13); + + x_12 = _mm256_unpacklo_epi32(t12, t13); + x_13 = _mm256_unpackhi_epi32(t12, t13); + + t12 = _mm256_unpacklo_epi32(x_12, x_13); + t13 = _mm256_unpackhi_epi32(x_12, x_13); + + /* required because unpack* are intra-lane */ + x_12 = _mm256_permutevar8x32_epi32(t12, permute); + x_13 = _mm256_permutevar8x32_epi32(t13, permute); + + orig12 = x_12; + orig13 = x_13; + + in1213 += 8; + + x[12] = in1213 & 0xFFFFFFFF; + x[13] = (in1213 >> 32) & 0xFFFFFFFF; + + for (i = 0; i < ROUNDS; i += 2) { + VEC8_ROUND(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); + VEC8_ROUND(0, 5, 10, 15, 1, 6, 11, 12, 2, 7, 8, 13, 3, 4, 9, 14); + } + +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + { \ + __m128i t0, t1, t2, t3; \ + x_##A = _mm256_add_epi32(x_##A, orig##A); \ + x_##B = _mm256_add_epi32(x_##B, orig##B); \ + x_##C = _mm256_add_epi32(x_##C, orig##C); \ + x_##D = _mm256_add_epi32(x_##D, orig##D); \ + t_##A = _mm256_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm256_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm256_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm256_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm256_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm256_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm256_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm256_unpackhi_epi64(t_##C, t_##D); \ + t0 = _mm_xor_si128(_mm256_extracti128_si256(x_##A, 0), \ + _mm_loadu_si128((__m128i*) (m + 0))); \ + _mm_storeu_si128((__m128i*) (c + 0), t0); \ + t1 = _mm_xor_si128(_mm256_extracti128_si256(x_##B, 0), \ + _mm_loadu_si128((__m128i*) (m + 64))); \ + _mm_storeu_si128((__m128i*) (c + 64), t1); \ + t2 = _mm_xor_si128(_mm256_extracti128_si256(x_##C, 0), \ + _mm_loadu_si128((__m128i*) (m + 128))); \ + _mm_storeu_si128((__m128i*) (c + 128), t2); \ + t3 = _mm_xor_si128(_mm256_extracti128_si256(x_##D, 0), \ + _mm_loadu_si128((__m128i*) (m + 192))); \ + _mm_storeu_si128((__m128i*) (c + 192), t3); \ + t0 = _mm_xor_si128(_mm256_extracti128_si256(x_##A, 1), \ + _mm_loadu_si128((__m128i*) (m + 256))); \ + _mm_storeu_si128((__m128i*) (c + 256), t0); \ + t1 = _mm_xor_si128(_mm256_extracti128_si256(x_##B, 1), \ + _mm_loadu_si128((__m128i*) (m + 320))); \ + _mm_storeu_si128((__m128i*) (c + 320), t1); \ + t2 = _mm_xor_si128(_mm256_extracti128_si256(x_##C, 1), \ + _mm_loadu_si128((__m128i*) (m + 384))); \ + _mm_storeu_si128((__m128i*) (c + 384), t2); \ + t3 = _mm_xor_si128(_mm256_extracti128_si256(x_##D, 1), \ + _mm_loadu_si128((__m128i*) (m + 448))); \ + _mm_storeu_si128((__m128i*) (c + 448), t3); \ + } + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + +#define ONEQUAD_UNPCK(A, B, C, D) \ + { \ + x_##A = _mm256_add_epi32(x_##A, orig##A); \ + x_##B = _mm256_add_epi32(x_##B, orig##B); \ + x_##C = _mm256_add_epi32(x_##C, orig##C); \ + x_##D = _mm256_add_epi32(x_##D, orig##D); \ + t_##A = _mm256_unpacklo_epi32(x_##A, x_##B); \ + t_##B = _mm256_unpacklo_epi32(x_##C, x_##D); \ + t_##C = _mm256_unpackhi_epi32(x_##A, x_##B); \ + t_##D = _mm256_unpackhi_epi32(x_##C, x_##D); \ + x_##A = _mm256_unpacklo_epi64(t_##A, t_##B); \ + x_##B = _mm256_unpackhi_epi64(t_##A, t_##B); \ + x_##C = _mm256_unpacklo_epi64(t_##C, t_##D); \ + x_##D = _mm256_unpackhi_epi64(t_##C, t_##D); \ + } + +#define ONEOCTO(A, B, C, D, A2, B2, C2, D2) \ + { \ + ONEQUAD_UNPCK(A, B, C, D); \ + ONEQUAD_UNPCK(A2, B2, C2, D2); \ + t_##A = _mm256_permute2x128_si256(x_##A, x_##A2, 0x20); \ + t_##A2 = _mm256_permute2x128_si256(x_##A, x_##A2, 0x31); \ + t_##B = _mm256_permute2x128_si256(x_##B, x_##B2, 0x20); \ + t_##B2 = _mm256_permute2x128_si256(x_##B, x_##B2, 0x31); \ + t_##C = _mm256_permute2x128_si256(x_##C, x_##C2, 0x20); \ + t_##C2 = _mm256_permute2x128_si256(x_##C, x_##C2, 0x31); \ + t_##D = _mm256_permute2x128_si256(x_##D, x_##D2, 0x20); \ + t_##D2 = _mm256_permute2x128_si256(x_##D, x_##D2, 0x31); \ + t_##A = \ + _mm256_xor_si256(t_##A, _mm256_loadu_si256((__m256i*) (m + 0))); \ + t_##B = \ + _mm256_xor_si256(t_##B, _mm256_loadu_si256((__m256i*) (m + 64))); \ + t_##C = \ + _mm256_xor_si256(t_##C, _mm256_loadu_si256((__m256i*) (m + 128))); \ + t_##D = \ + _mm256_xor_si256(t_##D, _mm256_loadu_si256((__m256i*) (m + 192))); \ + t_##A2 = _mm256_xor_si256(t_##A2, \ + _mm256_loadu_si256((__m256i*) (m + 256))); \ + t_##B2 = _mm256_xor_si256(t_##B2, \ + _mm256_loadu_si256((__m256i*) (m + 320))); \ + t_##C2 = _mm256_xor_si256(t_##C2, \ + _mm256_loadu_si256((__m256i*) (m + 384))); \ + t_##D2 = _mm256_xor_si256(t_##D2, \ + _mm256_loadu_si256((__m256i*) (m + 448))); \ + _mm256_storeu_si256((__m256i*) (c + 0), t_##A); \ + _mm256_storeu_si256((__m256i*) (c + 64), t_##B); \ + _mm256_storeu_si256((__m256i*) (c + 128), t_##C); \ + _mm256_storeu_si256((__m256i*) (c + 192), t_##D); \ + _mm256_storeu_si256((__m256i*) (c + 256), t_##A2); \ + _mm256_storeu_si256((__m256i*) (c + 320), t_##B2); \ + _mm256_storeu_si256((__m256i*) (c + 384), t_##C2); \ + _mm256_storeu_si256((__m256i*) (c + 448), t_##D2); \ + } + + ONEOCTO(0, 1, 2, 3, 4, 5, 6, 7); + m += 32; + c += 32; + ONEOCTO(8, 9, 10, 11, 12, 13, 14, 15); + m -= 32; + c -= 32; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE +#undef ONEQUAD_UNPCK +#undef ONEOCTO + + bytes -= 512; + c += 512; + m += 512; + } +} +#undef VEC8_ROT +#undef VEC8_QUARTERROUND +#undef VEC8_QUARTERROUND_NAIVE +#undef VEC8_QUARTERROUND_SHUFFLE +#undef VEC8_QUARTERROUND_SHUFFLE2 +#undef VEC8_LINE1 +#undef VEC8_LINE2 +#undef VEC8_LINE3 +#undef VEC8_LINE4 +#undef VEC8_ROUND +#undef VEC8_ROUND_SEQ +#undef VEC8_ROUND_HALF +#undef VEC8_ROUND_HALFANDHALF diff --git a/libs/libsodium/src/crypto_stream/chacha20/ref/chacha20_ref.c b/libs/libsodium/src/crypto_stream/chacha20/ref/chacha20_ref.c new file mode 100644 index 0000000000..f88a99dbdf --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/ref/chacha20_ref.c @@ -0,0 +1,315 @@ + +/* + chacha-merged.c version 20080118 + D. J. Bernstein + Public domain. + */ + +#include +#include +#include + +#include "core.h" +#include "crypto_stream_chacha20.h" +#include "private/common.h" +#include "utils.h" + +#include "../stream_chacha20.h" +#include "chacha20_ref.h" + +struct chacha_ctx { + uint32_t input[16]; +}; + +typedef struct chacha_ctx chacha_ctx; + +#define U32C(v) (v##U) + +#define U32V(v) ((uint32_t)(v) &U32C(0xFFFFFFFF)) + +#define ROTATE(v, c) (ROTL32(v, c)) +#define XOR(v, w) ((v) ^ (w)) +#define PLUS(v, w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v), 1)) + +#define QUARTERROUND(a, b, c, d) \ + a = PLUS(a, b); \ + d = ROTATE(XOR(d, a), 16); \ + c = PLUS(c, d); \ + b = ROTATE(XOR(b, c), 12); \ + a = PLUS(a, b); \ + d = ROTATE(XOR(d, a), 8); \ + c = PLUS(c, d); \ + b = ROTATE(XOR(b, c), 7); + +static void +chacha_keysetup(chacha_ctx *ctx, const uint8_t *k) +{ + ctx->input[0] = U32C(0x61707865); + ctx->input[1] = U32C(0x3320646e); + ctx->input[2] = U32C(0x79622d32); + ctx->input[3] = U32C(0x6b206574); + ctx->input[4] = LOAD32_LE(k + 0); + ctx->input[5] = LOAD32_LE(k + 4); + ctx->input[6] = LOAD32_LE(k + 8); + ctx->input[7] = LOAD32_LE(k + 12); + ctx->input[8] = LOAD32_LE(k + 16); + ctx->input[9] = LOAD32_LE(k + 20); + ctx->input[10] = LOAD32_LE(k + 24); + ctx->input[11] = LOAD32_LE(k + 28); +} + +static void +chacha_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter + 0); + ctx->input[13] = counter == NULL ? 0 : LOAD32_LE(counter + 4); + ctx->input[14] = LOAD32_LE(iv + 0); + ctx->input[15] = LOAD32_LE(iv + 4); +} + +static void +chacha_ietf_ivsetup(chacha_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[12] = counter == NULL ? 0 : LOAD32_LE(counter); + ctx->input[13] = LOAD32_LE(iv + 0); + ctx->input[14] = LOAD32_LE(iv + 4); + ctx->input[15] = LOAD32_LE(iv + 8); +} + +static void +chacha20_encrypt_bytes(chacha_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, + x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, + j15; + uint8_t *ctarget = NULL; + uint8_t tmp[64]; + unsigned int i; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } + if (bytes > crypto_stream_chacha20_MESSAGEBYTES_MAX) { + sodium_misuse(); + } + j0 = ctx->input[0]; + j1 = ctx->input[1]; + j2 = ctx->input[2]; + j3 = ctx->input[3]; + j4 = ctx->input[4]; + j5 = ctx->input[5]; + j6 = ctx->input[6]; + j7 = ctx->input[7]; + j8 = ctx->input[8]; + j9 = ctx->input[9]; + j10 = ctx->input[10]; + j11 = ctx->input[11]; + j12 = ctx->input[12]; + j13 = ctx->input[13]; + j14 = ctx->input[14]; + j15 = ctx->input[15]; + + for (;;) { + if (bytes < 64) { + memset(tmp, 0, 64); + for (i = 0; i < bytes; ++i) { + tmp[i] = m[i]; + } + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20; i > 0; i -= 2) { + QUARTERROUND(x0, x4, x8, x12) + QUARTERROUND(x1, x5, x9, x13) + QUARTERROUND(x2, x6, x10, x14) + QUARTERROUND(x3, x7, x11, x15) + QUARTERROUND(x0, x5, x10, x15) + QUARTERROUND(x1, x6, x11, x12) + QUARTERROUND(x2, x7, x8, x13) + QUARTERROUND(x3, x4, x9, x14) + } + x0 = PLUS(x0, j0); + x1 = PLUS(x1, j1); + x2 = PLUS(x2, j2); + x3 = PLUS(x3, j3); + x4 = PLUS(x4, j4); + x5 = PLUS(x5, j5); + x6 = PLUS(x6, j6); + x7 = PLUS(x7, j7); + x8 = PLUS(x8, j8); + x9 = PLUS(x9, j9); + x10 = PLUS(x10, j10); + x11 = PLUS(x11, j11); + x12 = PLUS(x12, j12); + x13 = PLUS(x13, j13); + x14 = PLUS(x14, j14); + x15 = PLUS(x15, j15); + + x0 = XOR(x0, LOAD32_LE(m + 0)); + x1 = XOR(x1, LOAD32_LE(m + 4)); + x2 = XOR(x2, LOAD32_LE(m + 8)); + x3 = XOR(x3, LOAD32_LE(m + 12)); + x4 = XOR(x4, LOAD32_LE(m + 16)); + x5 = XOR(x5, LOAD32_LE(m + 20)); + x6 = XOR(x6, LOAD32_LE(m + 24)); + x7 = XOR(x7, LOAD32_LE(m + 28)); + x8 = XOR(x8, LOAD32_LE(m + 32)); + x9 = XOR(x9, LOAD32_LE(m + 36)); + x10 = XOR(x10, LOAD32_LE(m + 40)); + x11 = XOR(x11, LOAD32_LE(m + 44)); + x12 = XOR(x12, LOAD32_LE(m + 48)); + x13 = XOR(x13, LOAD32_LE(m + 52)); + x14 = XOR(x14, LOAD32_LE(m + 56)); + x15 = XOR(x15, LOAD32_LE(m + 60)); + + j12 = PLUSONE(j12); + /* LCOV_EXCL_START */ + if (!j12) { + j13 = PLUSONE(j13); + } + /* LCOV_EXCL_STOP */ + + STORE32_LE(c + 0, x0); + STORE32_LE(c + 4, x1); + STORE32_LE(c + 8, x2); + STORE32_LE(c + 12, x3); + STORE32_LE(c + 16, x4); + STORE32_LE(c + 20, x5); + STORE32_LE(c + 24, x6); + STORE32_LE(c + 28, x7); + STORE32_LE(c + 32, x8); + STORE32_LE(c + 36, x9); + STORE32_LE(c + 40, x10); + STORE32_LE(c + 44, x11); + STORE32_LE(c + 48, x12); + STORE32_LE(c + 52, x13); + STORE32_LE(c + 56, x14); + STORE32_LE(c + 60, x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0; i < (unsigned int) bytes; ++i) { + ctarget[i] = c[i]; /* ctarget cannot be NULL */ + } + } + ctx->input[12] = j12; + ctx->input[13] = j13; + + return; + } + bytes -= 64; + c += 64; + m += 64; + } +} + +static int +stream_ref(unsigned char *c, unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + struct chacha_ctx ctx; + + if (!clen) { + return 0; + } + COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8); + chacha_keysetup(&ctx, k); + chacha_ivsetup(&ctx, n, NULL); + memset(c, 0, clen); + chacha20_encrypt_bytes(&ctx, c, c, clen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_ietf_ref(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + struct chacha_ctx ctx; + + if (!clen) { + return 0; + } + COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES == 256 / 8); + chacha_keysetup(&ctx, k); + chacha_ietf_ivsetup(&ctx, n, NULL); + memset(c, 0, clen); + chacha20_encrypt_bytes(&ctx, c, c, clen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (!mlen) { + return 0; + } + ic_high = U32V(ic >> 32); + ic_low = U32V(ic); + STORE32_LE(&ic_bytes[0], ic_low); + STORE32_LE(&ic_bytes[4], ic_high); + chacha_keysetup(&ctx, k); + chacha_ivsetup(&ctx, n, ic_bytes); + chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_ietf_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint32_t ic, const unsigned char *k) +{ + struct chacha_ctx ctx; + uint8_t ic_bytes[4]; + + if (!mlen) { + return 0; + } + STORE32_LE(ic_bytes, ic); + chacha_keysetup(&ctx, k); + chacha_ietf_ivsetup(&ctx, n, ic_bytes); + chacha20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_ref_implementation = { + SODIUM_C99(.stream =) stream_ref, + SODIUM_C99(.stream_ietf =) stream_ietf_ref, + SODIUM_C99(.stream_xor_ic =) stream_ref_xor_ic, + SODIUM_C99(.stream_ietf_xor_ic =) stream_ietf_ref_xor_ic + }; diff --git a/libs/libsodium/src/crypto_stream/chacha20/ref/chacha20_ref.h b/libs/libsodium/src/crypto_stream/chacha20/ref/chacha20_ref.h new file mode 100644 index 0000000000..6ac4807554 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/ref/chacha20_ref.h @@ -0,0 +1,8 @@ + +#include + +#include "../stream_chacha20.h" +#include "crypto_stream_chacha20.h" + +extern struct crypto_stream_chacha20_implementation + crypto_stream_chacha20_ref_implementation; diff --git a/libs/libsodium/src/crypto_stream/chacha20/stream_chacha20.c b/libs/libsodium/src/crypto_stream/chacha20/stream_chacha20.c new file mode 100644 index 0000000000..3b0895112c --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/stream_chacha20.c @@ -0,0 +1,130 @@ +#include "crypto_stream_chacha20.h" +#include "private/common.h" +#include "private/implementations.h" +#include "randombytes.h" +#include "runtime.h" +#include "stream_chacha20.h" + +#include "ref/chacha20_ref.h" +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_EMMINTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) +# include "dolbeau/chacha20_dolbeau-avx2.h" +#endif +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) +# include "dolbeau/chacha20_dolbeau-ssse3.h" +#endif + +static const crypto_stream_chacha20_implementation *implementation = + &crypto_stream_chacha20_ref_implementation; + +size_t +crypto_stream_chacha20_keybytes(void) { + return crypto_stream_chacha20_KEYBYTES; +} + +size_t +crypto_stream_chacha20_noncebytes(void) { + return crypto_stream_chacha20_NONCEBYTES; +} + +size_t +crypto_stream_chacha20_messagebytes_max(void) +{ + return crypto_stream_chacha20_MESSAGEBYTES_MAX; +} + +size_t +crypto_stream_chacha20_ietf_keybytes(void) { + return crypto_stream_chacha20_ietf_KEYBYTES; +} + +size_t +crypto_stream_chacha20_ietf_noncebytes(void) { + return crypto_stream_chacha20_ietf_NONCEBYTES; +} + +size_t +crypto_stream_chacha20_ietf_messagebytes_max(void) +{ + return crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX; +} + +int +crypto_stream_chacha20(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + return implementation->stream(c, clen, n, k); +} + +int +crypto_stream_chacha20_ietf(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + return implementation->stream_ietf(c, clen, n, k); +} + +int +crypto_stream_chacha20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + return implementation->stream_xor_ic(c, m, mlen, n, ic, k); +} + +int +crypto_stream_chacha20_ietf_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint32_t ic, + const unsigned char *k) +{ + return implementation->stream_ietf_xor_ic(c, m, mlen, n, ic, k); +} + +int +crypto_stream_chacha20_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + return implementation->stream_xor_ic(c, m, mlen, n, 0U, k); +} + +int +crypto_stream_chacha20_ietf_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + return implementation->stream_ietf_xor_ic(c, m, mlen, n, 0U, k); +} + +void +crypto_stream_chacha20_ietf_keygen(unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]) +{ + randombytes_buf(k, crypto_stream_chacha20_ietf_KEYBYTES); +} + +void +crypto_stream_chacha20_keygen(unsigned char k[crypto_stream_chacha20_KEYBYTES]) +{ + randombytes_buf(k, crypto_stream_chacha20_KEYBYTES); +} + +int +_crypto_stream_chacha20_pick_best_implementation(void) +{ + implementation = &crypto_stream_chacha20_ref_implementation; +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_EMMINTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + if (sodium_runtime_has_avx2()) { + implementation = &crypto_stream_chacha20_dolbeau_avx2_implementation; + return 0; + } +#endif +#if defined(HAVE_EMMINTRIN_H) && defined(HAVE_TMMINTRIN_H) + if (sodium_runtime_has_ssse3()) { + implementation = &crypto_stream_chacha20_dolbeau_ssse3_implementation; + return 0; + } +#endif + return 0; +} diff --git a/libs/libsodium/src/crypto_stream/chacha20/stream_chacha20.h b/libs/libsodium/src/crypto_stream/chacha20/stream_chacha20.h new file mode 100644 index 0000000000..d6b71c5e0d --- /dev/null +++ b/libs/libsodium/src/crypto_stream/chacha20/stream_chacha20.h @@ -0,0 +1,22 @@ + +#ifndef stream_chacha20_H +#define stream_chacha20_H + +#include + +typedef struct crypto_stream_chacha20_implementation { + int (*stream)(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + int (*stream_ietf)(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + int (*stream_xor_ic)(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k); + int (*stream_ietf_xor_ic)(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint32_t ic, + const unsigned char *k); +} crypto_stream_chacha20_implementation; + +#endif diff --git a/libs/libsodium/src/crypto_stream/crypto_stream.c b/libs/libsodium/src/crypto_stream/crypto_stream.c new file mode 100644 index 0000000000..58d25381ab --- /dev/null +++ b/libs/libsodium/src/crypto_stream/crypto_stream.c @@ -0,0 +1,49 @@ + +#include "crypto_stream.h" +#include "randombytes.h" + +size_t +crypto_stream_keybytes(void) +{ + return crypto_stream_KEYBYTES; +} + +size_t +crypto_stream_noncebytes(void) +{ + return crypto_stream_NONCEBYTES; +} + +size_t +crypto_stream_messagebytes_max(void) +{ + return crypto_stream_MESSAGEBYTES_MAX; +} + +const char * +crypto_stream_primitive(void) +{ + return crypto_stream_PRIMITIVE; +} + +int +crypto_stream(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + return crypto_stream_xsalsa20(c, clen, n, k); +} + + +int +crypto_stream_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + return crypto_stream_xsalsa20_xor(c, m, mlen, n, k); +} + +void +crypto_stream_keygen(unsigned char k[crypto_stream_KEYBYTES]) +{ + randombytes_buf(k, crypto_stream_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_stream/salsa20/ref/salsa20_ref.c b/libs/libsodium/src/crypto_stream/salsa20/ref/salsa20_ref.c new file mode 100644 index 0000000000..f0854ebf7e --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/ref/salsa20_ref.c @@ -0,0 +1,120 @@ +/* +version 20140420 +D. J. Bernstein +Public domain. +*/ + +#include + +#include "crypto_core_salsa20.h" +#include "crypto_stream_salsa20.h" +#include "utils.h" + +#include "../stream_salsa20.h" +#include "salsa20_ref.h" + +#ifndef HAVE_AMD64_ASM + +static int +stream_ref(unsigned char *c, unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + unsigned char in[16]; + unsigned char block[64]; + unsigned char kcopy[32]; + unsigned int i; + unsigned int u; + + if (!clen) { + return 0; + } + for (i = 0; i < 32; i++) { + kcopy[i] = k[i]; + } + for (i = 0; i < 8; i++) { + in[i] = n[i]; + } + for (i = 8; i < 16; i++) { + in[i] = 0; + } + while (clen >= 64) { + crypto_core_salsa20(c, in, kcopy, NULL); + u = 1; + for (i = 8; i < 16; i++) { + u += (unsigned int) in[i]; + in[i] = u; + u >>= 8; + } + clen -= 64; + c += 64; + } + if (clen) { + crypto_core_salsa20(block, in, kcopy, NULL); + for (i = 0; i < (unsigned int) clen; i++) { + c[i] = block[i]; + } + } + sodium_memzero(block, sizeof block); + sodium_memzero(kcopy, sizeof kcopy); + + return 0; +} + +static int +stream_ref_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + unsigned char in[16]; + unsigned char block[64]; + unsigned char kcopy[32]; + unsigned int i; + unsigned int u; + + if (!mlen) { + return 0; + } + for (i = 0; i < 32; i++) { + kcopy[i] = k[i]; + } + for (i = 0; i < 8; i++) { + in[i] = n[i]; + } + for (i = 8; i < 16; i++) { + in[i] = (unsigned char) (ic & 0xff); + ic >>= 8; + } + while (mlen >= 64) { + crypto_core_salsa20(block, in, kcopy, NULL); + for (i = 0; i < 64; i++) { + c[i] = m[i] ^ block[i]; + } + u = 1; + for (i = 8; i < 16; i++) { + u += (unsigned int) in[i]; + in[i] = u; + u >>= 8; + } + mlen -= 64; + c += 64; + m += 64; + } + if (mlen) { + crypto_core_salsa20(block, in, kcopy, NULL); + for (i = 0; i < (unsigned int) mlen; i++) { + c[i] = m[i] ^ block[i]; + } + } + sodium_memzero(block, sizeof block); + sodium_memzero(kcopy, sizeof kcopy); + + return 0; +} + +struct crypto_stream_salsa20_implementation + crypto_stream_salsa20_ref_implementation = { + SODIUM_C99(.stream =) stream_ref, + SODIUM_C99(.stream_xor_ic =) stream_ref_xor_ic, + }; + +#endif diff --git a/libs/libsodium/src/crypto_stream/salsa20/ref/salsa20_ref.h b/libs/libsodium/src/crypto_stream/salsa20/ref/salsa20_ref.h new file mode 100644 index 0000000000..8716cb4048 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/ref/salsa20_ref.h @@ -0,0 +1,8 @@ + +#include + +#include "../stream_salsa20.h" +#include "crypto_stream_salsa20.h" + +extern struct crypto_stream_salsa20_implementation + crypto_stream_salsa20_ref_implementation; diff --git a/libs/libsodium/src/crypto_stream/salsa20/stream_salsa20.c b/libs/libsodium/src/crypto_stream/salsa20/stream_salsa20.c new file mode 100644 index 0000000000..4529850136 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/stream_salsa20.c @@ -0,0 +1,100 @@ +#include "crypto_stream_salsa20.h" +#include "private/common.h" +#include "private/implementations.h" +#include "randombytes.h" +#include "runtime.h" +#include "stream_salsa20.h" + +#ifdef HAVE_AMD64_ASM +# include "xmm6/salsa20_xmm6.h" +#else +# include "ref/salsa20_ref.h" +#endif +#if !defined(HAVE_AMD64_ASM) && defined(HAVE_EMMINTRIN_H) +# include "xmm6int/salsa20_xmm6int-sse2.h" +#endif +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_EMMINTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) +# include "xmm6int/salsa20_xmm6int-avx2.h" +#endif + +#if HAVE_AMD64_ASM +static const crypto_stream_salsa20_implementation *implementation = + &crypto_stream_salsa20_xmm6_implementation; +#else +static const crypto_stream_salsa20_implementation *implementation = + &crypto_stream_salsa20_ref_implementation; +#endif + +size_t +crypto_stream_salsa20_keybytes(void) +{ + return crypto_stream_salsa20_KEYBYTES; +} + +size_t +crypto_stream_salsa20_noncebytes(void) +{ + return crypto_stream_salsa20_NONCEBYTES; +} + +size_t +crypto_stream_salsa20_messagebytes_max(void) +{ + return crypto_stream_salsa20_MESSAGEBYTES_MAX; +} + +int +crypto_stream_salsa20(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + return implementation->stream(c, clen, n, k); +} + +int +crypto_stream_salsa20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + return implementation->stream_xor_ic(c, m, mlen, n, ic, k); +} + +int +crypto_stream_salsa20_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + return implementation->stream_xor_ic(c, m, mlen, n, 0U, k); +} + +void +crypto_stream_salsa20_keygen(unsigned char k[crypto_stream_salsa20_KEYBYTES]) +{ + randombytes_buf(k, crypto_stream_salsa20_KEYBYTES); +} + +int +_crypto_stream_salsa20_pick_best_implementation(void) +{ +#ifdef HAVE_AMD64_ASM + implementation = &crypto_stream_salsa20_xmm6_implementation; +#else + implementation = &crypto_stream_salsa20_ref_implementation; +#endif + +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_EMMINTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + if (sodium_runtime_has_avx2()) { + implementation = &crypto_stream_salsa20_xmm6int_avx2_implementation; + return 0; + } +#endif +#if !defined(HAVE_AMD64_ASM) && defined(HAVE_EMMINTRIN_H) + if (sodium_runtime_has_sse2()) { + implementation = &crypto_stream_salsa20_xmm6int_sse2_implementation; + return 0; + } +#endif + return 0; /* LCOV_EXCL_LINE */ +} diff --git a/libs/libsodium/src/crypto_stream/salsa20/stream_salsa20.h b/libs/libsodium/src/crypto_stream/salsa20/stream_salsa20.h new file mode 100644 index 0000000000..1949d38113 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/stream_salsa20.h @@ -0,0 +1,16 @@ + +#ifndef stream_salsa20_H +#define stream_salsa20_H + +#include + +typedef struct crypto_stream_salsa20_implementation { + int (*stream)(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + int (*stream_xor_ic)(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k); +} crypto_stream_salsa20_implementation; + +#endif diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S b/libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S new file mode 100644 index 0000000000..6d9f354e10 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6-asm.S @@ -0,0 +1,960 @@ +#ifdef HAVE_AMD64_ASM + +.text +.p2align 5 + +#ifdef ASM_HIDE_SYMBOL +ASM_HIDE_SYMBOL stream_salsa20_xmm6 +ASM_HIDE_SYMBOL _stream_salsa20_xmm6 +#endif +.globl stream_salsa20_xmm6 +.globl _stream_salsa20_xmm6 +#ifdef __ELF__ +.type stream_salsa20_xmm6, @function +.type _stream_salsa20_xmm6, @function +#endif +stream_salsa20_xmm6: +_stream_salsa20_xmm6: +mov %rsp,%r11 +and $31,%r11 +add $512,%r11 +sub %r11,%rsp +movq %r11,416(%rsp) +movq %r12,424(%rsp) +movq %r13,432(%rsp) +movq %r14,440(%rsp) +movq %r15,448(%rsp) +movq %rbx,456(%rsp) +movq %rbp,464(%rsp) +mov %rsi,%r9 +mov %rdi,%rdi +mov %rdi,%rsi +mov %rdx,%rdx +mov %rcx,%r10 +cmp $0,%r9 +jbe ._done +mov $0,%rax +mov %r9,%rcx +rep stosb +sub %r9,%rdi +movq $0,472(%rsp) +jmp ._start + +.text +.p2align 5 + +#ifdef ASM_HIDE_SYMBOL +ASM_HIDE_SYMBOL stream_salsa20_xmm6_xor_ic +ASM_HIDE_SYMBOL _stream_salsa20_xmm6_xor_ic +#endif +.globl stream_salsa20_xmm6_xor_ic +.globl _stream_salsa20_xmm6_xor_ic +#ifdef __ELF__ +.type stream_salsa20_xmm6_xor_ic, @function +.type _stream_salsa20_xmm6_xor_ic, @function +#endif +stream_salsa20_xmm6_xor_ic: +_stream_salsa20_xmm6_xor_ic: + +mov %rsp,%r11 +and $31,%r11 +add $512,%r11 +sub %r11,%rsp +movq %r11,416(%rsp) +movq %r12,424(%rsp) +movq %r13,432(%rsp) +movq %r14,440(%rsp) +movq %r15,448(%rsp) +movq %rbx,456(%rsp) +movq %rbp,464(%rsp) +mov %rdi,%rdi +mov %rsi,%rsi +mov %r9,%r10 +movq %r8,472(%rsp) +mov %rdx,%r9 +mov %rcx,%rdx +cmp $0,%r9 +jbe ._done + +._start: +movl 20(%r10),%ecx +movl 0(%r10),%r8d +movl 0(%rdx),%eax +movl 16(%r10),%r11d +movl %ecx,64(%rsp) +movl %r8d,4+64(%rsp) +movl %eax,8+64(%rsp) +movl %r11d,12+64(%rsp) +movl 24(%r10),%r8d +movl 4(%r10),%eax +movl 4(%rdx),%edx +movq 472(%rsp),%rcx +movl %ecx,80(%rsp) +movl %r8d,4+80(%rsp) +movl %eax,8+80(%rsp) +movl %edx,12+80(%rsp) +movl 12(%r10),%edx +shr $32,%rcx +movl 28(%r10),%r8d +movl 8(%r10),%eax +movl %edx,96(%rsp) +movl %ecx,4+96(%rsp) +movl %r8d,8+96(%rsp) +movl %eax,12+96(%rsp) +mov $1634760805,%rdx +mov $857760878,%rcx +mov $2036477234,%r8 +mov $1797285236,%rax +movl %edx,112(%rsp) +movl %ecx,4+112(%rsp) +movl %r8d,8+112(%rsp) +movl %eax,12+112(%rsp) +cmp $256,%r9 +jb ._bytesbetween1and255 +movdqa 112(%rsp),%xmm0 +pshufd $0x55,%xmm0,%xmm1 +pshufd $0xaa,%xmm0,%xmm2 +pshufd $0xff,%xmm0,%xmm3 +pshufd $0x00,%xmm0,%xmm0 +movdqa %xmm1,128(%rsp) +movdqa %xmm2,144(%rsp) +movdqa %xmm3,160(%rsp) +movdqa %xmm0,176(%rsp) +movdqa 64(%rsp),%xmm0 +pshufd $0xaa,%xmm0,%xmm1 +pshufd $0xff,%xmm0,%xmm2 +pshufd $0x00,%xmm0,%xmm3 +pshufd $0x55,%xmm0,%xmm0 +movdqa %xmm1,192(%rsp) +movdqa %xmm2,208(%rsp) +movdqa %xmm3,224(%rsp) +movdqa %xmm0,240(%rsp) +movdqa 80(%rsp),%xmm0 +pshufd $0xff,%xmm0,%xmm1 +pshufd $0x55,%xmm0,%xmm2 +pshufd $0xaa,%xmm0,%xmm0 +movdqa %xmm1,256(%rsp) +movdqa %xmm2,272(%rsp) +movdqa %xmm0,288(%rsp) +movdqa 96(%rsp),%xmm0 +pshufd $0x00,%xmm0,%xmm1 +pshufd $0xaa,%xmm0,%xmm2 +pshufd $0xff,%xmm0,%xmm0 +movdqa %xmm1,304(%rsp) +movdqa %xmm2,320(%rsp) +movdqa %xmm0,336(%rsp) + +.p2align 4 +._bytesatleast256: +movq 472(%rsp),%rdx +mov %rdx,%rcx +shr $32,%rcx +movl %edx,352(%rsp) +movl %ecx,368(%rsp) +add $1,%rdx +mov %rdx,%rcx +shr $32,%rcx +movl %edx,4+352(%rsp) +movl %ecx,4+368(%rsp) +add $1,%rdx +mov %rdx,%rcx +shr $32,%rcx +movl %edx,8+352(%rsp) +movl %ecx,8+368(%rsp) +add $1,%rdx +mov %rdx,%rcx +shr $32,%rcx +movl %edx,12+352(%rsp) +movl %ecx,12+368(%rsp) +add $1,%rdx +mov %rdx,%rcx +shr $32,%rcx +movl %edx,80(%rsp) +movl %ecx,4+96(%rsp) +movq %rdx,472(%rsp) +movq %r9,480(%rsp) +mov $20,%rdx +movdqa 128(%rsp),%xmm0 +movdqa 144(%rsp),%xmm1 +movdqa 160(%rsp),%xmm2 +movdqa 320(%rsp),%xmm3 +movdqa 336(%rsp),%xmm4 +movdqa 192(%rsp),%xmm5 +movdqa 208(%rsp),%xmm6 +movdqa 240(%rsp),%xmm7 +movdqa 256(%rsp),%xmm8 +movdqa 272(%rsp),%xmm9 +movdqa 288(%rsp),%xmm10 +movdqa 368(%rsp),%xmm11 +movdqa 176(%rsp),%xmm12 +movdqa 224(%rsp),%xmm13 +movdqa 304(%rsp),%xmm14 +movdqa 352(%rsp),%xmm15 + +.p2align 4 +._mainloop1: +movdqa %xmm1,384(%rsp) +movdqa %xmm2,400(%rsp) +movdqa %xmm13,%xmm1 +paddd %xmm12,%xmm1 +movdqa %xmm1,%xmm2 +pslld $7,%xmm1 +pxor %xmm1,%xmm14 +psrld $25,%xmm2 +pxor %xmm2,%xmm14 +movdqa %xmm7,%xmm1 +paddd %xmm0,%xmm1 +movdqa %xmm1,%xmm2 +pslld $7,%xmm1 +pxor %xmm1,%xmm11 +psrld $25,%xmm2 +pxor %xmm2,%xmm11 +movdqa %xmm12,%xmm1 +paddd %xmm14,%xmm1 +movdqa %xmm1,%xmm2 +pslld $9,%xmm1 +pxor %xmm1,%xmm15 +psrld $23,%xmm2 +pxor %xmm2,%xmm15 +movdqa %xmm0,%xmm1 +paddd %xmm11,%xmm1 +movdqa %xmm1,%xmm2 +pslld $9,%xmm1 +pxor %xmm1,%xmm9 +psrld $23,%xmm2 +pxor %xmm2,%xmm9 +movdqa %xmm14,%xmm1 +paddd %xmm15,%xmm1 +movdqa %xmm1,%xmm2 +pslld $13,%xmm1 +pxor %xmm1,%xmm13 +psrld $19,%xmm2 +pxor %xmm2,%xmm13 +movdqa %xmm11,%xmm1 +paddd %xmm9,%xmm1 +movdqa %xmm1,%xmm2 +pslld $13,%xmm1 +pxor %xmm1,%xmm7 +psrld $19,%xmm2 +pxor %xmm2,%xmm7 +movdqa %xmm15,%xmm1 +paddd %xmm13,%xmm1 +movdqa %xmm1,%xmm2 +pslld $18,%xmm1 +pxor %xmm1,%xmm12 +psrld $14,%xmm2 +pxor %xmm2,%xmm12 +movdqa 384(%rsp),%xmm1 +movdqa %xmm12,384(%rsp) +movdqa %xmm9,%xmm2 +paddd %xmm7,%xmm2 +movdqa %xmm2,%xmm12 +pslld $18,%xmm2 +pxor %xmm2,%xmm0 +psrld $14,%xmm12 +pxor %xmm12,%xmm0 +movdqa %xmm5,%xmm2 +paddd %xmm1,%xmm2 +movdqa %xmm2,%xmm12 +pslld $7,%xmm2 +pxor %xmm2,%xmm3 +psrld $25,%xmm12 +pxor %xmm12,%xmm3 +movdqa 400(%rsp),%xmm2 +movdqa %xmm0,400(%rsp) +movdqa %xmm6,%xmm0 +paddd %xmm2,%xmm0 +movdqa %xmm0,%xmm12 +pslld $7,%xmm0 +pxor %xmm0,%xmm4 +psrld $25,%xmm12 +pxor %xmm12,%xmm4 +movdqa %xmm1,%xmm0 +paddd %xmm3,%xmm0 +movdqa %xmm0,%xmm12 +pslld $9,%xmm0 +pxor %xmm0,%xmm10 +psrld $23,%xmm12 +pxor %xmm12,%xmm10 +movdqa %xmm2,%xmm0 +paddd %xmm4,%xmm0 +movdqa %xmm0,%xmm12 +pslld $9,%xmm0 +pxor %xmm0,%xmm8 +psrld $23,%xmm12 +pxor %xmm12,%xmm8 +movdqa %xmm3,%xmm0 +paddd %xmm10,%xmm0 +movdqa %xmm0,%xmm12 +pslld $13,%xmm0 +pxor %xmm0,%xmm5 +psrld $19,%xmm12 +pxor %xmm12,%xmm5 +movdqa %xmm4,%xmm0 +paddd %xmm8,%xmm0 +movdqa %xmm0,%xmm12 +pslld $13,%xmm0 +pxor %xmm0,%xmm6 +psrld $19,%xmm12 +pxor %xmm12,%xmm6 +movdqa %xmm10,%xmm0 +paddd %xmm5,%xmm0 +movdqa %xmm0,%xmm12 +pslld $18,%xmm0 +pxor %xmm0,%xmm1 +psrld $14,%xmm12 +pxor %xmm12,%xmm1 +movdqa 384(%rsp),%xmm0 +movdqa %xmm1,384(%rsp) +movdqa %xmm4,%xmm1 +paddd %xmm0,%xmm1 +movdqa %xmm1,%xmm12 +pslld $7,%xmm1 +pxor %xmm1,%xmm7 +psrld $25,%xmm12 +pxor %xmm12,%xmm7 +movdqa %xmm8,%xmm1 +paddd %xmm6,%xmm1 +movdqa %xmm1,%xmm12 +pslld $18,%xmm1 +pxor %xmm1,%xmm2 +psrld $14,%xmm12 +pxor %xmm12,%xmm2 +movdqa 400(%rsp),%xmm12 +movdqa %xmm2,400(%rsp) +movdqa %xmm14,%xmm1 +paddd %xmm12,%xmm1 +movdqa %xmm1,%xmm2 +pslld $7,%xmm1 +pxor %xmm1,%xmm5 +psrld $25,%xmm2 +pxor %xmm2,%xmm5 +movdqa %xmm0,%xmm1 +paddd %xmm7,%xmm1 +movdqa %xmm1,%xmm2 +pslld $9,%xmm1 +pxor %xmm1,%xmm10 +psrld $23,%xmm2 +pxor %xmm2,%xmm10 +movdqa %xmm12,%xmm1 +paddd %xmm5,%xmm1 +movdqa %xmm1,%xmm2 +pslld $9,%xmm1 +pxor %xmm1,%xmm8 +psrld $23,%xmm2 +pxor %xmm2,%xmm8 +movdqa %xmm7,%xmm1 +paddd %xmm10,%xmm1 +movdqa %xmm1,%xmm2 +pslld $13,%xmm1 +pxor %xmm1,%xmm4 +psrld $19,%xmm2 +pxor %xmm2,%xmm4 +movdqa %xmm5,%xmm1 +paddd %xmm8,%xmm1 +movdqa %xmm1,%xmm2 +pslld $13,%xmm1 +pxor %xmm1,%xmm14 +psrld $19,%xmm2 +pxor %xmm2,%xmm14 +movdqa %xmm10,%xmm1 +paddd %xmm4,%xmm1 +movdqa %xmm1,%xmm2 +pslld $18,%xmm1 +pxor %xmm1,%xmm0 +psrld $14,%xmm2 +pxor %xmm2,%xmm0 +movdqa 384(%rsp),%xmm1 +movdqa %xmm0,384(%rsp) +movdqa %xmm8,%xmm0 +paddd %xmm14,%xmm0 +movdqa %xmm0,%xmm2 +pslld $18,%xmm0 +pxor %xmm0,%xmm12 +psrld $14,%xmm2 +pxor %xmm2,%xmm12 +movdqa %xmm11,%xmm0 +paddd %xmm1,%xmm0 +movdqa %xmm0,%xmm2 +pslld $7,%xmm0 +pxor %xmm0,%xmm6 +psrld $25,%xmm2 +pxor %xmm2,%xmm6 +movdqa 400(%rsp),%xmm2 +movdqa %xmm12,400(%rsp) +movdqa %xmm3,%xmm0 +paddd %xmm2,%xmm0 +movdqa %xmm0,%xmm12 +pslld $7,%xmm0 +pxor %xmm0,%xmm13 +psrld $25,%xmm12 +pxor %xmm12,%xmm13 +movdqa %xmm1,%xmm0 +paddd %xmm6,%xmm0 +movdqa %xmm0,%xmm12 +pslld $9,%xmm0 +pxor %xmm0,%xmm15 +psrld $23,%xmm12 +pxor %xmm12,%xmm15 +movdqa %xmm2,%xmm0 +paddd %xmm13,%xmm0 +movdqa %xmm0,%xmm12 +pslld $9,%xmm0 +pxor %xmm0,%xmm9 +psrld $23,%xmm12 +pxor %xmm12,%xmm9 +movdqa %xmm6,%xmm0 +paddd %xmm15,%xmm0 +movdqa %xmm0,%xmm12 +pslld $13,%xmm0 +pxor %xmm0,%xmm11 +psrld $19,%xmm12 +pxor %xmm12,%xmm11 +movdqa %xmm13,%xmm0 +paddd %xmm9,%xmm0 +movdqa %xmm0,%xmm12 +pslld $13,%xmm0 +pxor %xmm0,%xmm3 +psrld $19,%xmm12 +pxor %xmm12,%xmm3 +movdqa %xmm15,%xmm0 +paddd %xmm11,%xmm0 +movdqa %xmm0,%xmm12 +pslld $18,%xmm0 +pxor %xmm0,%xmm1 +psrld $14,%xmm12 +pxor %xmm12,%xmm1 +movdqa %xmm9,%xmm0 +paddd %xmm3,%xmm0 +movdqa %xmm0,%xmm12 +pslld $18,%xmm0 +pxor %xmm0,%xmm2 +psrld $14,%xmm12 +pxor %xmm12,%xmm2 +movdqa 384(%rsp),%xmm12 +movdqa 400(%rsp),%xmm0 +sub $2,%rdx +ja ._mainloop1 + +paddd 176(%rsp),%xmm12 +paddd 240(%rsp),%xmm7 +paddd 288(%rsp),%xmm10 +paddd 336(%rsp),%xmm4 +movd %xmm12,%rdx +movd %xmm7,%rcx +movd %xmm10,%r8 +movd %xmm4,%r9 +pshufd $0x39,%xmm12,%xmm12 +pshufd $0x39,%xmm7,%xmm7 +pshufd $0x39,%xmm10,%xmm10 +pshufd $0x39,%xmm4,%xmm4 +xorl 0(%rsi),%edx +xorl 4(%rsi),%ecx +xorl 8(%rsi),%r8d +xorl 12(%rsi),%r9d +movl %edx,0(%rdi) +movl %ecx,4(%rdi) +movl %r8d,8(%rdi) +movl %r9d,12(%rdi) +movd %xmm12,%rdx +movd %xmm7,%rcx +movd %xmm10,%r8 +movd %xmm4,%r9 +pshufd $0x39,%xmm12,%xmm12 +pshufd $0x39,%xmm7,%xmm7 +pshufd $0x39,%xmm10,%xmm10 +pshufd $0x39,%xmm4,%xmm4 +xorl 64(%rsi),%edx +xorl 68(%rsi),%ecx +xorl 72(%rsi),%r8d +xorl 76(%rsi),%r9d +movl %edx,64(%rdi) +movl %ecx,68(%rdi) +movl %r8d,72(%rdi) +movl %r9d,76(%rdi) +movd %xmm12,%rdx +movd %xmm7,%rcx +movd %xmm10,%r8 +movd %xmm4,%r9 +pshufd $0x39,%xmm12,%xmm12 +pshufd $0x39,%xmm7,%xmm7 +pshufd $0x39,%xmm10,%xmm10 +pshufd $0x39,%xmm4,%xmm4 +xorl 128(%rsi),%edx +xorl 132(%rsi),%ecx +xorl 136(%rsi),%r8d +xorl 140(%rsi),%r9d +movl %edx,128(%rdi) +movl %ecx,132(%rdi) +movl %r8d,136(%rdi) +movl %r9d,140(%rdi) +movd %xmm12,%rdx +movd %xmm7,%rcx +movd %xmm10,%r8 +movd %xmm4,%r9 +xorl 192(%rsi),%edx +xorl 196(%rsi),%ecx +xorl 200(%rsi),%r8d +xorl 204(%rsi),%r9d +movl %edx,192(%rdi) +movl %ecx,196(%rdi) +movl %r8d,200(%rdi) +movl %r9d,204(%rdi) +paddd 304(%rsp),%xmm14 +paddd 128(%rsp),%xmm0 +paddd 192(%rsp),%xmm5 +paddd 256(%rsp),%xmm8 +movd %xmm14,%rdx +movd %xmm0,%rcx +movd %xmm5,%r8 +movd %xmm8,%r9 +pshufd $0x39,%xmm14,%xmm14 +pshufd $0x39,%xmm0,%xmm0 +pshufd $0x39,%xmm5,%xmm5 +pshufd $0x39,%xmm8,%xmm8 +xorl 16(%rsi),%edx +xorl 20(%rsi),%ecx +xorl 24(%rsi),%r8d +xorl 28(%rsi),%r9d +movl %edx,16(%rdi) +movl %ecx,20(%rdi) +movl %r8d,24(%rdi) +movl %r9d,28(%rdi) +movd %xmm14,%rdx +movd %xmm0,%rcx +movd %xmm5,%r8 +movd %xmm8,%r9 +pshufd $0x39,%xmm14,%xmm14 +pshufd $0x39,%xmm0,%xmm0 +pshufd $0x39,%xmm5,%xmm5 +pshufd $0x39,%xmm8,%xmm8 +xorl 80(%rsi),%edx +xorl 84(%rsi),%ecx +xorl 88(%rsi),%r8d +xorl 92(%rsi),%r9d +movl %edx,80(%rdi) +movl %ecx,84(%rdi) +movl %r8d,88(%rdi) +movl %r9d,92(%rdi) +movd %xmm14,%rdx +movd %xmm0,%rcx +movd %xmm5,%r8 +movd %xmm8,%r9 +pshufd $0x39,%xmm14,%xmm14 +pshufd $0x39,%xmm0,%xmm0 +pshufd $0x39,%xmm5,%xmm5 +pshufd $0x39,%xmm8,%xmm8 +xorl 144(%rsi),%edx +xorl 148(%rsi),%ecx +xorl 152(%rsi),%r8d +xorl 156(%rsi),%r9d +movl %edx,144(%rdi) +movl %ecx,148(%rdi) +movl %r8d,152(%rdi) +movl %r9d,156(%rdi) +movd %xmm14,%rdx +movd %xmm0,%rcx +movd %xmm5,%r8 +movd %xmm8,%r9 +xorl 208(%rsi),%edx +xorl 212(%rsi),%ecx +xorl 216(%rsi),%r8d +xorl 220(%rsi),%r9d +movl %edx,208(%rdi) +movl %ecx,212(%rdi) +movl %r8d,216(%rdi) +movl %r9d,220(%rdi) +paddd 352(%rsp),%xmm15 +paddd 368(%rsp),%xmm11 +paddd 144(%rsp),%xmm1 +paddd 208(%rsp),%xmm6 +movd %xmm15,%rdx +movd %xmm11,%rcx +movd %xmm1,%r8 +movd %xmm6,%r9 +pshufd $0x39,%xmm15,%xmm15 +pshufd $0x39,%xmm11,%xmm11 +pshufd $0x39,%xmm1,%xmm1 +pshufd $0x39,%xmm6,%xmm6 +xorl 32(%rsi),%edx +xorl 36(%rsi),%ecx +xorl 40(%rsi),%r8d +xorl 44(%rsi),%r9d +movl %edx,32(%rdi) +movl %ecx,36(%rdi) +movl %r8d,40(%rdi) +movl %r9d,44(%rdi) +movd %xmm15,%rdx +movd %xmm11,%rcx +movd %xmm1,%r8 +movd %xmm6,%r9 +pshufd $0x39,%xmm15,%xmm15 +pshufd $0x39,%xmm11,%xmm11 +pshufd $0x39,%xmm1,%xmm1 +pshufd $0x39,%xmm6,%xmm6 +xorl 96(%rsi),%edx +xorl 100(%rsi),%ecx +xorl 104(%rsi),%r8d +xorl 108(%rsi),%r9d +movl %edx,96(%rdi) +movl %ecx,100(%rdi) +movl %r8d,104(%rdi) +movl %r9d,108(%rdi) +movd %xmm15,%rdx +movd %xmm11,%rcx +movd %xmm1,%r8 +movd %xmm6,%r9 +pshufd $0x39,%xmm15,%xmm15 +pshufd $0x39,%xmm11,%xmm11 +pshufd $0x39,%xmm1,%xmm1 +pshufd $0x39,%xmm6,%xmm6 +xorl 160(%rsi),%edx +xorl 164(%rsi),%ecx +xorl 168(%rsi),%r8d +xorl 172(%rsi),%r9d +movl %edx,160(%rdi) +movl %ecx,164(%rdi) +movl %r8d,168(%rdi) +movl %r9d,172(%rdi) +movd %xmm15,%rdx +movd %xmm11,%rcx +movd %xmm1,%r8 +movd %xmm6,%r9 +xorl 224(%rsi),%edx +xorl 228(%rsi),%ecx +xorl 232(%rsi),%r8d +xorl 236(%rsi),%r9d +movl %edx,224(%rdi) +movl %ecx,228(%rdi) +movl %r8d,232(%rdi) +movl %r9d,236(%rdi) +paddd 224(%rsp),%xmm13 +paddd 272(%rsp),%xmm9 +paddd 320(%rsp),%xmm3 +paddd 160(%rsp),%xmm2 +movd %xmm13,%rdx +movd %xmm9,%rcx +movd %xmm3,%r8 +movd %xmm2,%r9 +pshufd $0x39,%xmm13,%xmm13 +pshufd $0x39,%xmm9,%xmm9 +pshufd $0x39,%xmm3,%xmm3 +pshufd $0x39,%xmm2,%xmm2 +xorl 48(%rsi),%edx +xorl 52(%rsi),%ecx +xorl 56(%rsi),%r8d +xorl 60(%rsi),%r9d +movl %edx,48(%rdi) +movl %ecx,52(%rdi) +movl %r8d,56(%rdi) +movl %r9d,60(%rdi) +movd %xmm13,%rdx +movd %xmm9,%rcx +movd %xmm3,%r8 +movd %xmm2,%r9 +pshufd $0x39,%xmm13,%xmm13 +pshufd $0x39,%xmm9,%xmm9 +pshufd $0x39,%xmm3,%xmm3 +pshufd $0x39,%xmm2,%xmm2 +xorl 112(%rsi),%edx +xorl 116(%rsi),%ecx +xorl 120(%rsi),%r8d +xorl 124(%rsi),%r9d +movl %edx,112(%rdi) +movl %ecx,116(%rdi) +movl %r8d,120(%rdi) +movl %r9d,124(%rdi) +movd %xmm13,%rdx +movd %xmm9,%rcx +movd %xmm3,%r8 +movd %xmm2,%r9 +pshufd $0x39,%xmm13,%xmm13 +pshufd $0x39,%xmm9,%xmm9 +pshufd $0x39,%xmm3,%xmm3 +pshufd $0x39,%xmm2,%xmm2 +xorl 176(%rsi),%edx +xorl 180(%rsi),%ecx +xorl 184(%rsi),%r8d +xorl 188(%rsi),%r9d +movl %edx,176(%rdi) +movl %ecx,180(%rdi) +movl %r8d,184(%rdi) +movl %r9d,188(%rdi) +movd %xmm13,%rdx +movd %xmm9,%rcx +movd %xmm3,%r8 +movd %xmm2,%r9 +xorl 240(%rsi),%edx +xorl 244(%rsi),%ecx +xorl 248(%rsi),%r8d +xorl 252(%rsi),%r9d +movl %edx,240(%rdi) +movl %ecx,244(%rdi) +movl %r8d,248(%rdi) +movl %r9d,252(%rdi) +movq 480(%rsp),%r9 +sub $256,%r9 +add $256,%rsi +add $256,%rdi +cmp $256,%r9 +jae ._bytesatleast256 + +cmp $0,%r9 +jbe ._done + +._bytesbetween1and255: +cmp $64,%r9 +jae ._nocopy + +mov %rdi,%rdx +leaq 0(%rsp),%rdi +mov %r9,%rcx +rep movsb +leaq 0(%rsp),%rdi +leaq 0(%rsp),%rsi + +._nocopy: +movq %r9,480(%rsp) +movdqa 112(%rsp),%xmm0 +movdqa 64(%rsp),%xmm1 +movdqa 80(%rsp),%xmm2 +movdqa 96(%rsp),%xmm3 +movdqa %xmm1,%xmm4 +mov $20,%rcx + +.p2align 4 +._mainloop2: +paddd %xmm0,%xmm4 +movdqa %xmm0,%xmm5 +movdqa %xmm4,%xmm6 +pslld $7,%xmm4 +psrld $25,%xmm6 +pxor %xmm4,%xmm3 +pxor %xmm6,%xmm3 +paddd %xmm3,%xmm5 +movdqa %xmm3,%xmm4 +movdqa %xmm5,%xmm6 +pslld $9,%xmm5 +psrld $23,%xmm6 +pxor %xmm5,%xmm2 +pshufd $0x93,%xmm3,%xmm3 +pxor %xmm6,%xmm2 +paddd %xmm2,%xmm4 +movdqa %xmm2,%xmm5 +movdqa %xmm4,%xmm6 +pslld $13,%xmm4 +psrld $19,%xmm6 +pxor %xmm4,%xmm1 +pshufd $0x4e,%xmm2,%xmm2 +pxor %xmm6,%xmm1 +paddd %xmm1,%xmm5 +movdqa %xmm3,%xmm4 +movdqa %xmm5,%xmm6 +pslld $18,%xmm5 +psrld $14,%xmm6 +pxor %xmm5,%xmm0 +pshufd $0x39,%xmm1,%xmm1 +pxor %xmm6,%xmm0 +paddd %xmm0,%xmm4 +movdqa %xmm0,%xmm5 +movdqa %xmm4,%xmm6 +pslld $7,%xmm4 +psrld $25,%xmm6 +pxor %xmm4,%xmm1 +pxor %xmm6,%xmm1 +paddd %xmm1,%xmm5 +movdqa %xmm1,%xmm4 +movdqa %xmm5,%xmm6 +pslld $9,%xmm5 +psrld $23,%xmm6 +pxor %xmm5,%xmm2 +pshufd $0x93,%xmm1,%xmm1 +pxor %xmm6,%xmm2 +paddd %xmm2,%xmm4 +movdqa %xmm2,%xmm5 +movdqa %xmm4,%xmm6 +pslld $13,%xmm4 +psrld $19,%xmm6 +pxor %xmm4,%xmm3 +pshufd $0x4e,%xmm2,%xmm2 +pxor %xmm6,%xmm3 +paddd %xmm3,%xmm5 +movdqa %xmm1,%xmm4 +movdqa %xmm5,%xmm6 +pslld $18,%xmm5 +psrld $14,%xmm6 +pxor %xmm5,%xmm0 +pshufd $0x39,%xmm3,%xmm3 +pxor %xmm6,%xmm0 +paddd %xmm0,%xmm4 +movdqa %xmm0,%xmm5 +movdqa %xmm4,%xmm6 +pslld $7,%xmm4 +psrld $25,%xmm6 +pxor %xmm4,%xmm3 +pxor %xmm6,%xmm3 +paddd %xmm3,%xmm5 +movdqa %xmm3,%xmm4 +movdqa %xmm5,%xmm6 +pslld $9,%xmm5 +psrld $23,%xmm6 +pxor %xmm5,%xmm2 +pshufd $0x93,%xmm3,%xmm3 +pxor %xmm6,%xmm2 +paddd %xmm2,%xmm4 +movdqa %xmm2,%xmm5 +movdqa %xmm4,%xmm6 +pslld $13,%xmm4 +psrld $19,%xmm6 +pxor %xmm4,%xmm1 +pshufd $0x4e,%xmm2,%xmm2 +pxor %xmm6,%xmm1 +paddd %xmm1,%xmm5 +movdqa %xmm3,%xmm4 +movdqa %xmm5,%xmm6 +pslld $18,%xmm5 +psrld $14,%xmm6 +pxor %xmm5,%xmm0 +pshufd $0x39,%xmm1,%xmm1 +pxor %xmm6,%xmm0 +paddd %xmm0,%xmm4 +movdqa %xmm0,%xmm5 +movdqa %xmm4,%xmm6 +pslld $7,%xmm4 +psrld $25,%xmm6 +pxor %xmm4,%xmm1 +pxor %xmm6,%xmm1 +paddd %xmm1,%xmm5 +movdqa %xmm1,%xmm4 +movdqa %xmm5,%xmm6 +pslld $9,%xmm5 +psrld $23,%xmm6 +pxor %xmm5,%xmm2 +pshufd $0x93,%xmm1,%xmm1 +pxor %xmm6,%xmm2 +paddd %xmm2,%xmm4 +movdqa %xmm2,%xmm5 +movdqa %xmm4,%xmm6 +pslld $13,%xmm4 +psrld $19,%xmm6 +pxor %xmm4,%xmm3 +pshufd $0x4e,%xmm2,%xmm2 +pxor %xmm6,%xmm3 +sub $4,%rcx +paddd %xmm3,%xmm5 +movdqa %xmm1,%xmm4 +movdqa %xmm5,%xmm6 +pslld $18,%xmm5 +pxor %xmm7,%xmm7 +psrld $14,%xmm6 +pxor %xmm5,%xmm0 +pshufd $0x39,%xmm3,%xmm3 +pxor %xmm6,%xmm0 +ja ._mainloop2 + +paddd 112(%rsp),%xmm0 +paddd 64(%rsp),%xmm1 +paddd 80(%rsp),%xmm2 +paddd 96(%rsp),%xmm3 +movd %xmm0,%rcx +movd %xmm1,%r8 +movd %xmm2,%r9 +movd %xmm3,%rax +pshufd $0x39,%xmm0,%xmm0 +pshufd $0x39,%xmm1,%xmm1 +pshufd $0x39,%xmm2,%xmm2 +pshufd $0x39,%xmm3,%xmm3 +xorl 0(%rsi),%ecx +xorl 48(%rsi),%r8d +xorl 32(%rsi),%r9d +xorl 16(%rsi),%eax +movl %ecx,0(%rdi) +movl %r8d,48(%rdi) +movl %r9d,32(%rdi) +movl %eax,16(%rdi) +movd %xmm0,%rcx +movd %xmm1,%r8 +movd %xmm2,%r9 +movd %xmm3,%rax +pshufd $0x39,%xmm0,%xmm0 +pshufd $0x39,%xmm1,%xmm1 +pshufd $0x39,%xmm2,%xmm2 +pshufd $0x39,%xmm3,%xmm3 +xorl 20(%rsi),%ecx +xorl 4(%rsi),%r8d +xorl 52(%rsi),%r9d +xorl 36(%rsi),%eax +movl %ecx,20(%rdi) +movl %r8d,4(%rdi) +movl %r9d,52(%rdi) +movl %eax,36(%rdi) +movd %xmm0,%rcx +movd %xmm1,%r8 +movd %xmm2,%r9 +movd %xmm3,%rax +pshufd $0x39,%xmm0,%xmm0 +pshufd $0x39,%xmm1,%xmm1 +pshufd $0x39,%xmm2,%xmm2 +pshufd $0x39,%xmm3,%xmm3 +xorl 40(%rsi),%ecx +xorl 24(%rsi),%r8d +xorl 8(%rsi),%r9d +xorl 56(%rsi),%eax +movl %ecx,40(%rdi) +movl %r8d,24(%rdi) +movl %r9d,8(%rdi) +movl %eax,56(%rdi) +movd %xmm0,%rcx +movd %xmm1,%r8 +movd %xmm2,%r9 +movd %xmm3,%rax +xorl 60(%rsi),%ecx +xorl 44(%rsi),%r8d +xorl 28(%rsi),%r9d +xorl 12(%rsi),%eax +movl %ecx,60(%rdi) +movl %r8d,44(%rdi) +movl %r9d,28(%rdi) +movl %eax,12(%rdi) +movq 480(%rsp),%r9 +movq 472(%rsp),%rcx +add $1,%rcx +mov %rcx,%r8 +shr $32,%r8 +movl %ecx,80(%rsp) +movl %r8d,4+96(%rsp) +movq %rcx,472(%rsp) +cmp $64,%r9 +ja ._bytesatleast65 +jae ._bytesatleast64 + +mov %rdi,%rsi +mov %rdx,%rdi +mov %r9,%rcx +rep movsb + +._bytesatleast64: +._done: +movq 416(%rsp),%r11 +movq 424(%rsp),%r12 +movq 432(%rsp),%r13 +movq 440(%rsp),%r14 +movq 448(%rsp),%r15 +movq 456(%rsp),%rbx +movq 464(%rsp),%rbp +add %r11,%rsp +xor %rax,%rax +mov %rsi,%rdx +ret + +._bytesatleast65: +sub $64,%r9 +add $64,%rdi +add $64,%rsi +jmp ._bytesbetween1and255 + +#endif + +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",%progbits +#endif diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6.c b/libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6.c new file mode 100644 index 0000000000..0a6fee0f3e --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6.c @@ -0,0 +1,31 @@ + +#include + +#include "utils.h" + +#include "../stream_salsa20.h" +#include "salsa20_xmm6.h" + +#ifdef HAVE_AMD64_ASM + +#ifdef __cplusplus +extern "C" { +#endif +extern int stream_salsa20_xmm6(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + +extern int stream_salsa20_xmm6_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + uint64_t ic, const unsigned char *k); +#ifdef __cplusplus +} +#endif + +struct crypto_stream_salsa20_implementation + crypto_stream_salsa20_xmm6_implementation = { + SODIUM_C99(.stream =) stream_salsa20_xmm6, + SODIUM_C99(.stream_xor_ic =) stream_salsa20_xmm6_xor_ic, + }; + +#endif diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6.h b/libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6.h new file mode 100644 index 0000000000..d38473a9ff --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6/salsa20_xmm6.h @@ -0,0 +1,8 @@ + +#include + +#include "../stream_salsa20.h" +#include "crypto_stream_salsa20.h" + +extern struct crypto_stream_salsa20_implementation + crypto_stream_salsa20_xmm6_implementation; diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c new file mode 100644 index 0000000000..18d4773ec9 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.c @@ -0,0 +1,131 @@ + +#include +#include +#include + +#include "crypto_stream_salsa20.h" +#include "private/common.h" +#include "private/sse2_64_32.h" +#include "utils.h" + +#if defined(HAVE_AVX2INTRIN_H) && defined(HAVE_EMMINTRIN_H) && \ + defined(HAVE_TMMINTRIN_H) && defined(HAVE_SMMINTRIN_H) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# pragma GCC target("ssse3") +# pragma GCC target("sse4.1") +# pragma GCC target("avx2") +# endif + +#include +#include +#include +#include + +# include "../stream_salsa20.h" +# include "salsa20_xmm6int-avx2.h" + +# define ROUNDS 20 + +typedef struct salsa_ctx { + uint32_t input[16]; +} salsa_ctx; + +static const int TR[16] = { + 0, 5, 10, 15, 12, 1, 6, 11, 8, 13, 2, 7, 4, 9, 14, 3 +}; + +static void +salsa_keysetup(salsa_ctx *ctx, const uint8_t *k) +{ + ctx->input[TR[1]] = LOAD32_LE(k + 0); + ctx->input[TR[2]] = LOAD32_LE(k + 4); + ctx->input[TR[3]] = LOAD32_LE(k + 8); + ctx->input[TR[4]] = LOAD32_LE(k + 12); + ctx->input[TR[11]] = LOAD32_LE(k + 16); + ctx->input[TR[12]] = LOAD32_LE(k + 20); + ctx->input[TR[13]] = LOAD32_LE(k + 24); + ctx->input[TR[14]] = LOAD32_LE(k + 28); + ctx->input[TR[0]] = 0x61707865; + ctx->input[TR[5]] = 0x3320646e; + ctx->input[TR[10]] = 0x79622d32; + ctx->input[TR[15]] = 0x6b206574; +} + +static void +salsa_ivsetup(salsa_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[TR[6]] = LOAD32_LE(iv + 0); + ctx->input[TR[7]] = LOAD32_LE(iv + 4); + ctx->input[TR[8]] = counter == NULL ? 0 : LOAD32_LE(counter + 0); + ctx->input[TR[9]] = counter == NULL ? 0 : LOAD32_LE(counter + 4); +} + +static void +salsa20_encrypt_bytes(salsa_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t * const x = &ctx->input[0]; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } + +#include "u8.h" +#include "u4.h" +#include "u1.h" +#include "u0.h" +} + +static int +stream_avx2(unsigned char *c, unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + struct salsa_ctx ctx; + + if (!clen) { + return 0; + } + COMPILER_ASSERT(crypto_stream_salsa20_KEYBYTES == 256 / 8); + salsa_keysetup(&ctx, k); + salsa_ivsetup(&ctx, n, NULL); + memset(c, 0, clen); + salsa20_encrypt_bytes(&ctx, c, c, clen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_avx2_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + struct salsa_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (!mlen) { + return 0; + } + ic_high = (uint32_t) (ic >> 32); + ic_low = (uint32_t) ic; + STORE32_LE(&ic_bytes[0], ic_low); + STORE32_LE(&ic_bytes[4], ic_high); + salsa_keysetup(&ctx, k); + salsa_ivsetup(&ctx, n, ic_bytes); + salsa20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_salsa20_implementation + crypto_stream_salsa20_xmm6int_avx2_implementation = { + SODIUM_C99(.stream =) stream_avx2, + SODIUM_C99(.stream_xor_ic =) stream_avx2_xor_ic + }; + +#endif diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.h b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.h new file mode 100644 index 0000000000..0924e9baff --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-avx2.h @@ -0,0 +1,8 @@ + +#include + +#include "../stream_salsa20.h" +#include "crypto_stream_salsa20.h" + +extern struct crypto_stream_salsa20_implementation + crypto_stream_salsa20_xmm6int_avx2_implementation; diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c new file mode 100644 index 0000000000..d8e53a6554 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.c @@ -0,0 +1,122 @@ + +#include +#include +#include + +#include "crypto_stream_salsa20.h" +#include "private/common.h" +#include "private/sse2_64_32.h" +#include "utils.h" + +#ifdef HAVE_EMMINTRIN_H + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# endif +# include + +# include "../stream_salsa20.h" +# include "salsa20_xmm6int-sse2.h" + +# define ROUNDS 20 + +typedef struct salsa_ctx { + uint32_t input[16]; +} salsa_ctx; + +static const int TR[16] = { + 0, 5, 10, 15, 12, 1, 6, 11, 8, 13, 2, 7, 4, 9, 14, 3 +}; + +static void +salsa_keysetup(salsa_ctx *ctx, const uint8_t *k) +{ + ctx->input[TR[1]] = LOAD32_LE(k + 0); + ctx->input[TR[2]] = LOAD32_LE(k + 4); + ctx->input[TR[3]] = LOAD32_LE(k + 8); + ctx->input[TR[4]] = LOAD32_LE(k + 12); + ctx->input[TR[11]] = LOAD32_LE(k + 16); + ctx->input[TR[12]] = LOAD32_LE(k + 20); + ctx->input[TR[13]] = LOAD32_LE(k + 24); + ctx->input[TR[14]] = LOAD32_LE(k + 28); + ctx->input[TR[0]] = 0x61707865; + ctx->input[TR[5]] = 0x3320646e; + ctx->input[TR[10]] = 0x79622d32; + ctx->input[TR[15]] = 0x6b206574; +} + +static void +salsa_ivsetup(salsa_ctx *ctx, const uint8_t *iv, const uint8_t *counter) +{ + ctx->input[TR[6]] = LOAD32_LE(iv + 0); + ctx->input[TR[7]] = LOAD32_LE(iv + 4); + ctx->input[TR[8]] = counter == NULL ? 0 : LOAD32_LE(counter + 0); + ctx->input[TR[9]] = counter == NULL ? 0 : LOAD32_LE(counter + 4); +} + +static void +salsa20_encrypt_bytes(salsa_ctx *ctx, const uint8_t *m, uint8_t *c, + unsigned long long bytes) +{ + uint32_t * const x = &ctx->input[0]; + + if (!bytes) { + return; /* LCOV_EXCL_LINE */ + } + +#include "u4.h" +#include "u1.h" +#include "u0.h" +} + +static int +stream_sse2(unsigned char *c, unsigned long long clen, const unsigned char *n, + const unsigned char *k) +{ + struct salsa_ctx ctx; + + if (!clen) { + return 0; + } + COMPILER_ASSERT(crypto_stream_salsa20_KEYBYTES == 256 / 8); + salsa_keysetup(&ctx, k); + salsa_ivsetup(&ctx, n, NULL); + memset(c, 0, clen); + salsa20_encrypt_bytes(&ctx, c, c, clen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +static int +stream_sse2_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, uint64_t ic, + const unsigned char *k) +{ + struct salsa_ctx ctx; + uint8_t ic_bytes[8]; + uint32_t ic_high; + uint32_t ic_low; + + if (!mlen) { + return 0; + } + ic_high = (uint32_t) (ic >> 32); + ic_low = (uint32_t) (ic); + STORE32_LE(&ic_bytes[0], ic_low); + STORE32_LE(&ic_bytes[4], ic_high); + salsa_keysetup(&ctx, k); + salsa_ivsetup(&ctx, n, ic_bytes); + salsa20_encrypt_bytes(&ctx, m, c, mlen); + sodium_memzero(&ctx, sizeof ctx); + + return 0; +} + +struct crypto_stream_salsa20_implementation + crypto_stream_salsa20_xmm6int_sse2_implementation = { + SODIUM_C99(.stream =) stream_sse2, + SODIUM_C99(.stream_xor_ic =) stream_sse2_xor_ic + }; + +#endif diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.h b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.h new file mode 100644 index 0000000000..ed52a8bcbe --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/salsa20_xmm6int-sse2.h @@ -0,0 +1,8 @@ + +#include + +#include "../stream_salsa20.h" +#include "crypto_stream_salsa20.h" + +extern struct crypto_stream_salsa20_implementation + crypto_stream_salsa20_xmm6int_sse2_implementation; diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u0.h b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u0.h new file mode 100644 index 0000000000..b2d4168058 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u0.h @@ -0,0 +1,195 @@ +if (bytes > 0) { + __m128i diag0 = _mm_loadu_si128((__m128i *) (x + 0)); + __m128i diag1 = _mm_loadu_si128((__m128i *) (x + 4)); + __m128i diag2 = _mm_loadu_si128((__m128i *) (x + 8)); + __m128i diag3 = _mm_loadu_si128((__m128i *) (x + 12)); + __m128i a0, a1, a2, a3, a4, a5, a6, a7; + __m128i b0, b1, b2, b3, b4, b5, b6, b7; + uint8_t partialblock[64]; + + unsigned int i; + + a0 = diag1; + for (i = 0; i < ROUNDS; i += 4) { + a0 = _mm_add_epi32(a0, diag0); + a1 = diag0; + b0 = a0; + a0 = _mm_slli_epi32(a0, 7); + b0 = _mm_srli_epi32(b0, 25); + diag3 = _mm_xor_si128(diag3, a0); + + diag3 = _mm_xor_si128(diag3, b0); + + a1 = _mm_add_epi32(a1, diag3); + a2 = diag3; + b1 = a1; + a1 = _mm_slli_epi32(a1, 9); + b1 = _mm_srli_epi32(b1, 23); + diag2 = _mm_xor_si128(diag2, a1); + diag3 = _mm_shuffle_epi32(diag3, 0x93); + diag2 = _mm_xor_si128(diag2, b1); + + a2 = _mm_add_epi32(a2, diag2); + a3 = diag2; + b2 = a2; + a2 = _mm_slli_epi32(a2, 13); + b2 = _mm_srli_epi32(b2, 19); + diag1 = _mm_xor_si128(diag1, a2); + diag2 = _mm_shuffle_epi32(diag2, 0x4e); + diag1 = _mm_xor_si128(diag1, b2); + + a3 = _mm_add_epi32(a3, diag1); + a4 = diag3; + b3 = a3; + a3 = _mm_slli_epi32(a3, 18); + b3 = _mm_srli_epi32(b3, 14); + diag0 = _mm_xor_si128(diag0, a3); + diag1 = _mm_shuffle_epi32(diag1, 0x39); + diag0 = _mm_xor_si128(diag0, b3); + + a4 = _mm_add_epi32(a4, diag0); + a5 = diag0; + b4 = a4; + a4 = _mm_slli_epi32(a4, 7); + b4 = _mm_srli_epi32(b4, 25); + diag1 = _mm_xor_si128(diag1, a4); + + diag1 = _mm_xor_si128(diag1, b4); + + a5 = _mm_add_epi32(a5, diag1); + a6 = diag1; + b5 = a5; + a5 = _mm_slli_epi32(a5, 9); + b5 = _mm_srli_epi32(b5, 23); + diag2 = _mm_xor_si128(diag2, a5); + diag1 = _mm_shuffle_epi32(diag1, 0x93); + diag2 = _mm_xor_si128(diag2, b5); + + a6 = _mm_add_epi32(a6, diag2); + a7 = diag2; + b6 = a6; + a6 = _mm_slli_epi32(a6, 13); + b6 = _mm_srli_epi32(b6, 19); + diag3 = _mm_xor_si128(diag3, a6); + diag2 = _mm_shuffle_epi32(diag2, 0x4e); + diag3 = _mm_xor_si128(diag3, b6); + + a7 = _mm_add_epi32(a7, diag3); + a0 = diag1; + b7 = a7; + a7 = _mm_slli_epi32(a7, 18); + b7 = _mm_srli_epi32(b7, 14); + diag0 = _mm_xor_si128(diag0, a7); + diag3 = _mm_shuffle_epi32(diag3, 0x39); + diag0 = _mm_xor_si128(diag0, b7); + + a0 = _mm_add_epi32(a0, diag0); + a1 = diag0; + b0 = a0; + a0 = _mm_slli_epi32(a0, 7); + b0 = _mm_srli_epi32(b0, 25); + diag3 = _mm_xor_si128(diag3, a0); + + diag3 = _mm_xor_si128(diag3, b0); + + a1 = _mm_add_epi32(a1, diag3); + a2 = diag3; + b1 = a1; + a1 = _mm_slli_epi32(a1, 9); + b1 = _mm_srli_epi32(b1, 23); + diag2 = _mm_xor_si128(diag2, a1); + diag3 = _mm_shuffle_epi32(diag3, 0x93); + diag2 = _mm_xor_si128(diag2, b1); + + a2 = _mm_add_epi32(a2, diag2); + a3 = diag2; + b2 = a2; + a2 = _mm_slli_epi32(a2, 13); + b2 = _mm_srli_epi32(b2, 19); + diag1 = _mm_xor_si128(diag1, a2); + diag2 = _mm_shuffle_epi32(diag2, 0x4e); + diag1 = _mm_xor_si128(diag1, b2); + + a3 = _mm_add_epi32(a3, diag1); + a4 = diag3; + b3 = a3; + a3 = _mm_slli_epi32(a3, 18); + b3 = _mm_srli_epi32(b3, 14); + diag0 = _mm_xor_si128(diag0, a3); + diag1 = _mm_shuffle_epi32(diag1, 0x39); + diag0 = _mm_xor_si128(diag0, b3); + + a4 = _mm_add_epi32(a4, diag0); + a5 = diag0; + b4 = a4; + a4 = _mm_slli_epi32(a4, 7); + b4 = _mm_srli_epi32(b4, 25); + diag1 = _mm_xor_si128(diag1, a4); + + diag1 = _mm_xor_si128(diag1, b4); + + a5 = _mm_add_epi32(a5, diag1); + a6 = diag1; + b5 = a5; + a5 = _mm_slli_epi32(a5, 9); + b5 = _mm_srli_epi32(b5, 23); + diag2 = _mm_xor_si128(diag2, a5); + diag1 = _mm_shuffle_epi32(diag1, 0x93); + diag2 = _mm_xor_si128(diag2, b5); + + a6 = _mm_add_epi32(a6, diag2); + a7 = diag2; + b6 = a6; + a6 = _mm_slli_epi32(a6, 13); + b6 = _mm_srli_epi32(b6, 19); + diag3 = _mm_xor_si128(diag3, a6); + diag2 = _mm_shuffle_epi32(diag2, 0x4e); + diag3 = _mm_xor_si128(diag3, b6); + + a7 = _mm_add_epi32(a7, diag3); + a0 = diag1; + b7 = a7; + a7 = _mm_slli_epi32(a7, 18); + b7 = _mm_srli_epi32(b7, 14); + diag0 = _mm_xor_si128(diag0, a7); + diag3 = _mm_shuffle_epi32(diag3, 0x39); + diag0 = _mm_xor_si128(diag0, b7); + } + + diag0 = _mm_add_epi32(diag0, _mm_loadu_si128((__m128i *) (x + 0))); + diag1 = _mm_add_epi32(diag1, _mm_loadu_si128((__m128i *) (x + 4))); + diag2 = _mm_add_epi32(diag2, _mm_loadu_si128((__m128i *) (x + 8))); + diag3 = _mm_add_epi32(diag3, _mm_loadu_si128((__m128i *) (x + 12))); + +#define ONEQUAD_SHUFFLE(A, B, C, D) \ + do { \ + uint32_t in##A = _mm_cvtsi128_si32(diag0); \ + uint32_t in##B = _mm_cvtsi128_si32(diag1); \ + uint32_t in##C = _mm_cvtsi128_si32(diag2); \ + uint32_t in##D = _mm_cvtsi128_si32(diag3); \ + diag0 = _mm_shuffle_epi32(diag0, 0x39); \ + diag1 = _mm_shuffle_epi32(diag1, 0x39); \ + diag2 = _mm_shuffle_epi32(diag2, 0x39); \ + diag3 = _mm_shuffle_epi32(diag3, 0x39); \ + *(uint32_t *) (partialblock + (A * 4)) = in##A; \ + *(uint32_t *) (partialblock + (B * 4)) = in##B; \ + *(uint32_t *) (partialblock + (C * 4)) = in##C; \ + *(uint32_t *) (partialblock + (D * 4)) = in##D; \ + } while (0) + +#define ONEQUAD(A, B, C, D) ONEQUAD_SHUFFLE(A, B, C, D) + + ONEQUAD(0, 12, 8, 4); + ONEQUAD(5, 1, 13, 9); + ONEQUAD(10, 6, 2, 14); + ONEQUAD(15, 11, 7, 3); + +#undef ONEQUAD +#undef ONEQUAD_SHUFFLE + + for (i = 0; i < bytes; i++) { + c[i] = m[i] ^ partialblock[i]; + } + + sodium_memzero(partialblock, sizeof partialblock); +} diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u1.h b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u1.h new file mode 100644 index 0000000000..c245d9565f --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u1.h @@ -0,0 +1,207 @@ +while (bytes >= 64) { + __m128i diag0 = _mm_loadu_si128((__m128i *) (x + 0)); + __m128i diag1 = _mm_loadu_si128((__m128i *) (x + 4)); + __m128i diag2 = _mm_loadu_si128((__m128i *) (x + 8)); + __m128i diag3 = _mm_loadu_si128((__m128i *) (x + 12)); + __m128i a0, a1, a2, a3, a4, a5, a6, a7; + __m128i b0, b1, b2, b3, b4, b5, b6, b7; + + uint32_t in8; + uint32_t in9; + int i; + + a0 = diag1; + for (i = 0; i < ROUNDS; i += 4) { + a0 = _mm_add_epi32(a0, diag0); + a1 = diag0; + b0 = a0; + a0 = _mm_slli_epi32(a0, 7); + b0 = _mm_srli_epi32(b0, 25); + diag3 = _mm_xor_si128(diag3, a0); + + diag3 = _mm_xor_si128(diag3, b0); + + a1 = _mm_add_epi32(a1, diag3); + a2 = diag3; + b1 = a1; + a1 = _mm_slli_epi32(a1, 9); + b1 = _mm_srli_epi32(b1, 23); + diag2 = _mm_xor_si128(diag2, a1); + diag3 = _mm_shuffle_epi32(diag3, 0x93); + diag2 = _mm_xor_si128(diag2, b1); + + a2 = _mm_add_epi32(a2, diag2); + a3 = diag2; + b2 = a2; + a2 = _mm_slli_epi32(a2, 13); + b2 = _mm_srli_epi32(b2, 19); + diag1 = _mm_xor_si128(diag1, a2); + diag2 = _mm_shuffle_epi32(diag2, 0x4e); + diag1 = _mm_xor_si128(diag1, b2); + + a3 = _mm_add_epi32(a3, diag1); + a4 = diag3; + b3 = a3; + a3 = _mm_slli_epi32(a3, 18); + b3 = _mm_srli_epi32(b3, 14); + diag0 = _mm_xor_si128(diag0, a3); + diag1 = _mm_shuffle_epi32(diag1, 0x39); + diag0 = _mm_xor_si128(diag0, b3); + + a4 = _mm_add_epi32(a4, diag0); + a5 = diag0; + b4 = a4; + a4 = _mm_slli_epi32(a4, 7); + b4 = _mm_srli_epi32(b4, 25); + diag1 = _mm_xor_si128(diag1, a4); + + diag1 = _mm_xor_si128(diag1, b4); + + a5 = _mm_add_epi32(a5, diag1); + a6 = diag1; + b5 = a5; + a5 = _mm_slli_epi32(a5, 9); + b5 = _mm_srli_epi32(b5, 23); + diag2 = _mm_xor_si128(diag2, a5); + diag1 = _mm_shuffle_epi32(diag1, 0x93); + diag2 = _mm_xor_si128(diag2, b5); + + a6 = _mm_add_epi32(a6, diag2); + a7 = diag2; + b6 = a6; + a6 = _mm_slli_epi32(a6, 13); + b6 = _mm_srli_epi32(b6, 19); + diag3 = _mm_xor_si128(diag3, a6); + diag2 = _mm_shuffle_epi32(diag2, 0x4e); + diag3 = _mm_xor_si128(diag3, b6); + + a7 = _mm_add_epi32(a7, diag3); + a0 = diag1; + b7 = a7; + a7 = _mm_slli_epi32(a7, 18); + b7 = _mm_srli_epi32(b7, 14); + diag0 = _mm_xor_si128(diag0, a7); + diag3 = _mm_shuffle_epi32(diag3, 0x39); + diag0 = _mm_xor_si128(diag0, b7); + + a0 = _mm_add_epi32(a0, diag0); + a1 = diag0; + b0 = a0; + a0 = _mm_slli_epi32(a0, 7); + b0 = _mm_srli_epi32(b0, 25); + diag3 = _mm_xor_si128(diag3, a0); + + diag3 = _mm_xor_si128(diag3, b0); + + a1 = _mm_add_epi32(a1, diag3); + a2 = diag3; + b1 = a1; + a1 = _mm_slli_epi32(a1, 9); + b1 = _mm_srli_epi32(b1, 23); + diag2 = _mm_xor_si128(diag2, a1); + diag3 = _mm_shuffle_epi32(diag3, 0x93); + diag2 = _mm_xor_si128(diag2, b1); + + a2 = _mm_add_epi32(a2, diag2); + a3 = diag2; + b2 = a2; + a2 = _mm_slli_epi32(a2, 13); + b2 = _mm_srli_epi32(b2, 19); + diag1 = _mm_xor_si128(diag1, a2); + diag2 = _mm_shuffle_epi32(diag2, 0x4e); + diag1 = _mm_xor_si128(diag1, b2); + + a3 = _mm_add_epi32(a3, diag1); + a4 = diag3; + b3 = a3; + a3 = _mm_slli_epi32(a3, 18); + b3 = _mm_srli_epi32(b3, 14); + diag0 = _mm_xor_si128(diag0, a3); + diag1 = _mm_shuffle_epi32(diag1, 0x39); + diag0 = _mm_xor_si128(diag0, b3); + + a4 = _mm_add_epi32(a4, diag0); + a5 = diag0; + b4 = a4; + a4 = _mm_slli_epi32(a4, 7); + b4 = _mm_srli_epi32(b4, 25); + diag1 = _mm_xor_si128(diag1, a4); + + diag1 = _mm_xor_si128(diag1, b4); + + a5 = _mm_add_epi32(a5, diag1); + a6 = diag1; + b5 = a5; + a5 = _mm_slli_epi32(a5, 9); + b5 = _mm_srli_epi32(b5, 23); + diag2 = _mm_xor_si128(diag2, a5); + diag1 = _mm_shuffle_epi32(diag1, 0x93); + diag2 = _mm_xor_si128(diag2, b5); + + a6 = _mm_add_epi32(a6, diag2); + a7 = diag2; + b6 = a6; + a6 = _mm_slli_epi32(a6, 13); + b6 = _mm_srli_epi32(b6, 19); + diag3 = _mm_xor_si128(diag3, a6); + diag2 = _mm_shuffle_epi32(diag2, 0x4e); + diag3 = _mm_xor_si128(diag3, b6); + + a7 = _mm_add_epi32(a7, diag3); + a0 = diag1; + b7 = a7; + a7 = _mm_slli_epi32(a7, 18); + b7 = _mm_srli_epi32(b7, 14); + diag0 = _mm_xor_si128(diag0, a7); + diag3 = _mm_shuffle_epi32(diag3, 0x39); + diag0 = _mm_xor_si128(diag0, b7); + } + + diag0 = _mm_add_epi32(diag0, _mm_loadu_si128((__m128i *) (x + 0))); + diag1 = _mm_add_epi32(diag1, _mm_loadu_si128((__m128i *) (x + 4))); + diag2 = _mm_add_epi32(diag2, _mm_loadu_si128((__m128i *) (x + 8))); + diag3 = _mm_add_epi32(diag3, _mm_loadu_si128((__m128i *) (x + 12))); + +#define ONEQUAD_SHUFFLE(A, B, C, D) \ + do { \ + uint32_t in##A = _mm_cvtsi128_si32(diag0); \ + uint32_t in##B = _mm_cvtsi128_si32(diag1); \ + uint32_t in##C = _mm_cvtsi128_si32(diag2); \ + uint32_t in##D = _mm_cvtsi128_si32(diag3); \ + diag0 = _mm_shuffle_epi32(diag0, 0x39); \ + diag1 = _mm_shuffle_epi32(diag1, 0x39); \ + diag2 = _mm_shuffle_epi32(diag2, 0x39); \ + diag3 = _mm_shuffle_epi32(diag3, 0x39); \ + in##A ^= *(uint32_t *) (m + (A * 4)); \ + in##B ^= *(uint32_t *) (m + (B * 4)); \ + in##C ^= *(uint32_t *) (m + (C * 4)); \ + in##D ^= *(uint32_t *) (m + (D * 4)); \ + *(uint32_t *) (c + (A * 4)) = in##A; \ + *(uint32_t *) (c + (B * 4)) = in##B; \ + *(uint32_t *) (c + (C * 4)) = in##C; \ + *(uint32_t *) (c + (D * 4)) = in##D; \ + } while (0) + +#define ONEQUAD(A, B, C, D) ONEQUAD_SHUFFLE(A, B, C, D) + + ONEQUAD(0, 12, 8, 4); + ONEQUAD(5, 1, 13, 9); + ONEQUAD(10, 6, 2, 14); + ONEQUAD(15, 11, 7, 3); + +#undef ONEQUAD +#undef ONEQUAD_SHUFFLE + + in8 = x[8]; + in9 = x[13]; + in8++; + if (in8 == 0) { + in9++; + } + x[8] = in8; + x[13] = in9; + + c += 64; + m += 64; + bytes -= 64; +} diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u4.h b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u4.h new file mode 100644 index 0000000000..61d935fc90 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u4.h @@ -0,0 +1,547 @@ +if (bytes >= 256) { + __m128i y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, + y15; + __m128i z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, + z15; + __m128i orig0, orig1, orig2, orig3, orig4, orig5, orig6, orig7, orig8, + orig9, orig10, orig11, orig12, orig13, orig14, orig15; + + uint32_t in8; + uint32_t in9; + int i; + + /* element broadcast immediate for _mm_shuffle_epi32 are in order: + 0x00, 0x55, 0xaa, 0xff */ + z0 = _mm_loadu_si128((__m128i *) (x + 0)); + z5 = _mm_shuffle_epi32(z0, 0x55); + z10 = _mm_shuffle_epi32(z0, 0xaa); + z15 = _mm_shuffle_epi32(z0, 0xff); + z0 = _mm_shuffle_epi32(z0, 0x00); + z1 = _mm_loadu_si128((__m128i *) (x + 4)); + z6 = _mm_shuffle_epi32(z1, 0xaa); + z11 = _mm_shuffle_epi32(z1, 0xff); + z12 = _mm_shuffle_epi32(z1, 0x00); + z1 = _mm_shuffle_epi32(z1, 0x55); + z2 = _mm_loadu_si128((__m128i *) (x + 8)); + z7 = _mm_shuffle_epi32(z2, 0xff); + z13 = _mm_shuffle_epi32(z2, 0x55); + z2 = _mm_shuffle_epi32(z2, 0xaa); + /* no z8 -> first half of the nonce, will fill later */ + z3 = _mm_loadu_si128((__m128i *) (x + 12)); + z4 = _mm_shuffle_epi32(z3, 0x00); + z14 = _mm_shuffle_epi32(z3, 0xaa); + z3 = _mm_shuffle_epi32(z3, 0xff); + /* no z9 -> second half of the nonce, will fill later */ + orig0 = z0; + orig1 = z1; + orig2 = z2; + orig3 = z3; + orig4 = z4; + orig5 = z5; + orig6 = z6; + orig7 = z7; + orig10 = z10; + orig11 = z11; + orig12 = z12; + orig13 = z13; + orig14 = z14; + orig15 = z15; + + while (bytes >= 256) { + /* vector implementation for z8 and z9 */ + /* not sure if it helps for only 4 blocks */ + const __m128i addv8 = _mm_set_epi64x(1, 0); + const __m128i addv9 = _mm_set_epi64x(3, 2); + __m128i t8, t9; + uint64_t in89; + + in8 = x[8]; + in9 = x[13]; + in89 = ((uint64_t) in8) | (((uint64_t) in9) << 32); + t8 = _mm_set1_epi64x(in89); + t9 = _mm_set1_epi64x(in89); + + z8 = _mm_add_epi64(addv8, t8); + z9 = _mm_add_epi64(addv9, t9); + + t8 = _mm_unpacklo_epi32(z8, z9); + t9 = _mm_unpackhi_epi32(z8, z9); + + z8 = _mm_unpacklo_epi32(t8, t9); + z9 = _mm_unpackhi_epi32(t8, t9); + + orig8 = z8; + orig9 = z9; + + in89 += 4; + + x[8] = in89 & 0xFFFFFFFF; + x[13] = (in89 >> 32) & 0xFFFFFFFF; + + z5 = orig5; + z10 = orig10; + z15 = orig15; + z14 = orig14; + z3 = orig3; + z6 = orig6; + z11 = orig11; + z1 = orig1; + + z7 = orig7; + z13 = orig13; + z2 = orig2; + z9 = orig9; + z0 = orig0; + z12 = orig12; + z4 = orig4; + z8 = orig8; + + for (i = 0; i < ROUNDS; i += 2) { + /* the inner loop is a direct translation (regexp search/replace) + * from the amd64-xmm6 ASM */ + __m128i r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, + r14, r15; + + y4 = z12; + y4 = _mm_add_epi32(y4, z0); + r4 = y4; + y4 = _mm_slli_epi32(y4, 7); + z4 = _mm_xor_si128(z4, y4); + r4 = _mm_srli_epi32(r4, 25); + z4 = _mm_xor_si128(z4, r4); + + y9 = z1; + y9 = _mm_add_epi32(y9, z5); + r9 = y9; + y9 = _mm_slli_epi32(y9, 7); + z9 = _mm_xor_si128(z9, y9); + r9 = _mm_srli_epi32(r9, 25); + z9 = _mm_xor_si128(z9, r9); + + y8 = z0; + y8 = _mm_add_epi32(y8, z4); + r8 = y8; + y8 = _mm_slli_epi32(y8, 9); + z8 = _mm_xor_si128(z8, y8); + r8 = _mm_srli_epi32(r8, 23); + z8 = _mm_xor_si128(z8, r8); + + y13 = z5; + y13 = _mm_add_epi32(y13, z9); + r13 = y13; + y13 = _mm_slli_epi32(y13, 9); + z13 = _mm_xor_si128(z13, y13); + r13 = _mm_srli_epi32(r13, 23); + z13 = _mm_xor_si128(z13, r13); + + y12 = z4; + y12 = _mm_add_epi32(y12, z8); + r12 = y12; + y12 = _mm_slli_epi32(y12, 13); + z12 = _mm_xor_si128(z12, y12); + r12 = _mm_srli_epi32(r12, 19); + z12 = _mm_xor_si128(z12, r12); + + y1 = z9; + y1 = _mm_add_epi32(y1, z13); + r1 = y1; + y1 = _mm_slli_epi32(y1, 13); + z1 = _mm_xor_si128(z1, y1); + r1 = _mm_srli_epi32(r1, 19); + z1 = _mm_xor_si128(z1, r1); + + y0 = z8; + y0 = _mm_add_epi32(y0, z12); + r0 = y0; + y0 = _mm_slli_epi32(y0, 18); + z0 = _mm_xor_si128(z0, y0); + r0 = _mm_srli_epi32(r0, 14); + z0 = _mm_xor_si128(z0, r0); + + y5 = z13; + y5 = _mm_add_epi32(y5, z1); + r5 = y5; + y5 = _mm_slli_epi32(y5, 18); + z5 = _mm_xor_si128(z5, y5); + r5 = _mm_srli_epi32(r5, 14); + z5 = _mm_xor_si128(z5, r5); + + y14 = z6; + y14 = _mm_add_epi32(y14, z10); + r14 = y14; + y14 = _mm_slli_epi32(y14, 7); + z14 = _mm_xor_si128(z14, y14); + r14 = _mm_srli_epi32(r14, 25); + z14 = _mm_xor_si128(z14, r14); + + y3 = z11; + y3 = _mm_add_epi32(y3, z15); + r3 = y3; + y3 = _mm_slli_epi32(y3, 7); + z3 = _mm_xor_si128(z3, y3); + r3 = _mm_srli_epi32(r3, 25); + z3 = _mm_xor_si128(z3, r3); + + y2 = z10; + y2 = _mm_add_epi32(y2, z14); + r2 = y2; + y2 = _mm_slli_epi32(y2, 9); + z2 = _mm_xor_si128(z2, y2); + r2 = _mm_srli_epi32(r2, 23); + z2 = _mm_xor_si128(z2, r2); + + y7 = z15; + y7 = _mm_add_epi32(y7, z3); + r7 = y7; + y7 = _mm_slli_epi32(y7, 9); + z7 = _mm_xor_si128(z7, y7); + r7 = _mm_srli_epi32(r7, 23); + z7 = _mm_xor_si128(z7, r7); + + y6 = z14; + y6 = _mm_add_epi32(y6, z2); + r6 = y6; + y6 = _mm_slli_epi32(y6, 13); + z6 = _mm_xor_si128(z6, y6); + r6 = _mm_srli_epi32(r6, 19); + z6 = _mm_xor_si128(z6, r6); + + y11 = z3; + y11 = _mm_add_epi32(y11, z7); + r11 = y11; + y11 = _mm_slli_epi32(y11, 13); + z11 = _mm_xor_si128(z11, y11); + r11 = _mm_srli_epi32(r11, 19); + z11 = _mm_xor_si128(z11, r11); + + y10 = z2; + y10 = _mm_add_epi32(y10, z6); + r10 = y10; + y10 = _mm_slli_epi32(y10, 18); + z10 = _mm_xor_si128(z10, y10); + r10 = _mm_srli_epi32(r10, 14); + z10 = _mm_xor_si128(z10, r10); + + y1 = z3; + y1 = _mm_add_epi32(y1, z0); + r1 = y1; + y1 = _mm_slli_epi32(y1, 7); + z1 = _mm_xor_si128(z1, y1); + r1 = _mm_srli_epi32(r1, 25); + z1 = _mm_xor_si128(z1, r1); + + y15 = z7; + y15 = _mm_add_epi32(y15, z11); + r15 = y15; + y15 = _mm_slli_epi32(y15, 18); + z15 = _mm_xor_si128(z15, y15); + r15 = _mm_srli_epi32(r15, 14); + z15 = _mm_xor_si128(z15, r15); + + y6 = z4; + y6 = _mm_add_epi32(y6, z5); + r6 = y6; + y6 = _mm_slli_epi32(y6, 7); + z6 = _mm_xor_si128(z6, y6); + r6 = _mm_srli_epi32(r6, 25); + z6 = _mm_xor_si128(z6, r6); + + y2 = z0; + y2 = _mm_add_epi32(y2, z1); + r2 = y2; + y2 = _mm_slli_epi32(y2, 9); + z2 = _mm_xor_si128(z2, y2); + r2 = _mm_srli_epi32(r2, 23); + z2 = _mm_xor_si128(z2, r2); + + y7 = z5; + y7 = _mm_add_epi32(y7, z6); + r7 = y7; + y7 = _mm_slli_epi32(y7, 9); + z7 = _mm_xor_si128(z7, y7); + r7 = _mm_srli_epi32(r7, 23); + z7 = _mm_xor_si128(z7, r7); + + y3 = z1; + y3 = _mm_add_epi32(y3, z2); + r3 = y3; + y3 = _mm_slli_epi32(y3, 13); + z3 = _mm_xor_si128(z3, y3); + r3 = _mm_srli_epi32(r3, 19); + z3 = _mm_xor_si128(z3, r3); + + y4 = z6; + y4 = _mm_add_epi32(y4, z7); + r4 = y4; + y4 = _mm_slli_epi32(y4, 13); + z4 = _mm_xor_si128(z4, y4); + r4 = _mm_srli_epi32(r4, 19); + z4 = _mm_xor_si128(z4, r4); + + y0 = z2; + y0 = _mm_add_epi32(y0, z3); + r0 = y0; + y0 = _mm_slli_epi32(y0, 18); + z0 = _mm_xor_si128(z0, y0); + r0 = _mm_srli_epi32(r0, 14); + z0 = _mm_xor_si128(z0, r0); + + y5 = z7; + y5 = _mm_add_epi32(y5, z4); + r5 = y5; + y5 = _mm_slli_epi32(y5, 18); + z5 = _mm_xor_si128(z5, y5); + r5 = _mm_srli_epi32(r5, 14); + z5 = _mm_xor_si128(z5, r5); + + y11 = z9; + y11 = _mm_add_epi32(y11, z10); + r11 = y11; + y11 = _mm_slli_epi32(y11, 7); + z11 = _mm_xor_si128(z11, y11); + r11 = _mm_srli_epi32(r11, 25); + z11 = _mm_xor_si128(z11, r11); + + y12 = z14; + y12 = _mm_add_epi32(y12, z15); + r12 = y12; + y12 = _mm_slli_epi32(y12, 7); + z12 = _mm_xor_si128(z12, y12); + r12 = _mm_srli_epi32(r12, 25); + z12 = _mm_xor_si128(z12, r12); + + y8 = z10; + y8 = _mm_add_epi32(y8, z11); + r8 = y8; + y8 = _mm_slli_epi32(y8, 9); + z8 = _mm_xor_si128(z8, y8); + r8 = _mm_srli_epi32(r8, 23); + z8 = _mm_xor_si128(z8, r8); + + y13 = z15; + y13 = _mm_add_epi32(y13, z12); + r13 = y13; + y13 = _mm_slli_epi32(y13, 9); + z13 = _mm_xor_si128(z13, y13); + r13 = _mm_srli_epi32(r13, 23); + z13 = _mm_xor_si128(z13, r13); + + y9 = z11; + y9 = _mm_add_epi32(y9, z8); + r9 = y9; + y9 = _mm_slli_epi32(y9, 13); + z9 = _mm_xor_si128(z9, y9); + r9 = _mm_srli_epi32(r9, 19); + z9 = _mm_xor_si128(z9, r9); + + y14 = z12; + y14 = _mm_add_epi32(y14, z13); + r14 = y14; + y14 = _mm_slli_epi32(y14, 13); + z14 = _mm_xor_si128(z14, y14); + r14 = _mm_srli_epi32(r14, 19); + z14 = _mm_xor_si128(z14, r14); + + y10 = z8; + y10 = _mm_add_epi32(y10, z9); + r10 = y10; + y10 = _mm_slli_epi32(y10, 18); + z10 = _mm_xor_si128(z10, y10); + r10 = _mm_srli_epi32(r10, 14); + z10 = _mm_xor_si128(z10, r10); + + y15 = z13; + y15 = _mm_add_epi32(y15, z14); + r15 = y15; + y15 = _mm_slli_epi32(y15, 18); + z15 = _mm_xor_si128(z15, y15); + r15 = _mm_srli_epi32(r15, 14); + z15 = _mm_xor_si128(z15, r15); + } + +/* store data ; this macro replicates the original amd64-xmm6 code */ +#define ONEQUAD_SHUFFLE(A, B, C, D) \ + z##A = _mm_add_epi32(z##A, orig##A); \ + z##B = _mm_add_epi32(z##B, orig##B); \ + z##C = _mm_add_epi32(z##C, orig##C); \ + z##D = _mm_add_epi32(z##D, orig##D); \ + in##A = _mm_cvtsi128_si32(z##A); \ + in##B = _mm_cvtsi128_si32(z##B); \ + in##C = _mm_cvtsi128_si32(z##C); \ + in##D = _mm_cvtsi128_si32(z##D); \ + z##A = _mm_shuffle_epi32(z##A, 0x39); \ + z##B = _mm_shuffle_epi32(z##B, 0x39); \ + z##C = _mm_shuffle_epi32(z##C, 0x39); \ + z##D = _mm_shuffle_epi32(z##D, 0x39); \ + \ + in##A ^= *(uint32_t *) (m + 0); \ + in##B ^= *(uint32_t *) (m + 4); \ + in##C ^= *(uint32_t *) (m + 8); \ + in##D ^= *(uint32_t *) (m + 12); \ + \ + *(uint32_t *) (c + 0) = in##A; \ + *(uint32_t *) (c + 4) = in##B; \ + *(uint32_t *) (c + 8) = in##C; \ + *(uint32_t *) (c + 12) = in##D; \ + \ + in##A = _mm_cvtsi128_si32(z##A); \ + in##B = _mm_cvtsi128_si32(z##B); \ + in##C = _mm_cvtsi128_si32(z##C); \ + in##D = _mm_cvtsi128_si32(z##D); \ + z##A = _mm_shuffle_epi32(z##A, 0x39); \ + z##B = _mm_shuffle_epi32(z##B, 0x39); \ + z##C = _mm_shuffle_epi32(z##C, 0x39); \ + z##D = _mm_shuffle_epi32(z##D, 0x39); \ + \ + in##A ^= *(uint32_t *) (m + 64); \ + in##B ^= *(uint32_t *) (m + 68); \ + in##C ^= *(uint32_t *) (m + 72); \ + in##D ^= *(uint32_t *) (m + 76); \ + *(uint32_t *) (c + 64) = in##A; \ + *(uint32_t *) (c + 68) = in##B; \ + *(uint32_t *) (c + 72) = in##C; \ + *(uint32_t *) (c + 76) = in##D; \ + \ + in##A = _mm_cvtsi128_si32(z##A); \ + in##B = _mm_cvtsi128_si32(z##B); \ + in##C = _mm_cvtsi128_si32(z##C); \ + in##D = _mm_cvtsi128_si32(z##D); \ + z##A = _mm_shuffle_epi32(z##A, 0x39); \ + z##B = _mm_shuffle_epi32(z##B, 0x39); \ + z##C = _mm_shuffle_epi32(z##C, 0x39); \ + z##D = _mm_shuffle_epi32(z##D, 0x39); \ + \ + in##A ^= *(uint32_t *) (m + 128); \ + in##B ^= *(uint32_t *) (m + 132); \ + in##C ^= *(uint32_t *) (m + 136); \ + in##D ^= *(uint32_t *) (m + 140); \ + *(uint32_t *) (c + 128) = in##A; \ + *(uint32_t *) (c + 132) = in##B; \ + *(uint32_t *) (c + 136) = in##C; \ + *(uint32_t *) (c + 140) = in##D; \ + \ + in##A = _mm_cvtsi128_si32(z##A); \ + in##B = _mm_cvtsi128_si32(z##B); \ + in##C = _mm_cvtsi128_si32(z##C); \ + in##D = _mm_cvtsi128_si32(z##D); \ + \ + in##A ^= *(uint32_t *) (m + 192); \ + in##B ^= *(uint32_t *) (m + 196); \ + in##C ^= *(uint32_t *) (m + 200); \ + in##D ^= *(uint32_t *) (m + 204); \ + *(uint32_t *) (c + 192) = in##A; \ + *(uint32_t *) (c + 196) = in##B; \ + *(uint32_t *) (c + 200) = in##C; \ + *(uint32_t *) (c + 204) = in##D + +/* store data ; this macro replaces shuffle+mov by a direct extract; not much + * difference */ +#define ONEQUAD_EXTRACT(A, B, C, D) \ + z##A = _mm_add_epi32(z##A, orig##A); \ + z##B = _mm_add_epi32(z##B, orig##B); \ + z##C = _mm_add_epi32(z##C, orig##C); \ + z##D = _mm_add_epi32(z##D, orig##D); \ + in##A = _mm_cvtsi128_si32(z##A); \ + in##B = _mm_cvtsi128_si32(z##B); \ + in##C = _mm_cvtsi128_si32(z##C); \ + in##D = _mm_cvtsi128_si32(z##D); \ + in##A ^= *(uint32_t *) (m + 0); \ + in##B ^= *(uint32_t *) (m + 4); \ + in##C ^= *(uint32_t *) (m + 8); \ + in##D ^= *(uint32_t *) (m + 12); \ + *(uint32_t *) (c + 0) = in##A; \ + *(uint32_t *) (c + 4) = in##B; \ + *(uint32_t *) (c + 8) = in##C; \ + *(uint32_t *) (c + 12) = in##D; \ + \ + in##A = _mm_extract_epi32(z##A, 1); \ + in##B = _mm_extract_epi32(z##B, 1); \ + in##C = _mm_extract_epi32(z##C, 1); \ + in##D = _mm_extract_epi32(z##D, 1); \ + \ + in##A ^= *(uint32_t *) (m + 64); \ + in##B ^= *(uint32_t *) (m + 68); \ + in##C ^= *(uint32_t *) (m + 72); \ + in##D ^= *(uint32_t *) (m + 76); \ + *(uint32_t *) (c + 64) = in##A; \ + *(uint32_t *) (c + 68) = in##B; \ + *(uint32_t *) (c + 72) = in##C; \ + *(uint32_t *) (c + 76) = in##D; \ + \ + in##A = _mm_extract_epi32(z##A, 2); \ + in##B = _mm_extract_epi32(z##B, 2); \ + in##C = _mm_extract_epi32(z##C, 2); \ + in##D = _mm_extract_epi32(z##D, 2); \ + \ + in##A ^= *(uint32_t *) (m + 128); \ + in##B ^= *(uint32_t *) (m + 132); \ + in##C ^= *(uint32_t *) (m + 136); \ + in##D ^= *(uint32_t *) (m + 140); \ + *(uint32_t *) (c + 128) = in##A; \ + *(uint32_t *) (c + 132) = in##B; \ + *(uint32_t *) (c + 136) = in##C; \ + *(uint32_t *) (c + 140) = in##D; \ + \ + in##A = _mm_extract_epi32(z##A, 3); \ + in##B = _mm_extract_epi32(z##B, 3); \ + in##C = _mm_extract_epi32(z##C, 3); \ + in##D = _mm_extract_epi32(z##D, 3); \ + \ + in##A ^= *(uint32_t *) (m + 192); \ + in##B ^= *(uint32_t *) (m + 196); \ + in##C ^= *(uint32_t *) (m + 200); \ + in##D ^= *(uint32_t *) (m + 204); \ + *(uint32_t *) (c + 192) = in##A; \ + *(uint32_t *) (c + 196) = in##B; \ + *(uint32_t *) (c + 200) = in##C; \ + *(uint32_t *) (c + 204) = in##D + +/* store data ; this macro first transpose data in-registers, and then store + * them in memory. much faster with icc. */ +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + z##A = _mm_add_epi32(z##A, orig##A); \ + z##B = _mm_add_epi32(z##B, orig##B); \ + z##C = _mm_add_epi32(z##C, orig##C); \ + z##D = _mm_add_epi32(z##D, orig##D); \ + y##A = _mm_unpacklo_epi32(z##A, z##B); \ + y##B = _mm_unpacklo_epi32(z##C, z##D); \ + y##C = _mm_unpackhi_epi32(z##A, z##B); \ + y##D = _mm_unpackhi_epi32(z##C, z##D); \ + z##A = _mm_unpacklo_epi64(y##A, y##B); \ + z##B = _mm_unpackhi_epi64(y##A, y##B); \ + z##C = _mm_unpacklo_epi64(y##C, y##D); \ + z##D = _mm_unpackhi_epi64(y##C, y##D); \ + y##A = _mm_xor_si128(z##A, _mm_loadu_si128((__m128i *) (m + 0))); \ + _mm_storeu_si128((__m128i *) (c + 0), y##A); \ + y##B = _mm_xor_si128(z##B, _mm_loadu_si128((__m128i *) (m + 64))); \ + _mm_storeu_si128((__m128i *) (c + 64), y##B); \ + y##C = _mm_xor_si128(z##C, _mm_loadu_si128((__m128i *) (m + 128))); \ + _mm_storeu_si128((__m128i *) (c + 128), y##C); \ + y##D = _mm_xor_si128(z##D, _mm_loadu_si128((__m128i *) (m + 192))); \ + _mm_storeu_si128((__m128i *) (c + 192), y##D) + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + + ONEQUAD(0, 1, 2, 3); + m += 16; + c += 16; + ONEQUAD(4, 5, 6, 7); + m += 16; + c += 16; + ONEQUAD(8, 9, 10, 11); + m += 16; + c += 16; + ONEQUAD(12, 13, 14, 15); + m -= 48; + c -= 48; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE +#undef ONEQUAD_EXTRACT +#undef ONEQUAD_SHUFFLE + + bytes -= 256; + c += 256; + m += 256; + } +} diff --git a/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u8.h b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u8.h new file mode 100644 index 0000000000..467a961299 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa20/xmm6int/u8.h @@ -0,0 +1,476 @@ +if (bytes >= 512) { + __m256i y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, + y15; + + /* the naive way seems as fast (if not a bit faster) than the vector way */ + __m256i z0 = _mm256_set1_epi32(x[0]); + __m256i z5 = _mm256_set1_epi32(x[1]); + __m256i z10 = _mm256_set1_epi32(x[2]); + __m256i z15 = _mm256_set1_epi32(x[3]); + __m256i z12 = _mm256_set1_epi32(x[4]); + __m256i z1 = _mm256_set1_epi32(x[5]); + __m256i z6 = _mm256_set1_epi32(x[6]); + __m256i z11 = _mm256_set1_epi32(x[7]); + __m256i z8; /* useless */ + __m256i z13 = _mm256_set1_epi32(x[9]); + __m256i z2 = _mm256_set1_epi32(x[10]); + __m256i z7 = _mm256_set1_epi32(x[11]); + __m256i z4 = _mm256_set1_epi32(x[12]); + __m256i z9; /* useless */ + __m256i z14 = _mm256_set1_epi32(x[14]); + __m256i z3 = _mm256_set1_epi32(x[15]); + + __m256i orig0 = z0; + __m256i orig1 = z1; + __m256i orig2 = z2; + __m256i orig3 = z3; + __m256i orig4 = z4; + __m256i orig5 = z5; + __m256i orig6 = z6; + __m256i orig7 = z7; + __m256i orig8; + __m256i orig9; + __m256i orig10 = z10; + __m256i orig11 = z11; + __m256i orig12 = z12; + __m256i orig13 = z13; + __m256i orig14 = z14; + __m256i orig15 = z15; + + uint32_t in8; + uint32_t in9; + int i; + + while (bytes >= 512) { + /* vector implementation for z8 and z9 */ + /* faster than the naive version for 8 blocks */ + const __m256i addv8 = _mm256_set_epi64x(3, 2, 1, 0); + const __m256i addv9 = _mm256_set_epi64x(7, 6, 5, 4); + const __m256i permute = _mm256_set_epi32(7, 6, 3, 2, 5, 4, 1, 0); + + __m256i t8, t9; + uint64_t in89; + + in8 = x[8]; + in9 = x[13]; /* see arrays above for the address translation */ + in89 = ((uint64_t) in8) | (((uint64_t) in9) << 32); + + z8 = z9 = _mm256_broadcastq_epi64(_mm_cvtsi64_si128(in89)); + + t8 = _mm256_add_epi64(addv8, z8); + t9 = _mm256_add_epi64(addv9, z9); + + z8 = _mm256_unpacklo_epi32(t8, t9); + z9 = _mm256_unpackhi_epi32(t8, t9); + + t8 = _mm256_unpacklo_epi32(z8, z9); + t9 = _mm256_unpackhi_epi32(z8, z9); + + /* required because unpack* are intra-lane */ + z8 = _mm256_permutevar8x32_epi32(t8, permute); + z9 = _mm256_permutevar8x32_epi32(t9, permute); + + orig8 = z8; + orig9 = z9; + + in89 += 8; + + x[8] = in89 & 0xFFFFFFFF; + x[13] = (in89 >> 32) & 0xFFFFFFFF; + + z5 = orig5; + z10 = orig10; + z15 = orig15; + z14 = orig14; + z3 = orig3; + z6 = orig6; + z11 = orig11; + z1 = orig1; + + z7 = orig7; + z13 = orig13; + z2 = orig2; + z9 = orig9; + z0 = orig0; + z12 = orig12; + z4 = orig4; + z8 = orig8; + + for (i = 0; i < ROUNDS; i += 2) { + /* the inner loop is a direct translation (regexp search/replace) + * from the amd64-xmm6 ASM */ + __m256i r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, + r14, r15; + + y4 = z12; + y4 = _mm256_add_epi32(y4, z0); + r4 = y4; + y4 = _mm256_slli_epi32(y4, 7); + z4 = _mm256_xor_si256(z4, y4); + r4 = _mm256_srli_epi32(r4, 25); + z4 = _mm256_xor_si256(z4, r4); + + y9 = z1; + y9 = _mm256_add_epi32(y9, z5); + r9 = y9; + y9 = _mm256_slli_epi32(y9, 7); + z9 = _mm256_xor_si256(z9, y9); + r9 = _mm256_srli_epi32(r9, 25); + z9 = _mm256_xor_si256(z9, r9); + + y8 = z0; + y8 = _mm256_add_epi32(y8, z4); + r8 = y8; + y8 = _mm256_slli_epi32(y8, 9); + z8 = _mm256_xor_si256(z8, y8); + r8 = _mm256_srli_epi32(r8, 23); + z8 = _mm256_xor_si256(z8, r8); + + y13 = z5; + y13 = _mm256_add_epi32(y13, z9); + r13 = y13; + y13 = _mm256_slli_epi32(y13, 9); + z13 = _mm256_xor_si256(z13, y13); + r13 = _mm256_srli_epi32(r13, 23); + z13 = _mm256_xor_si256(z13, r13); + + y12 = z4; + y12 = _mm256_add_epi32(y12, z8); + r12 = y12; + y12 = _mm256_slli_epi32(y12, 13); + z12 = _mm256_xor_si256(z12, y12); + r12 = _mm256_srli_epi32(r12, 19); + z12 = _mm256_xor_si256(z12, r12); + + y1 = z9; + y1 = _mm256_add_epi32(y1, z13); + r1 = y1; + y1 = _mm256_slli_epi32(y1, 13); + z1 = _mm256_xor_si256(z1, y1); + r1 = _mm256_srli_epi32(r1, 19); + z1 = _mm256_xor_si256(z1, r1); + + y0 = z8; + y0 = _mm256_add_epi32(y0, z12); + r0 = y0; + y0 = _mm256_slli_epi32(y0, 18); + z0 = _mm256_xor_si256(z0, y0); + r0 = _mm256_srli_epi32(r0, 14); + z0 = _mm256_xor_si256(z0, r0); + + y5 = z13; + y5 = _mm256_add_epi32(y5, z1); + r5 = y5; + y5 = _mm256_slli_epi32(y5, 18); + z5 = _mm256_xor_si256(z5, y5); + r5 = _mm256_srli_epi32(r5, 14); + z5 = _mm256_xor_si256(z5, r5); + + y14 = z6; + y14 = _mm256_add_epi32(y14, z10); + r14 = y14; + y14 = _mm256_slli_epi32(y14, 7); + z14 = _mm256_xor_si256(z14, y14); + r14 = _mm256_srli_epi32(r14, 25); + z14 = _mm256_xor_si256(z14, r14); + + y3 = z11; + y3 = _mm256_add_epi32(y3, z15); + r3 = y3; + y3 = _mm256_slli_epi32(y3, 7); + z3 = _mm256_xor_si256(z3, y3); + r3 = _mm256_srli_epi32(r3, 25); + z3 = _mm256_xor_si256(z3, r3); + + y2 = z10; + y2 = _mm256_add_epi32(y2, z14); + r2 = y2; + y2 = _mm256_slli_epi32(y2, 9); + z2 = _mm256_xor_si256(z2, y2); + r2 = _mm256_srli_epi32(r2, 23); + z2 = _mm256_xor_si256(z2, r2); + + y7 = z15; + y7 = _mm256_add_epi32(y7, z3); + r7 = y7; + y7 = _mm256_slli_epi32(y7, 9); + z7 = _mm256_xor_si256(z7, y7); + r7 = _mm256_srli_epi32(r7, 23); + z7 = _mm256_xor_si256(z7, r7); + + y6 = z14; + y6 = _mm256_add_epi32(y6, z2); + r6 = y6; + y6 = _mm256_slli_epi32(y6, 13); + z6 = _mm256_xor_si256(z6, y6); + r6 = _mm256_srli_epi32(r6, 19); + z6 = _mm256_xor_si256(z6, r6); + + y11 = z3; + y11 = _mm256_add_epi32(y11, z7); + r11 = y11; + y11 = _mm256_slli_epi32(y11, 13); + z11 = _mm256_xor_si256(z11, y11); + r11 = _mm256_srli_epi32(r11, 19); + z11 = _mm256_xor_si256(z11, r11); + + y10 = z2; + y10 = _mm256_add_epi32(y10, z6); + r10 = y10; + y10 = _mm256_slli_epi32(y10, 18); + z10 = _mm256_xor_si256(z10, y10); + r10 = _mm256_srli_epi32(r10, 14); + z10 = _mm256_xor_si256(z10, r10); + + y1 = z3; + y1 = _mm256_add_epi32(y1, z0); + r1 = y1; + y1 = _mm256_slli_epi32(y1, 7); + z1 = _mm256_xor_si256(z1, y1); + r1 = _mm256_srli_epi32(r1, 25); + z1 = _mm256_xor_si256(z1, r1); + + y15 = z7; + y15 = _mm256_add_epi32(y15, z11); + r15 = y15; + y15 = _mm256_slli_epi32(y15, 18); + z15 = _mm256_xor_si256(z15, y15); + r15 = _mm256_srli_epi32(r15, 14); + z15 = _mm256_xor_si256(z15, r15); + + y6 = z4; + y6 = _mm256_add_epi32(y6, z5); + r6 = y6; + y6 = _mm256_slli_epi32(y6, 7); + z6 = _mm256_xor_si256(z6, y6); + r6 = _mm256_srli_epi32(r6, 25); + z6 = _mm256_xor_si256(z6, r6); + + y2 = z0; + y2 = _mm256_add_epi32(y2, z1); + r2 = y2; + y2 = _mm256_slli_epi32(y2, 9); + z2 = _mm256_xor_si256(z2, y2); + r2 = _mm256_srli_epi32(r2, 23); + z2 = _mm256_xor_si256(z2, r2); + + y7 = z5; + y7 = _mm256_add_epi32(y7, z6); + r7 = y7; + y7 = _mm256_slli_epi32(y7, 9); + z7 = _mm256_xor_si256(z7, y7); + r7 = _mm256_srli_epi32(r7, 23); + z7 = _mm256_xor_si256(z7, r7); + + y3 = z1; + y3 = _mm256_add_epi32(y3, z2); + r3 = y3; + y3 = _mm256_slli_epi32(y3, 13); + z3 = _mm256_xor_si256(z3, y3); + r3 = _mm256_srli_epi32(r3, 19); + z3 = _mm256_xor_si256(z3, r3); + + y4 = z6; + y4 = _mm256_add_epi32(y4, z7); + r4 = y4; + y4 = _mm256_slli_epi32(y4, 13); + z4 = _mm256_xor_si256(z4, y4); + r4 = _mm256_srli_epi32(r4, 19); + z4 = _mm256_xor_si256(z4, r4); + + y0 = z2; + y0 = _mm256_add_epi32(y0, z3); + r0 = y0; + y0 = _mm256_slli_epi32(y0, 18); + z0 = _mm256_xor_si256(z0, y0); + r0 = _mm256_srli_epi32(r0, 14); + z0 = _mm256_xor_si256(z0, r0); + + y5 = z7; + y5 = _mm256_add_epi32(y5, z4); + r5 = y5; + y5 = _mm256_slli_epi32(y5, 18); + z5 = _mm256_xor_si256(z5, y5); + r5 = _mm256_srli_epi32(r5, 14); + z5 = _mm256_xor_si256(z5, r5); + + y11 = z9; + y11 = _mm256_add_epi32(y11, z10); + r11 = y11; + y11 = _mm256_slli_epi32(y11, 7); + z11 = _mm256_xor_si256(z11, y11); + r11 = _mm256_srli_epi32(r11, 25); + z11 = _mm256_xor_si256(z11, r11); + + y12 = z14; + y12 = _mm256_add_epi32(y12, z15); + r12 = y12; + y12 = _mm256_slli_epi32(y12, 7); + z12 = _mm256_xor_si256(z12, y12); + r12 = _mm256_srli_epi32(r12, 25); + z12 = _mm256_xor_si256(z12, r12); + + y8 = z10; + y8 = _mm256_add_epi32(y8, z11); + r8 = y8; + y8 = _mm256_slli_epi32(y8, 9); + z8 = _mm256_xor_si256(z8, y8); + r8 = _mm256_srli_epi32(r8, 23); + z8 = _mm256_xor_si256(z8, r8); + + y13 = z15; + y13 = _mm256_add_epi32(y13, z12); + r13 = y13; + y13 = _mm256_slli_epi32(y13, 9); + z13 = _mm256_xor_si256(z13, y13); + r13 = _mm256_srli_epi32(r13, 23); + z13 = _mm256_xor_si256(z13, r13); + + y9 = z11; + y9 = _mm256_add_epi32(y9, z8); + r9 = y9; + y9 = _mm256_slli_epi32(y9, 13); + z9 = _mm256_xor_si256(z9, y9); + r9 = _mm256_srli_epi32(r9, 19); + z9 = _mm256_xor_si256(z9, r9); + + y14 = z12; + y14 = _mm256_add_epi32(y14, z13); + r14 = y14; + y14 = _mm256_slli_epi32(y14, 13); + z14 = _mm256_xor_si256(z14, y14); + r14 = _mm256_srli_epi32(r14, 19); + z14 = _mm256_xor_si256(z14, r14); + + y10 = z8; + y10 = _mm256_add_epi32(y10, z9); + r10 = y10; + y10 = _mm256_slli_epi32(y10, 18); + z10 = _mm256_xor_si256(z10, y10); + r10 = _mm256_srli_epi32(r10, 14); + z10 = _mm256_xor_si256(z10, r10); + + y15 = z13; + y15 = _mm256_add_epi32(y15, z14); + r15 = y15; + y15 = _mm256_slli_epi32(y15, 18); + z15 = _mm256_xor_si256(z15, y15); + r15 = _mm256_srli_epi32(r15, 14); + z15 = _mm256_xor_si256(z15, r15); + } + +/* store data ; this macro first transpose data in-registers, and then store + * them in memory. much faster with icc. */ +#define ONEQUAD_TRANSPOSE(A, B, C, D) \ + { \ + __m128i t0, t1, t2, t3; \ + z##A = _mm256_add_epi32(z##A, orig##A); \ + z##B = _mm256_add_epi32(z##B, orig##B); \ + z##C = _mm256_add_epi32(z##C, orig##C); \ + z##D = _mm256_add_epi32(z##D, orig##D); \ + y##A = _mm256_unpacklo_epi32(z##A, z##B); \ + y##B = _mm256_unpacklo_epi32(z##C, z##D); \ + y##C = _mm256_unpackhi_epi32(z##A, z##B); \ + y##D = _mm256_unpackhi_epi32(z##C, z##D); \ + z##A = _mm256_unpacklo_epi64(y##A, y##B); \ + z##B = _mm256_unpackhi_epi64(y##A, y##B); \ + z##C = _mm256_unpacklo_epi64(y##C, y##D); \ + z##D = _mm256_unpackhi_epi64(y##C, y##D); \ + t0 = _mm_xor_si128(_mm256_extracti128_si256(z##A, 0), \ + _mm_loadu_si128((__m128i*) (m + 0))); \ + _mm_storeu_si128((__m128i*) (c + 0), t0); \ + t1 = _mm_xor_si128(_mm256_extracti128_si256(z##B, 0), \ + _mm_loadu_si128((__m128i*) (m + 64))); \ + _mm_storeu_si128((__m128i*) (c + 64), t1); \ + t2 = _mm_xor_si128(_mm256_extracti128_si256(z##C, 0), \ + _mm_loadu_si128((__m128i*) (m + 128))); \ + _mm_storeu_si128((__m128i*) (c + 128), t2); \ + t3 = _mm_xor_si128(_mm256_extracti128_si256(z##D, 0), \ + _mm_loadu_si128((__m128i*) (m + 192))); \ + _mm_storeu_si128((__m128i*) (c + 192), t3); \ + t0 = _mm_xor_si128(_mm256_extracti128_si256(z##A, 1), \ + _mm_loadu_si128((__m128i*) (m + 256))); \ + _mm_storeu_si128((__m128i*) (c + 256), t0); \ + t1 = _mm_xor_si128(_mm256_extracti128_si256(z##B, 1), \ + _mm_loadu_si128((__m128i*) (m + 320))); \ + _mm_storeu_si128((__m128i*) (c + 320), t1); \ + t2 = _mm_xor_si128(_mm256_extracti128_si256(z##C, 1), \ + _mm_loadu_si128((__m128i*) (m + 384))); \ + _mm_storeu_si128((__m128i*) (c + 384), t2); \ + t3 = _mm_xor_si128(_mm256_extracti128_si256(z##D, 1), \ + _mm_loadu_si128((__m128i*) (m + 448))); \ + _mm_storeu_si128((__m128i*) (c + 448), t3); \ + } + +#define ONEQUAD(A, B, C, D) ONEQUAD_TRANSPOSE(A, B, C, D) + +#define ONEQUAD_UNPCK(A, B, C, D) \ + { \ + z##A = _mm256_add_epi32(z##A, orig##A); \ + z##B = _mm256_add_epi32(z##B, orig##B); \ + z##C = _mm256_add_epi32(z##C, orig##C); \ + z##D = _mm256_add_epi32(z##D, orig##D); \ + y##A = _mm256_unpacklo_epi32(z##A, z##B); \ + y##B = _mm256_unpacklo_epi32(z##C, z##D); \ + y##C = _mm256_unpackhi_epi32(z##A, z##B); \ + y##D = _mm256_unpackhi_epi32(z##C, z##D); \ + z##A = _mm256_unpacklo_epi64(y##A, y##B); \ + z##B = _mm256_unpackhi_epi64(y##A, y##B); \ + z##C = _mm256_unpacklo_epi64(y##C, y##D); \ + z##D = _mm256_unpackhi_epi64(y##C, y##D); \ + } + +#define ONEOCTO(A, B, C, D, A2, B2, C2, D2) \ + { \ + ONEQUAD_UNPCK(A, B, C, D); \ + ONEQUAD_UNPCK(A2, B2, C2, D2); \ + y##A = _mm256_permute2x128_si256(z##A, z##A2, 0x20); \ + y##A2 = _mm256_permute2x128_si256(z##A, z##A2, 0x31); \ + y##B = _mm256_permute2x128_si256(z##B, z##B2, 0x20); \ + y##B2 = _mm256_permute2x128_si256(z##B, z##B2, 0x31); \ + y##C = _mm256_permute2x128_si256(z##C, z##C2, 0x20); \ + y##C2 = _mm256_permute2x128_si256(z##C, z##C2, 0x31); \ + y##D = _mm256_permute2x128_si256(z##D, z##D2, 0x20); \ + y##D2 = _mm256_permute2x128_si256(z##D, z##D2, 0x31); \ + y##A = _mm256_xor_si256(y##A, _mm256_loadu_si256((__m256i*) (m + 0))); \ + y##B = \ + _mm256_xor_si256(y##B, _mm256_loadu_si256((__m256i*) (m + 64))); \ + y##C = \ + _mm256_xor_si256(y##C, _mm256_loadu_si256((__m256i*) (m + 128))); \ + y##D = \ + _mm256_xor_si256(y##D, _mm256_loadu_si256((__m256i*) (m + 192))); \ + y##A2 = \ + _mm256_xor_si256(y##A2, _mm256_loadu_si256((__m256i*) (m + 256))); \ + y##B2 = \ + _mm256_xor_si256(y##B2, _mm256_loadu_si256((__m256i*) (m + 320))); \ + y##C2 = \ + _mm256_xor_si256(y##C2, _mm256_loadu_si256((__m256i*) (m + 384))); \ + y##D2 = \ + _mm256_xor_si256(y##D2, _mm256_loadu_si256((__m256i*) (m + 448))); \ + _mm256_storeu_si256((__m256i*) (c + 0), y##A); \ + _mm256_storeu_si256((__m256i*) (c + 64), y##B); \ + _mm256_storeu_si256((__m256i*) (c + 128), y##C); \ + _mm256_storeu_si256((__m256i*) (c + 192), y##D); \ + _mm256_storeu_si256((__m256i*) (c + 256), y##A2); \ + _mm256_storeu_si256((__m256i*) (c + 320), y##B2); \ + _mm256_storeu_si256((__m256i*) (c + 384), y##C2); \ + _mm256_storeu_si256((__m256i*) (c + 448), y##D2); \ + } + + ONEOCTO(0, 1, 2, 3, 4, 5, 6, 7); + m += 32; + c += 32; + ONEOCTO(8, 9, 10, 11, 12, 13, 14, 15); + m -= 32; + c -= 32; + +#undef ONEQUAD +#undef ONEQUAD_TRANSPOSE +#undef ONEQUAD_UNPCK +#undef ONEOCTO + + bytes -= 512; + c += 512; + m += 512; + } +} diff --git a/libs/libsodium/src/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c b/libs/libsodium/src/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c new file mode 100644 index 0000000000..bfdfeedba3 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa2012/ref/stream_salsa2012_ref.c @@ -0,0 +1,106 @@ +/* +version 20140420 +D. J. Bernstein +Public domain. +*/ + +#include + +#include "crypto_core_salsa2012.h" +#include "crypto_stream_salsa2012.h" +#include "utils.h" + +int +crypto_stream_salsa2012(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + unsigned char in[16]; + unsigned char block[64]; + unsigned char kcopy[32]; + unsigned int i; + unsigned int u; + + if (!clen) { + return 0; + } + for (i = 0; i < 32; ++i) { + kcopy[i] = k[i]; + } + for (i = 0; i < 8; ++i) { + in[i] = n[i]; + } + for (i = 8; i < 16; ++i) { + in[i] = 0; + } + while (clen >= 64) { + crypto_core_salsa2012(c, in, kcopy, NULL); + u = 1; + for (i = 8; i < 16; ++i) { + u += (unsigned int)in[i]; + in[i] = u; + u >>= 8; + } + clen -= 64; + c += 64; + } + if (clen) { + crypto_core_salsa2012(block, in, kcopy, NULL); + for (i = 0; i < (unsigned int)clen; ++i) { + c[i] = block[i]; + } + } + sodium_memzero(block, sizeof block); + sodium_memzero(kcopy, sizeof kcopy); + + return 0; +} + +int +crypto_stream_salsa2012_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + unsigned char in[16]; + unsigned char block[64]; + unsigned char kcopy[32]; + unsigned int i; + unsigned int u; + + if (!mlen) { + return 0; + } + for (i = 0; i < 32; ++i) { + kcopy[i] = k[i]; + } + for (i = 0; i < 8; ++i) { + in[i] = n[i]; + } + for (i = 8; i < 16; ++i) { + in[i] = 0; + } + while (mlen >= 64) { + crypto_core_salsa2012(block, in, kcopy, NULL); + for (i = 0; i < 64; ++i) { + c[i] = m[i] ^ block[i]; + } + u = 1; + for (i = 8; i < 16; ++i) { + u += (unsigned int)in[i]; + in[i] = u; + u >>= 8; + } + mlen -= 64; + c += 64; + m += 64; + } + if (mlen) { + crypto_core_salsa2012(block, in, kcopy, NULL); + for (i = 0; i < (unsigned int)mlen; ++i) { + c[i] = m[i] ^ block[i]; + } + } + sodium_memzero(block, sizeof block); + sodium_memzero(kcopy, sizeof kcopy); + + return 0; +} diff --git a/libs/libsodium/src/crypto_stream/salsa2012/stream_salsa2012.c b/libs/libsodium/src/crypto_stream/salsa2012/stream_salsa2012.c new file mode 100644 index 0000000000..d0cc0f68ee --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa2012/stream_salsa2012.c @@ -0,0 +1,26 @@ +#include "crypto_stream_salsa2012.h" +#include "randombytes.h" + +size_t +crypto_stream_salsa2012_keybytes(void) +{ + return crypto_stream_salsa2012_KEYBYTES; +} + +size_t +crypto_stream_salsa2012_noncebytes(void) +{ + return crypto_stream_salsa2012_NONCEBYTES; +} + +size_t +crypto_stream_salsa2012_messagebytes_max(void) +{ + return crypto_stream_salsa2012_MESSAGEBYTES_MAX; +} + +void +crypto_stream_salsa2012_keygen(unsigned char k[crypto_stream_salsa2012_KEYBYTES]) +{ + randombytes_buf(k, crypto_stream_salsa2012_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_stream/salsa208/ref/stream_salsa208_ref.c b/libs/libsodium/src/crypto_stream/salsa208/ref/stream_salsa208_ref.c new file mode 100644 index 0000000000..7ec0c4e78e --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa208/ref/stream_salsa208_ref.c @@ -0,0 +1,106 @@ +/* +version 20140420 +D. J. Bernstein +Public domain. +*/ + +#include + +#include "crypto_core_salsa208.h" +#include "crypto_stream_salsa208.h" +#include "utils.h" + +int +crypto_stream_salsa208(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + unsigned char in[16]; + unsigned char block[64]; + unsigned char kcopy[32]; + unsigned int i; + unsigned int u; + + if (!clen) { + return 0; + } + for (i = 0; i < 32; ++i) { + kcopy[i] = k[i]; + } + for (i = 0; i < 8; ++i) { + in[i] = n[i]; + } + for (i = 8; i < 16; ++i) { + in[i] = 0; + } + while (clen >= 64) { + crypto_core_salsa208(c, in, kcopy, NULL); + u = 1; + for (i = 8; i < 16; ++i) { + u += (unsigned int)in[i]; + in[i] = u; + u >>= 8; + } + clen -= 64; + c += 64; + } + if (clen) { + crypto_core_salsa208(block, in, kcopy, NULL); + for (i = 0; i < (unsigned int)clen; ++i) { + c[i] = block[i]; + } + } + sodium_memzero(block, sizeof block); + sodium_memzero(kcopy, sizeof kcopy); + + return 0; +} + +int +crypto_stream_salsa208_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + unsigned char in[16]; + unsigned char block[64]; + unsigned char kcopy[32]; + unsigned int i; + unsigned int u; + + if (!mlen) { + return 0; + } + for (i = 0; i < 32; ++i) { + kcopy[i] = k[i]; + } + for (i = 0; i < 8; ++i) { + in[i] = n[i]; + } + for (i = 8; i < 16; ++i) { + in[i] = 0; + } + while (mlen >= 64) { + crypto_core_salsa208(block, in, kcopy, NULL); + for (i = 0; i < 64; ++i) { + c[i] = m[i] ^ block[i]; + } + u = 1; + for (i = 8; i < 16; ++i) { + u += (unsigned int)in[i]; + in[i] = u; + u >>= 8; + } + mlen -= 64; + c += 64; + m += 64; + } + if (mlen) { + crypto_core_salsa208(block, in, kcopy, NULL); + for (i = 0; i < (unsigned int)mlen; ++i) { + c[i] = m[i] ^ block[i]; + } + } + sodium_memzero(block, sizeof block); + sodium_memzero(kcopy, sizeof kcopy); + + return 0; +} diff --git a/libs/libsodium/src/crypto_stream/salsa208/stream_salsa208.c b/libs/libsodium/src/crypto_stream/salsa208/stream_salsa208.c new file mode 100644 index 0000000000..b79bda5ec2 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/salsa208/stream_salsa208.c @@ -0,0 +1,26 @@ +#include "crypto_stream_salsa208.h" +#include "randombytes.h" + +size_t +crypto_stream_salsa208_keybytes(void) +{ + return crypto_stream_salsa208_KEYBYTES; +} + +size_t +crypto_stream_salsa208_noncebytes(void) +{ + return crypto_stream_salsa208_NONCEBYTES; +} + +size_t +crypto_stream_salsa208_messagebytes_max(void) +{ + return crypto_stream_salsa208_MESSAGEBYTES_MAX; +} + +void +crypto_stream_salsa208_keygen(unsigned char k[crypto_stream_salsa208_KEYBYTES]) +{ + randombytes_buf(k, crypto_stream_salsa208_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_stream/xchacha20/stream_xchacha20.c b/libs/libsodium/src/crypto_stream/xchacha20/stream_xchacha20.c new file mode 100644 index 0000000000..8b1bc09abd --- /dev/null +++ b/libs/libsodium/src/crypto_stream/xchacha20/stream_xchacha20.c @@ -0,0 +1,69 @@ + +#include + +#include "crypto_core_hchacha20.h" +#include "crypto_stream_chacha20.h" +#include "crypto_stream_xchacha20.h" +#include "private/common.h" +#include "randombytes.h" + +size_t +crypto_stream_xchacha20_keybytes(void) +{ + return crypto_stream_xchacha20_KEYBYTES; +} + +size_t +crypto_stream_xchacha20_noncebytes(void) +{ + return crypto_stream_xchacha20_NONCEBYTES; +} + +size_t +crypto_stream_xchacha20_messagebytes_max(void) +{ + return crypto_stream_xchacha20_MESSAGEBYTES_MAX; +} + +int +crypto_stream_xchacha20(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES]; + + crypto_core_hchacha20(k2, n, k, NULL); + COMPILER_ASSERT(crypto_stream_chacha20_KEYBYTES <= sizeof k2); + COMPILER_ASSERT(crypto_stream_chacha20_NONCEBYTES == + crypto_stream_xchacha20_NONCEBYTES - + crypto_core_hchacha20_INPUTBYTES); + + return crypto_stream_chacha20(c, clen, n + crypto_core_hchacha20_INPUTBYTES, + k2); +} + +int +crypto_stream_xchacha20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint64_t ic, const unsigned char *k) +{ + unsigned char k2[crypto_core_hchacha20_OUTPUTBYTES]; + + crypto_core_hchacha20(k2, n, k, NULL); + return crypto_stream_chacha20_xor_ic( + c, m, mlen, n + crypto_core_hchacha20_INPUTBYTES, ic, k2); +} + +int +crypto_stream_xchacha20_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + return crypto_stream_xchacha20_xor_ic(c, m, mlen, n, 0U, k); +} + +void +crypto_stream_xchacha20_keygen( + unsigned char k[crypto_stream_xchacha20_KEYBYTES]) +{ + randombytes_buf(k, crypto_stream_xchacha20_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_stream/xsalsa20/stream_xsalsa20.c b/libs/libsodium/src/crypto_stream/xsalsa20/stream_xsalsa20.c new file mode 100644 index 0000000000..dc831a94d8 --- /dev/null +++ b/libs/libsodium/src/crypto_stream/xsalsa20/stream_xsalsa20.c @@ -0,0 +1,66 @@ +#include "crypto_core_hsalsa20.h" +#include "crypto_stream_salsa20.h" +#include "crypto_stream_xsalsa20.h" +#include "randombytes.h" +#include "utils.h" + +int +crypto_stream_xsalsa20(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) +{ + unsigned char subkey[32]; + int ret; + + crypto_core_hsalsa20(subkey, n, k, NULL); + ret = crypto_stream_salsa20(c, clen, n + 16, subkey); + sodium_memzero(subkey, sizeof subkey); + + return ret; +} + +int +crypto_stream_xsalsa20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + uint64_t ic, const unsigned char *k) +{ + unsigned char subkey[32]; + int ret; + + crypto_core_hsalsa20(subkey, n, k, NULL); + ret = crypto_stream_salsa20_xor_ic(c, m, mlen, n + 16, ic, subkey); + sodium_memzero(subkey, sizeof subkey); + + return ret; +} + +int +crypto_stream_xsalsa20_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) +{ + return crypto_stream_xsalsa20_xor_ic(c, m, mlen, n, 0ULL, k); +} + +size_t +crypto_stream_xsalsa20_keybytes(void) +{ + return crypto_stream_xsalsa20_KEYBYTES; +} + +size_t +crypto_stream_xsalsa20_noncebytes(void) +{ + return crypto_stream_xsalsa20_NONCEBYTES; +} + +size_t +crypto_stream_xsalsa20_messagebytes_max(void) +{ + return crypto_stream_xsalsa20_MESSAGEBYTES_MAX; +} + +void +crypto_stream_xsalsa20_keygen(unsigned char k[crypto_stream_xsalsa20_KEYBYTES]) +{ + randombytes_buf(k, crypto_stream_xsalsa20_KEYBYTES); +} diff --git a/libs/libsodium/src/crypto_verify/sodium/verify.c b/libs/libsodium/src/crypto_verify/sodium/verify.c new file mode 100644 index 0000000000..ffebf220a0 --- /dev/null +++ b/libs/libsodium/src/crypto_verify/sodium/verify.c @@ -0,0 +1,98 @@ + +#include +#include + +#include "crypto_verify_16.h" +#include "crypto_verify_32.h" +#include "crypto_verify_64.h" + +size_t +crypto_verify_16_bytes(void) +{ + return crypto_verify_16_BYTES; +} + +size_t +crypto_verify_32_bytes(void) +{ + return crypto_verify_32_BYTES; +} + +size_t +crypto_verify_64_bytes(void) +{ + return crypto_verify_64_BYTES; +} + +#if defined(HAVE_EMMINTRIN_H) && defined(__SSE2__) + +# ifdef __GNUC__ +# pragma GCC target("sse2") +# endif +# include + +static inline int +crypto_verify_n(const unsigned char *x_, const unsigned char *y_, + const int n) +{ + const __m128i zero = _mm_setzero_si128(); + volatile __m128i v1, v2, z; + volatile int m; + int i; + + const volatile __m128i *volatile x = + (const volatile __m128i *volatile) (const void *) x_; + const volatile __m128i *volatile y = + (const volatile __m128i *volatile) (const void *) y_; + v1 = _mm_loadu_si128((const __m128i *) &x[0]); + v2 = _mm_loadu_si128((const __m128i *) &y[0]); + z = _mm_xor_si128(v1, v2); + for (i = 1; i < n / 16; i++) { + v1 = _mm_loadu_si128((const __m128i *) &x[i]); + v2 = _mm_loadu_si128((const __m128i *) &y[i]); + z = _mm_or_si128(z, _mm_xor_si128(v1, v2)); + } + m = _mm_movemask_epi8(_mm_cmpeq_epi32(z, zero)); + v1 = zero; v2 = zero; z = zero; + + return (int) (((uint32_t) m + 1U) >> 16) - 1; +} + +#else + +static inline int +crypto_verify_n(const unsigned char *x_, const unsigned char *y_, + const int n) +{ + const volatile unsigned char *volatile x = + (const volatile unsigned char *volatile) x_; + const volatile unsigned char *volatile y = + (const volatile unsigned char *volatile) y_; + volatile uint_fast16_t d = 0U; + int i; + + for (i = 0; i < n; i++) { + d |= x[i] ^ y[i]; + } + return (1 & ((d - 1) >> 8)) - 1; +} + +#endif + +int +crypto_verify_16(const unsigned char *x, const unsigned char *y) +{ + return crypto_verify_n(x, y, crypto_verify_16_BYTES); +} + +int +crypto_verify_32(const unsigned char *x, const unsigned char *y) +{ + return crypto_verify_n(x, y, crypto_verify_32_BYTES); +} + +int +crypto_verify_64(const unsigned char *x, const unsigned char *y) +{ + return crypto_verify_n(x, y, crypto_verify_64_BYTES); +} diff --git a/libs/libsodium/src/include/Makefile.am b/libs/libsodium/src/include/Makefile.am new file mode 100644 index 0000000000..b70c22b39b --- /dev/null +++ b/libs/libsodium/src/include/Makefile.am @@ -0,0 +1,75 @@ + +SODIUM_EXPORT = \ + sodium.h \ + sodium/core.h \ + sodium/crypto_aead_aes256gcm.h \ + sodium/crypto_aead_chacha20poly1305.h \ + sodium/crypto_aead_xchacha20poly1305.h \ + sodium/crypto_auth.h \ + sodium/crypto_auth_hmacsha256.h \ + sodium/crypto_auth_hmacsha512.h \ + sodium/crypto_auth_hmacsha512256.h \ + sodium/crypto_box.h \ + sodium/crypto_box_curve25519xchacha20poly1305.h \ + sodium/crypto_box_curve25519xsalsa20poly1305.h \ + sodium/crypto_core_ed25519.h \ + sodium/crypto_core_hchacha20.h \ + sodium/crypto_core_hsalsa20.h \ + sodium/crypto_core_salsa20.h \ + sodium/crypto_core_salsa2012.h \ + sodium/crypto_core_salsa208.h \ + sodium/crypto_generichash.h \ + sodium/crypto_generichash_blake2b.h \ + sodium/crypto_hash.h \ + sodium/crypto_hash_sha256.h \ + sodium/crypto_hash_sha512.h \ + sodium/crypto_kdf.h \ + sodium/crypto_kdf_blake2b.h \ + sodium/crypto_kx.h \ + sodium/crypto_onetimeauth.h \ + sodium/crypto_onetimeauth_poly1305.h \ + sodium/crypto_pwhash.h \ + sodium/crypto_pwhash_argon2i.h \ + sodium/crypto_pwhash_argon2id.h \ + sodium/crypto_pwhash_scryptsalsa208sha256.h \ + sodium/crypto_scalarmult.h \ + sodium/crypto_scalarmult_curve25519.h \ + sodium/crypto_scalarmult_ed25519.h \ + sodium/crypto_secretbox.h \ + sodium/crypto_secretbox_xchacha20poly1305.h \ + sodium/crypto_secretbox_xsalsa20poly1305.h \ + sodium/crypto_secretstream_xchacha20poly1305.h \ + sodium/crypto_shorthash.h \ + sodium/crypto_shorthash_siphash24.h \ + sodium/crypto_sign.h \ + sodium/crypto_sign_ed25519.h \ + sodium/crypto_sign_edwards25519sha512batch.h \ + sodium/crypto_stream.h \ + sodium/crypto_stream_chacha20.h \ + sodium/crypto_stream_salsa20.h \ + sodium/crypto_stream_salsa2012.h \ + sodium/crypto_stream_salsa208.h \ + sodium/crypto_stream_xchacha20.h \ + sodium/crypto_stream_xsalsa20.h \ + sodium/crypto_verify_16.h \ + sodium/crypto_verify_32.h \ + sodium/crypto_verify_64.h \ + sodium/export.h \ + sodium/randombytes.h \ + sodium/randombytes_salsa20_random.h \ + sodium/randombytes_sysrandom.h \ + sodium/runtime.h \ + sodium/utils.h + +if NATIVECLIENT +SODIUM_EXPORT += \ + sodium/randombytes_nativeclient.h +endif + +EXTRA_SRC = $(SODIUM_EXPORT) \ + sodium/version.h.in + +nobase_include_HEADERS = $(SODIUM_EXPORT) + +nobase_nodist_include_HEADERS = \ + sodium/version.h diff --git a/libs/libsodium/src/include/sodium.h b/libs/libsodium/src/include/sodium.h new file mode 100644 index 0000000000..e7b1af46f0 --- /dev/null +++ b/libs/libsodium/src/include/sodium.h @@ -0,0 +1,70 @@ + +#ifndef sodium_H +#define sodium_H + +#include "sodium/version.h" + +#include "sodium/core.h" +#include "sodium/crypto_aead_aes256gcm.h" +#include "sodium/crypto_aead_chacha20poly1305.h" +#include "sodium/crypto_aead_xchacha20poly1305.h" +#include "sodium/crypto_auth.h" +#include "sodium/crypto_auth_hmacsha256.h" +#include "sodium/crypto_auth_hmacsha512.h" +#include "sodium/crypto_auth_hmacsha512256.h" +#include "sodium/crypto_box.h" +#include "sodium/crypto_box_curve25519xsalsa20poly1305.h" +#include "sodium/crypto_core_hsalsa20.h" +#include "sodium/crypto_core_hchacha20.h" +#include "sodium/crypto_core_salsa20.h" +#include "sodium/crypto_core_salsa2012.h" +#include "sodium/crypto_core_salsa208.h" +#include "sodium/crypto_generichash.h" +#include "sodium/crypto_generichash_blake2b.h" +#include "sodium/crypto_hash.h" +#include "sodium/crypto_hash_sha256.h" +#include "sodium/crypto_hash_sha512.h" +#include "sodium/crypto_kdf.h" +#include "sodium/crypto_kdf_blake2b.h" +#include "sodium/crypto_kx.h" +#include "sodium/crypto_onetimeauth.h" +#include "sodium/crypto_onetimeauth_poly1305.h" +#include "sodium/crypto_pwhash.h" +#include "sodium/crypto_pwhash_argon2i.h" +#include "sodium/crypto_scalarmult.h" +#include "sodium/crypto_scalarmult_curve25519.h" +#include "sodium/crypto_secretbox.h" +#include "sodium/crypto_secretbox_xsalsa20poly1305.h" +#include "sodium/crypto_secretstream_xchacha20poly1305.h" +#include "sodium/crypto_shorthash.h" +#include "sodium/crypto_shorthash_siphash24.h" +#include "sodium/crypto_sign.h" +#include "sodium/crypto_sign_ed25519.h" +#include "sodium/crypto_stream.h" +#include "sodium/crypto_stream_chacha20.h" +#include "sodium/crypto_stream_salsa20.h" +#include "sodium/crypto_stream_xsalsa20.h" +#include "sodium/crypto_verify_16.h" +#include "sodium/crypto_verify_32.h" +#include "sodium/crypto_verify_64.h" +#include "sodium/randombytes.h" +#ifdef __native_client__ +# include "sodium/randombytes_nativeclient.h" +#endif +#include "sodium/randombytes_salsa20_random.h" +#include "sodium/randombytes_sysrandom.h" +#include "sodium/runtime.h" +#include "sodium/utils.h" + +#ifndef SODIUM_LIBRARY_MINIMAL +# include "sodium/crypto_box_curve25519xchacha20poly1305.h" +# include "sodium/crypto_core_ed25519.h" +# include "sodium/crypto_scalarmult_ed25519.h" +# include "sodium/crypto_secretbox_xchacha20poly1305.h" +# include "sodium/crypto_pwhash_scryptsalsa208sha256.h" +# include "sodium/crypto_stream_salsa2012.h" +# include "sodium/crypto_stream_salsa208.h" +# include "sodium/crypto_stream_xchacha20.h" +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/core.h b/libs/libsodium/src/include/sodium/core.h new file mode 100644 index 0000000000..dd088d2cae --- /dev/null +++ b/libs/libsodium/src/include/sodium/core.h @@ -0,0 +1,28 @@ + +#ifndef sodium_core_H +#define sodium_core_H + +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SODIUM_EXPORT +int sodium_init(void) + __attribute__ ((warn_unused_result)); + +/* ---- */ + +SODIUM_EXPORT +int sodium_set_misuse_handler(void (*handler)(void)); + +SODIUM_EXPORT +void sodium_misuse(void) + __attribute__ ((noreturn)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_aead_aes256gcm.h b/libs/libsodium/src/include/sodium/crypto_aead_aes256gcm.h new file mode 100644 index 0000000000..46a3800f37 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_aead_aes256gcm.h @@ -0,0 +1,171 @@ +#ifndef crypto_aead_aes256gcm_H +#define crypto_aead_aes256gcm_H + +/* + * WARNING: Despite being the most popular AEAD construction due to its + * use in TLS, safely using AES-GCM in a different context is tricky. + * + * No more than ~ 350 GB of input data should be encrypted with a given key. + * This is for ~ 16 KB messages -- Actual figures vary according to + * message sizes. + * + * In addition, nonces are short and repeated nonces would totally destroy + * the security of this scheme. + * + * Nonces should thus come from atomic counters, which can be difficult to + * set up in a distributed environment. + * + * Unless you absolutely need AES-GCM, use crypto_aead_xchacha20poly1305_ietf_*() + * instead. It doesn't have any of these limitations. + * Or, if you don't need to authenticate additional data, just stick to + * crypto_secretbox(). + */ + +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +SODIUM_EXPORT +int crypto_aead_aes256gcm_is_available(void); + +#define crypto_aead_aes256gcm_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_aead_aes256gcm_keybytes(void); + +#define crypto_aead_aes256gcm_NSECBYTES 0U +SODIUM_EXPORT +size_t crypto_aead_aes256gcm_nsecbytes(void); + +#define crypto_aead_aes256gcm_NPUBBYTES 12U +SODIUM_EXPORT +size_t crypto_aead_aes256gcm_npubbytes(void); + +#define crypto_aead_aes256gcm_ABYTES 16U +SODIUM_EXPORT +size_t crypto_aead_aes256gcm_abytes(void); + +#define crypto_aead_aes256gcm_MESSAGEBYTES_MAX \ + SODIUM_MIN(SODIUM_SIZE_MAX - crypto_aead_aes256gcm_ABYTES, \ + (16ULL * ((1ULL << 32) - 2ULL)) - crypto_aead_aes256gcm_ABYTES) +SODIUM_EXPORT +size_t crypto_aead_aes256gcm_messagebytes_max(void); + +typedef CRYPTO_ALIGN(16) unsigned char crypto_aead_aes256gcm_state[512]; + +SODIUM_EXPORT +size_t crypto_aead_aes256gcm_statebytes(void); + +SODIUM_EXPORT +int crypto_aead_aes256gcm_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_aes256gcm_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_aead_aes256gcm_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_aes256gcm_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +/* -- Precomputation interface -- */ + +SODIUM_EXPORT +int crypto_aead_aes256gcm_beforenm(crypto_aead_aes256gcm_state *ctx_, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_aes256gcm_encrypt_afternm(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_); + +SODIUM_EXPORT +int crypto_aead_aes256gcm_decrypt_afternm(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_aead_aes256gcm_encrypt_detached_afternm(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_); + +SODIUM_EXPORT +int crypto_aead_aes256gcm_decrypt_detached_afternm(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const crypto_aead_aes256gcm_state *ctx_) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +void crypto_aead_aes256gcm_keygen(unsigned char k[crypto_aead_aes256gcm_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_aead_chacha20poly1305.h b/libs/libsodium/src/include/sodium/crypto_aead_chacha20poly1305.h new file mode 100644 index 0000000000..a575ec7173 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_aead_chacha20poly1305.h @@ -0,0 +1,174 @@ +#ifndef crypto_aead_chacha20poly1305_H +#define crypto_aead_chacha20poly1305_H + +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +/* -- IETF ChaCha20-Poly1305 construction with a 96-bit nonce and a 32-bit internal counter -- */ + +#define crypto_aead_chacha20poly1305_ietf_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_ietf_keybytes(void); + +#define crypto_aead_chacha20poly1305_ietf_NSECBYTES 0U +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_ietf_nsecbytes(void); + +#define crypto_aead_chacha20poly1305_ietf_NPUBBYTES 12U + +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_ietf_npubbytes(void); + +#define crypto_aead_chacha20poly1305_ietf_ABYTES 16U +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_ietf_abytes(void); + +#define crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX \ + SODIUM_MIN(SODIUM_SIZE_MAX - crypto_aead_chacha20poly1305_ietf_ABYTES, \ + (64ULL * (1ULL << 32) - 64ULL) - crypto_aead_chacha20poly1305_ietf_ABYTES) +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_ietf_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_aead_chacha20poly1305_ietf_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_chacha20poly1305_ietf_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_aead_chacha20poly1305_ietf_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_chacha20poly1305_ietf_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +void crypto_aead_chacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_chacha20poly1305_ietf_KEYBYTES]); + +/* -- Original ChaCha20-Poly1305 construction with a 64-bit nonce and a 64-bit internal counter -- */ + +#define crypto_aead_chacha20poly1305_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_keybytes(void); + +#define crypto_aead_chacha20poly1305_NSECBYTES 0U +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_nsecbytes(void); + +#define crypto_aead_chacha20poly1305_NPUBBYTES 8U +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_npubbytes(void); + +#define crypto_aead_chacha20poly1305_ABYTES 16U +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_abytes(void); + +#define crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX \ + (SODIUM_SIZE_MAX - crypto_aead_chacha20poly1305_ABYTES) +SODIUM_EXPORT +size_t crypto_aead_chacha20poly1305_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_aead_chacha20poly1305_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_chacha20poly1305_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_aead_chacha20poly1305_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_chacha20poly1305_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +void crypto_aead_chacha20poly1305_keygen(unsigned char k[crypto_aead_chacha20poly1305_KEYBYTES]); + +/* Aliases */ + +#define crypto_aead_chacha20poly1305_IETF_KEYBYTES crypto_aead_chacha20poly1305_ietf_KEYBYTES +#define crypto_aead_chacha20poly1305_IETF_NSECBYTES crypto_aead_chacha20poly1305_ietf_NSECBYTES +#define crypto_aead_chacha20poly1305_IETF_NPUBBYTES crypto_aead_chacha20poly1305_ietf_NPUBBYTES +#define crypto_aead_chacha20poly1305_IETF_ABYTES crypto_aead_chacha20poly1305_ietf_ABYTES +#define crypto_aead_chacha20poly1305_IETF_MESSAGEBYTES_MAX crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_aead_xchacha20poly1305.h b/libs/libsodium/src/include/sodium/crypto_aead_xchacha20poly1305.h new file mode 100644 index 0000000000..99692aae9a --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_aead_xchacha20poly1305.h @@ -0,0 +1,97 @@ +#ifndef crypto_aead_xchacha20poly1305_H +#define crypto_aead_xchacha20poly1305_H + +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_aead_xchacha20poly1305_ietf_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_aead_xchacha20poly1305_ietf_keybytes(void); + +#define crypto_aead_xchacha20poly1305_ietf_NSECBYTES 0U +SODIUM_EXPORT +size_t crypto_aead_xchacha20poly1305_ietf_nsecbytes(void); + +#define crypto_aead_xchacha20poly1305_ietf_NPUBBYTES 24U +SODIUM_EXPORT +size_t crypto_aead_xchacha20poly1305_ietf_npubbytes(void); + +#define crypto_aead_xchacha20poly1305_ietf_ABYTES 16U +SODIUM_EXPORT +size_t crypto_aead_xchacha20poly1305_ietf_abytes(void); + +#define crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX \ + (SODIUM_SIZE_MAX - crypto_aead_xchacha20poly1305_ietf_ABYTES) +SODIUM_EXPORT +size_t crypto_aead_xchacha20poly1305_ietf_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_xchacha20poly1305_ietf_decrypt(unsigned char *m, + unsigned long long *mlen_p, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_aead_xchacha20poly1305_ietf_encrypt_detached(unsigned char *c, + unsigned char *mac, + unsigned long long *maclen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m, + unsigned char *nsec, + const unsigned char *c, + unsigned long long clen, + const unsigned char *mac, + const unsigned char *ad, + unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +void crypto_aead_xchacha20poly1305_ietf_keygen(unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES]); + +/* Aliases */ + +#define crypto_aead_xchacha20poly1305_IETF_KEYBYTES crypto_aead_xchacha20poly1305_ietf_KEYBYTES +#define crypto_aead_xchacha20poly1305_IETF_NSECBYTES crypto_aead_xchacha20poly1305_ietf_NSECBYTES +#define crypto_aead_xchacha20poly1305_IETF_NPUBBYTES crypto_aead_xchacha20poly1305_ietf_NPUBBYTES +#define crypto_aead_xchacha20poly1305_IETF_ABYTES crypto_aead_xchacha20poly1305_ietf_ABYTES +#define crypto_aead_xchacha20poly1305_IETF_MESSAGEBYTES_MAX crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_auth.h b/libs/libsodium/src/include/sodium/crypto_auth.h new file mode 100644 index 0000000000..7174e7bced --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_auth.h @@ -0,0 +1,44 @@ +#ifndef crypto_auth_H +#define crypto_auth_H + +#include + +#include "crypto_auth_hmacsha512256.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES +SODIUM_EXPORT +size_t crypto_auth_bytes(void); + +#define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES +SODIUM_EXPORT +size_t crypto_auth_keybytes(void); + +#define crypto_auth_PRIMITIVE "hmacsha512256" +SODIUM_EXPORT +const char *crypto_auth_primitive(void); + +SODIUM_EXPORT +int crypto_auth(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k); + +SODIUM_EXPORT +int crypto_auth_verify(const unsigned char *h, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +void crypto_auth_keygen(unsigned char k[crypto_auth_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_auth_hmacsha256.h b/libs/libsodium/src/include/sodium/crypto_auth_hmacsha256.h new file mode 100644 index 0000000000..deec5266e6 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_auth_hmacsha256.h @@ -0,0 +1,68 @@ +#ifndef crypto_auth_hmacsha256_H +#define crypto_auth_hmacsha256_H + +#include +#include "crypto_hash_sha256.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_auth_hmacsha256_BYTES 32U +SODIUM_EXPORT +size_t crypto_auth_hmacsha256_bytes(void); + +#define crypto_auth_hmacsha256_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_auth_hmacsha256_keybytes(void); + +SODIUM_EXPORT +int crypto_auth_hmacsha256(unsigned char *out, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_auth_hmacsha256_verify(const unsigned char *h, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +/* ------------------------------------------------------------------------- */ + +typedef struct crypto_auth_hmacsha256_state { + crypto_hash_sha256_state ictx; + crypto_hash_sha256_state octx; +} crypto_auth_hmacsha256_state; + +SODIUM_EXPORT +size_t crypto_auth_hmacsha256_statebytes(void); + +SODIUM_EXPORT +int crypto_auth_hmacsha256_init(crypto_auth_hmacsha256_state *state, + const unsigned char *key, + size_t keylen); + +SODIUM_EXPORT +int crypto_auth_hmacsha256_update(crypto_auth_hmacsha256_state *state, + const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_auth_hmacsha256_final(crypto_auth_hmacsha256_state *state, + unsigned char *out); + + +SODIUM_EXPORT +void crypto_auth_hmacsha256_keygen(unsigned char k[crypto_auth_hmacsha256_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_auth_hmacsha512.h b/libs/libsodium/src/include/sodium/crypto_auth_hmacsha512.h new file mode 100644 index 0000000000..77a55fbc00 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_auth_hmacsha512.h @@ -0,0 +1,67 @@ +#ifndef crypto_auth_hmacsha512_H +#define crypto_auth_hmacsha512_H + +#include +#include "crypto_hash_sha512.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_auth_hmacsha512_BYTES 64U +SODIUM_EXPORT +size_t crypto_auth_hmacsha512_bytes(void); + +#define crypto_auth_hmacsha512_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_auth_hmacsha512_keybytes(void); + +SODIUM_EXPORT +int crypto_auth_hmacsha512(unsigned char *out, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_auth_hmacsha512_verify(const unsigned char *h, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +/* ------------------------------------------------------------------------- */ + +typedef struct crypto_auth_hmacsha512_state { + crypto_hash_sha512_state ictx; + crypto_hash_sha512_state octx; +} crypto_auth_hmacsha512_state; + +SODIUM_EXPORT +size_t crypto_auth_hmacsha512_statebytes(void); + +SODIUM_EXPORT +int crypto_auth_hmacsha512_init(crypto_auth_hmacsha512_state *state, + const unsigned char *key, + size_t keylen); + +SODIUM_EXPORT +int crypto_auth_hmacsha512_update(crypto_auth_hmacsha512_state *state, + const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_auth_hmacsha512_final(crypto_auth_hmacsha512_state *state, + unsigned char *out); + +SODIUM_EXPORT +void crypto_auth_hmacsha512_keygen(unsigned char k[crypto_auth_hmacsha512_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_auth_hmacsha512256.h b/libs/libsodium/src/include/sodium/crypto_auth_hmacsha512256.h new file mode 100644 index 0000000000..4842f3debc --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_auth_hmacsha512256.h @@ -0,0 +1,62 @@ +#ifndef crypto_auth_hmacsha512256_H +#define crypto_auth_hmacsha512256_H + +#include +#include "crypto_auth_hmacsha512.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_auth_hmacsha512256_BYTES 32U +SODIUM_EXPORT +size_t crypto_auth_hmacsha512256_bytes(void); + +#define crypto_auth_hmacsha512256_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_auth_hmacsha512256_keybytes(void); + +SODIUM_EXPORT +int crypto_auth_hmacsha512256(unsigned char *out, const unsigned char *in, + unsigned long long inlen,const unsigned char *k); + +SODIUM_EXPORT +int crypto_auth_hmacsha512256_verify(const unsigned char *h, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +/* ------------------------------------------------------------------------- */ + +typedef crypto_auth_hmacsha512_state crypto_auth_hmacsha512256_state; + +SODIUM_EXPORT +size_t crypto_auth_hmacsha512256_statebytes(void); + +SODIUM_EXPORT +int crypto_auth_hmacsha512256_init(crypto_auth_hmacsha512256_state *state, + const unsigned char *key, + size_t keylen); + +SODIUM_EXPORT +int crypto_auth_hmacsha512256_update(crypto_auth_hmacsha512256_state *state, + const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_auth_hmacsha512256_final(crypto_auth_hmacsha512256_state *state, + unsigned char *out); + +SODIUM_EXPORT +void crypto_auth_hmacsha512256_keygen(unsigned char k[crypto_auth_hmacsha512256_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_box.h b/libs/libsodium/src/include/sodium/crypto_box.h new file mode 100644 index 0000000000..99ee19a8f6 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_box.h @@ -0,0 +1,173 @@ +#ifndef crypto_box_H +#define crypto_box_H + +/* + * THREAD SAFETY: crypto_box_keypair() is thread-safe, + * provided that sodium_init() was called before. + * + * Other functions are always thread-safe. + */ + +#include + +#include "crypto_box_curve25519xsalsa20poly1305.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_box_SEEDBYTES crypto_box_curve25519xsalsa20poly1305_SEEDBYTES +SODIUM_EXPORT +size_t crypto_box_seedbytes(void); + +#define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES +SODIUM_EXPORT +size_t crypto_box_publickeybytes(void); + +#define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES +SODIUM_EXPORT +size_t crypto_box_secretkeybytes(void); + +#define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES +SODIUM_EXPORT +size_t crypto_box_noncebytes(void); + +#define crypto_box_MACBYTES crypto_box_curve25519xsalsa20poly1305_MACBYTES +SODIUM_EXPORT +size_t crypto_box_macbytes(void); + +#define crypto_box_MESSAGEBYTES_MAX crypto_box_curve25519xsalsa20poly1305_MESSAGEBYTES_MAX +SODIUM_EXPORT +size_t crypto_box_messagebytes_max(void); + +#define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305" +SODIUM_EXPORT +const char *crypto_box_primitive(void); + +SODIUM_EXPORT +int crypto_box_seed_keypair(unsigned char *pk, unsigned char *sk, + const unsigned char *seed); + +SODIUM_EXPORT +int crypto_box_keypair(unsigned char *pk, unsigned char *sk); + +SODIUM_EXPORT +int crypto_box_easy(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_open_easy(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_detached(unsigned char *c, unsigned char *mac, + const unsigned char *m, unsigned long long mlen, + const unsigned char *n, const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_open_detached(unsigned char *m, const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, + const unsigned char *n, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +/* -- Precomputation interface -- */ + +#define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES +SODIUM_EXPORT +size_t crypto_box_beforenmbytes(void); + +SODIUM_EXPORT +int crypto_box_beforenm(unsigned char *k, const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_easy_afternm(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_box_open_easy_afternm(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_detached_afternm(unsigned char *c, unsigned char *mac, + const unsigned char *m, unsigned long long mlen, + const unsigned char *n, const unsigned char *k); + +SODIUM_EXPORT +int crypto_box_open_detached_afternm(unsigned char *m, const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +/* -- Ephemeral SK interface -- */ + +#define crypto_box_SEALBYTES (crypto_box_PUBLICKEYBYTES + crypto_box_MACBYTES) +SODIUM_EXPORT +size_t crypto_box_sealbytes(void); + +SODIUM_EXPORT +int crypto_box_seal(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *pk); + +SODIUM_EXPORT +int crypto_box_seal_open(unsigned char *m, const unsigned char *c, + unsigned long long clen, + const unsigned char *pk, const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +/* -- NaCl compatibility interface ; Requires padding -- */ + +#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES +SODIUM_EXPORT +size_t crypto_box_zerobytes(void); + +#define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES +SODIUM_EXPORT +size_t crypto_box_boxzerobytes(void); + +SODIUM_EXPORT +int crypto_box(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_open(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_afternm(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_box_open_afternm(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_box_curve25519xchacha20poly1305.h b/libs/libsodium/src/include/sodium/crypto_box_curve25519xchacha20poly1305.h new file mode 100644 index 0000000000..c1cf756687 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_box_curve25519xchacha20poly1305.h @@ -0,0 +1,159 @@ + +#ifndef crypto_box_curve25519xchacha20poly1305_H +#define crypto_box_curve25519xchacha20poly1305_H + +#include +#include "crypto_stream_xchacha20.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_box_curve25519xchacha20poly1305_SEEDBYTES 32U +SODIUM_EXPORT +size_t crypto_box_curve25519xchacha20poly1305_seedbytes(void); + +#define crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES 32U +SODIUM_EXPORT +size_t crypto_box_curve25519xchacha20poly1305_publickeybytes(void); + +#define crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES 32U +SODIUM_EXPORT +size_t crypto_box_curve25519xchacha20poly1305_secretkeybytes(void); + +#define crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES 32U +SODIUM_EXPORT +size_t crypto_box_curve25519xchacha20poly1305_beforenmbytes(void); + +#define crypto_box_curve25519xchacha20poly1305_NONCEBYTES 24U +SODIUM_EXPORT +size_t crypto_box_curve25519xchacha20poly1305_noncebytes(void); + +#define crypto_box_curve25519xchacha20poly1305_MACBYTES 16U +SODIUM_EXPORT +size_t crypto_box_curve25519xchacha20poly1305_macbytes(void); + +#define crypto_box_curve25519xchacha20poly1305_MESSAGEBYTES_MAX \ + (crypto_stream_xchacha20_MESSAGEBYTES_MAX - crypto_box_curve25519xchacha20poly1305_MACBYTES) +SODIUM_EXPORT +size_t crypto_box_curve25519xchacha20poly1305_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_seed_keypair(unsigned char *pk, + unsigned char *sk, + const unsigned char *seed); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_keypair(unsigned char *pk, + unsigned char *sk); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_easy(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_open_easy(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_detached(unsigned char *c, + unsigned char *mac, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_open_detached(unsigned char *m, + const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, + const unsigned char *n, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +/* -- Precomputation interface -- */ + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_beforenm(unsigned char *k, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_easy_afternm(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_open_easy_afternm(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_detached_afternm(unsigned char *c, + unsigned char *mac, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_open_detached_afternm(unsigned char *m, + const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +/* -- Ephemeral SK interface -- */ + +#define crypto_box_curve25519xchacha20poly1305_SEALBYTES \ + (crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES + \ + crypto_box_curve25519xchacha20poly1305_MACBYTES) + +SODIUM_EXPORT +size_t crypto_box_curve25519xchacha20poly1305_sealbytes(void); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_seal(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk); + +SODIUM_EXPORT +int crypto_box_curve25519xchacha20poly1305_seal_open(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_box_curve25519xsalsa20poly1305.h b/libs/libsodium/src/include/sodium/crypto_box_curve25519xsalsa20poly1305.h new file mode 100644 index 0000000000..c5b15f42e4 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_box_curve25519xsalsa20poly1305.h @@ -0,0 +1,109 @@ +#ifndef crypto_box_curve25519xsalsa20poly1305_H +#define crypto_box_curve25519xsalsa20poly1305_H + +#include +#include "crypto_stream_xsalsa20.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_box_curve25519xsalsa20poly1305_SEEDBYTES 32U +SODIUM_EXPORT +size_t crypto_box_curve25519xsalsa20poly1305_seedbytes(void); + +#define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES 32U +SODIUM_EXPORT +size_t crypto_box_curve25519xsalsa20poly1305_publickeybytes(void); + +#define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES 32U +SODIUM_EXPORT +size_t crypto_box_curve25519xsalsa20poly1305_secretkeybytes(void); + +#define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES 32U +SODIUM_EXPORT +size_t crypto_box_curve25519xsalsa20poly1305_beforenmbytes(void); + +#define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES 24U +SODIUM_EXPORT +size_t crypto_box_curve25519xsalsa20poly1305_noncebytes(void); + +#define crypto_box_curve25519xsalsa20poly1305_MACBYTES 16U +SODIUM_EXPORT +size_t crypto_box_curve25519xsalsa20poly1305_macbytes(void); + +/* Only for the libsodium API - The NaCl compatibility API would require BOXZEROBYTES extra bytes */ +#define crypto_box_curve25519xsalsa20poly1305_MESSAGEBYTES_MAX \ + (crypto_stream_xsalsa20_MESSAGEBYTES_MAX - crypto_box_curve25519xsalsa20poly1305_MACBYTES) +SODIUM_EXPORT +size_t crypto_box_curve25519xsalsa20poly1305_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_box_curve25519xsalsa20poly1305_seed_keypair(unsigned char *pk, + unsigned char *sk, + const unsigned char *seed); + +SODIUM_EXPORT +int crypto_box_curve25519xsalsa20poly1305_keypair(unsigned char *pk, + unsigned char *sk); + +SODIUM_EXPORT +int crypto_box_curve25519xsalsa20poly1305_beforenm(unsigned char *k, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +/* -- NaCl compatibility interface ; Requires padding -- */ + +#define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES 16U +SODIUM_EXPORT +size_t crypto_box_curve25519xsalsa20poly1305_boxzerobytes(void); + +#define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES \ + (crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES + \ + crypto_box_curve25519xsalsa20poly1305_MACBYTES) +SODIUM_EXPORT +size_t crypto_box_curve25519xsalsa20poly1305_zerobytes(void); + +SODIUM_EXPORT +int crypto_box_curve25519xsalsa20poly1305(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_curve25519xsalsa20poly1305_open(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *pk, + const unsigned char *sk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_box_curve25519xsalsa20poly1305_afternm(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_box_curve25519xsalsa20poly1305_open_afternm(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_core_ed25519.h b/libs/libsodium/src/include/sodium/crypto_core_ed25519.h new file mode 100644 index 0000000000..1536294b21 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_core_ed25519.h @@ -0,0 +1,37 @@ +#ifndef crypto_core_ed25519_H +#define crypto_core_ed25519_H + +#include +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_core_ed25519_BYTES 32 +SODIUM_EXPORT +size_t crypto_core_ed25519_bytes(void); + +#define crypto_core_ed25519_UNIFORMBYTES 32 +SODIUM_EXPORT +size_t crypto_core_ed25519_uniformbytes(void); + +SODIUM_EXPORT +int crypto_core_ed25519_is_valid_point(const unsigned char *p); + +SODIUM_EXPORT +int crypto_core_ed25519_add(unsigned char *r, + const unsigned char *p, const unsigned char *q); + +SODIUM_EXPORT +int crypto_core_ed25519_sub(unsigned char *r, + const unsigned char *p, const unsigned char *q); + +SODIUM_EXPORT +int crypto_core_ed25519_from_uniform(unsigned char *p, const unsigned char *r); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_core_hchacha20.h b/libs/libsodium/src/include/sodium/crypto_core_hchacha20.h new file mode 100644 index 0000000000..05e5670c10 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_core_hchacha20.h @@ -0,0 +1,35 @@ +#ifndef crypto_core_hchacha20_H +#define crypto_core_hchacha20_H + +#include +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_core_hchacha20_OUTPUTBYTES 32U +SODIUM_EXPORT +size_t crypto_core_hchacha20_outputbytes(void); + +#define crypto_core_hchacha20_INPUTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_hchacha20_inputbytes(void); + +#define crypto_core_hchacha20_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_core_hchacha20_keybytes(void); + +#define crypto_core_hchacha20_CONSTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_hchacha20_constbytes(void); + +SODIUM_EXPORT +int crypto_core_hchacha20(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_core_hsalsa20.h b/libs/libsodium/src/include/sodium/crypto_core_hsalsa20.h new file mode 100644 index 0000000000..82e475b8f6 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_core_hsalsa20.h @@ -0,0 +1,35 @@ +#ifndef crypto_core_hsalsa20_H +#define crypto_core_hsalsa20_H + +#include +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_core_hsalsa20_OUTPUTBYTES 32U +SODIUM_EXPORT +size_t crypto_core_hsalsa20_outputbytes(void); + +#define crypto_core_hsalsa20_INPUTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_hsalsa20_inputbytes(void); + +#define crypto_core_hsalsa20_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_core_hsalsa20_keybytes(void); + +#define crypto_core_hsalsa20_CONSTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_hsalsa20_constbytes(void); + +SODIUM_EXPORT +int crypto_core_hsalsa20(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_core_salsa20.h b/libs/libsodium/src/include/sodium/crypto_core_salsa20.h new file mode 100644 index 0000000000..160cc56d2c --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_core_salsa20.h @@ -0,0 +1,35 @@ +#ifndef crypto_core_salsa20_H +#define crypto_core_salsa20_H + +#include +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_core_salsa20_OUTPUTBYTES 64U +SODIUM_EXPORT +size_t crypto_core_salsa20_outputbytes(void); + +#define crypto_core_salsa20_INPUTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_salsa20_inputbytes(void); + +#define crypto_core_salsa20_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_core_salsa20_keybytes(void); + +#define crypto_core_salsa20_CONSTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_salsa20_constbytes(void); + +SODIUM_EXPORT +int crypto_core_salsa20(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_core_salsa2012.h b/libs/libsodium/src/include/sodium/crypto_core_salsa2012.h new file mode 100644 index 0000000000..bdd5f9fdbb --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_core_salsa2012.h @@ -0,0 +1,35 @@ +#ifndef crypto_core_salsa2012_H +#define crypto_core_salsa2012_H + +#include +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_core_salsa2012_OUTPUTBYTES 64U +SODIUM_EXPORT +size_t crypto_core_salsa2012_outputbytes(void); + +#define crypto_core_salsa2012_INPUTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_salsa2012_inputbytes(void); + +#define crypto_core_salsa2012_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_core_salsa2012_keybytes(void); + +#define crypto_core_salsa2012_CONSTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_salsa2012_constbytes(void); + +SODIUM_EXPORT +int crypto_core_salsa2012(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_core_salsa208.h b/libs/libsodium/src/include/sodium/crypto_core_salsa208.h new file mode 100644 index 0000000000..876bda8936 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_core_salsa208.h @@ -0,0 +1,39 @@ +#ifndef crypto_core_salsa208_H +#define crypto_core_salsa208_H + +#include +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_core_salsa208_OUTPUTBYTES 64U +SODIUM_EXPORT +size_t crypto_core_salsa208_outputbytes(void) + __attribute__ ((deprecated)); + +#define crypto_core_salsa208_INPUTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_salsa208_inputbytes(void) + __attribute__ ((deprecated)); + +#define crypto_core_salsa208_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_core_salsa208_keybytes(void) + __attribute__ ((deprecated)); + +#define crypto_core_salsa208_CONSTBYTES 16U +SODIUM_EXPORT +size_t crypto_core_salsa208_constbytes(void) + __attribute__ ((deprecated)); + +SODIUM_EXPORT +int crypto_core_salsa208(unsigned char *out, const unsigned char *in, + const unsigned char *k, const unsigned char *c); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_generichash.h b/libs/libsodium/src/include/sodium/crypto_generichash.h new file mode 100644 index 0000000000..2398fb9dbb --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_generichash.h @@ -0,0 +1,75 @@ +#ifndef crypto_generichash_H +#define crypto_generichash_H + +#include + +#include "crypto_generichash_blake2b.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_generichash_BYTES_MIN crypto_generichash_blake2b_BYTES_MIN +SODIUM_EXPORT +size_t crypto_generichash_bytes_min(void); + +#define crypto_generichash_BYTES_MAX crypto_generichash_blake2b_BYTES_MAX +SODIUM_EXPORT +size_t crypto_generichash_bytes_max(void); + +#define crypto_generichash_BYTES crypto_generichash_blake2b_BYTES +SODIUM_EXPORT +size_t crypto_generichash_bytes(void); + +#define crypto_generichash_KEYBYTES_MIN crypto_generichash_blake2b_KEYBYTES_MIN +SODIUM_EXPORT +size_t crypto_generichash_keybytes_min(void); + +#define crypto_generichash_KEYBYTES_MAX crypto_generichash_blake2b_KEYBYTES_MAX +SODIUM_EXPORT +size_t crypto_generichash_keybytes_max(void); + +#define crypto_generichash_KEYBYTES crypto_generichash_blake2b_KEYBYTES +SODIUM_EXPORT +size_t crypto_generichash_keybytes(void); + +#define crypto_generichash_PRIMITIVE "blake2b" +SODIUM_EXPORT +const char *crypto_generichash_primitive(void); + +typedef crypto_generichash_blake2b_state crypto_generichash_state; + +SODIUM_EXPORT +size_t crypto_generichash_statebytes(void); + +SODIUM_EXPORT +int crypto_generichash(unsigned char *out, size_t outlen, + const unsigned char *in, unsigned long long inlen, + const unsigned char *key, size_t keylen); + +SODIUM_EXPORT +int crypto_generichash_init(crypto_generichash_state *state, + const unsigned char *key, + const size_t keylen, const size_t outlen); + +SODIUM_EXPORT +int crypto_generichash_update(crypto_generichash_state *state, + const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_generichash_final(crypto_generichash_state *state, + unsigned char *out, const size_t outlen); + +SODIUM_EXPORT +void crypto_generichash_keygen(unsigned char k[crypto_generichash_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_generichash_blake2b.h b/libs/libsodium/src/include/sodium/crypto_generichash_blake2b.h new file mode 100644 index 0000000000..9326a04ad1 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_generichash_blake2b.h @@ -0,0 +1,117 @@ +#ifndef crypto_generichash_blake2b_H +#define crypto_generichash_blake2b_H + +#include +#include +#include + +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack(1) +#else +# pragma pack(push, 1) +#endif + +typedef struct CRYPTO_ALIGN(64) crypto_generichash_blake2b_state { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[2 * 128]; + size_t buflen; + uint8_t last_node; +} crypto_generichash_blake2b_state; + +#if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack() +#else +# pragma pack(pop) +#endif + +#define crypto_generichash_blake2b_BYTES_MIN 16U +SODIUM_EXPORT +size_t crypto_generichash_blake2b_bytes_min(void); + +#define crypto_generichash_blake2b_BYTES_MAX 64U +SODIUM_EXPORT +size_t crypto_generichash_blake2b_bytes_max(void); + +#define crypto_generichash_blake2b_BYTES 32U +SODIUM_EXPORT +size_t crypto_generichash_blake2b_bytes(void); + +#define crypto_generichash_blake2b_KEYBYTES_MIN 16U +SODIUM_EXPORT +size_t crypto_generichash_blake2b_keybytes_min(void); + +#define crypto_generichash_blake2b_KEYBYTES_MAX 64U +SODIUM_EXPORT +size_t crypto_generichash_blake2b_keybytes_max(void); + +#define crypto_generichash_blake2b_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_generichash_blake2b_keybytes(void); + +#define crypto_generichash_blake2b_SALTBYTES 16U +SODIUM_EXPORT +size_t crypto_generichash_blake2b_saltbytes(void); + +#define crypto_generichash_blake2b_PERSONALBYTES 16U +SODIUM_EXPORT +size_t crypto_generichash_blake2b_personalbytes(void); + +SODIUM_EXPORT +size_t crypto_generichash_blake2b_statebytes(void); + +SODIUM_EXPORT +int crypto_generichash_blake2b(unsigned char *out, size_t outlen, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *key, size_t keylen); + +SODIUM_EXPORT +int crypto_generichash_blake2b_salt_personal(unsigned char *out, size_t outlen, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *key, + size_t keylen, + const unsigned char *salt, + const unsigned char *personal); + +SODIUM_EXPORT +int crypto_generichash_blake2b_init(crypto_generichash_blake2b_state *state, + const unsigned char *key, + const size_t keylen, const size_t outlen); + +SODIUM_EXPORT +int crypto_generichash_blake2b_init_salt_personal(crypto_generichash_blake2b_state *state, + const unsigned char *key, + const size_t keylen, const size_t outlen, + const unsigned char *salt, + const unsigned char *personal); + +SODIUM_EXPORT +int crypto_generichash_blake2b_update(crypto_generichash_blake2b_state *state, + const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_generichash_blake2b_final(crypto_generichash_blake2b_state *state, + unsigned char *out, + const size_t outlen); + +SODIUM_EXPORT +void crypto_generichash_blake2b_keygen(unsigned char k[crypto_generichash_blake2b_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_hash.h b/libs/libsodium/src/include/sodium/crypto_hash.h new file mode 100644 index 0000000000..302ed5c5ea --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_hash.h @@ -0,0 +1,40 @@ +#ifndef crypto_hash_H +#define crypto_hash_H + +/* + * WARNING: Unless you absolutely need to use SHA512 for interoperatibility, + * purposes, you might want to consider crypto_generichash() instead. + * Unlike SHA512, crypto_generichash() is not vulnerable to length + * extension attacks. + */ + +#include + +#include "crypto_hash_sha512.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_hash_BYTES crypto_hash_sha512_BYTES +SODIUM_EXPORT +size_t crypto_hash_bytes(void); + +SODIUM_EXPORT +int crypto_hash(unsigned char *out, const unsigned char *in, + unsigned long long inlen); + +#define crypto_hash_PRIMITIVE "sha512" +SODIUM_EXPORT +const char *crypto_hash_primitive(void) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_hash_sha256.h b/libs/libsodium/src/include/sodium/crypto_hash_sha256.h new file mode 100644 index 0000000000..f64d16e0e5 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_hash_sha256.h @@ -0,0 +1,57 @@ +#ifndef crypto_hash_sha256_H +#define crypto_hash_sha256_H + +/* + * WARNING: Unless you absolutely need to use SHA256 for interoperatibility, + * purposes, you might want to consider crypto_generichash() instead. + * Unlike SHA256, crypto_generichash() is not vulnerable to length + * extension attacks. + */ + +#include +#include +#include + +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +typedef struct crypto_hash_sha256_state { + uint32_t state[8]; + uint64_t count; + uint8_t buf[64]; +} crypto_hash_sha256_state; + +SODIUM_EXPORT +size_t crypto_hash_sha256_statebytes(void); + +#define crypto_hash_sha256_BYTES 32U +SODIUM_EXPORT +size_t crypto_hash_sha256_bytes(void); + +SODIUM_EXPORT +int crypto_hash_sha256(unsigned char *out, const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_hash_sha256_init(crypto_hash_sha256_state *state); + +SODIUM_EXPORT +int crypto_hash_sha256_update(crypto_hash_sha256_state *state, + const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_hash_sha256_final(crypto_hash_sha256_state *state, + unsigned char *out); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_hash_sha512.h b/libs/libsodium/src/include/sodium/crypto_hash_sha512.h new file mode 100644 index 0000000000..6b0330f14f --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_hash_sha512.h @@ -0,0 +1,57 @@ +#ifndef crypto_hash_sha512_H +#define crypto_hash_sha512_H + +/* + * WARNING: Unless you absolutely need to use SHA512 for interoperatibility, + * purposes, you might want to consider crypto_generichash() instead. + * Unlike SHA512, crypto_generichash() is not vulnerable to length + * extension attacks. + */ + +#include +#include +#include + +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +typedef struct crypto_hash_sha512_state { + uint64_t state[8]; + uint64_t count[2]; + uint8_t buf[128]; +} crypto_hash_sha512_state; + +SODIUM_EXPORT +size_t crypto_hash_sha512_statebytes(void); + +#define crypto_hash_sha512_BYTES 64U +SODIUM_EXPORT +size_t crypto_hash_sha512_bytes(void); + +SODIUM_EXPORT +int crypto_hash_sha512(unsigned char *out, const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_hash_sha512_init(crypto_hash_sha512_state *state); + +SODIUM_EXPORT +int crypto_hash_sha512_update(crypto_hash_sha512_state *state, + const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_hash_sha512_final(crypto_hash_sha512_state *state, + unsigned char *out); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_kdf.h b/libs/libsodium/src/include/sodium/crypto_kdf.h new file mode 100644 index 0000000000..52e496a744 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_kdf.h @@ -0,0 +1,51 @@ +#ifndef crypto_kdf_H +#define crypto_kdf_H + +#include +#include + +#include "crypto_kdf_blake2b.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_kdf_BYTES_MIN crypto_kdf_blake2b_BYTES_MIN +SODIUM_EXPORT +size_t crypto_kdf_bytes_min(void); + +#define crypto_kdf_BYTES_MAX crypto_kdf_blake2b_BYTES_MAX +SODIUM_EXPORT +size_t crypto_kdf_bytes_max(void); + +#define crypto_kdf_CONTEXTBYTES crypto_kdf_blake2b_CONTEXTBYTES +SODIUM_EXPORT +size_t crypto_kdf_contextbytes(void); + +#define crypto_kdf_KEYBYTES crypto_kdf_blake2b_KEYBYTES +SODIUM_EXPORT +size_t crypto_kdf_keybytes(void); + +#define crypto_kdf_PRIMITIVE "blake2b" +SODIUM_EXPORT +const char *crypto_kdf_primitive(void) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_kdf_derive_from_key(unsigned char *subkey, size_t subkey_len, + uint64_t subkey_id, + const char ctx[crypto_kdf_CONTEXTBYTES], + const unsigned char key[crypto_kdf_KEYBYTES]); + +SODIUM_EXPORT +void crypto_kdf_keygen(unsigned char k[crypto_kdf_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_kdf_blake2b.h b/libs/libsodium/src/include/sodium/crypto_kdf_blake2b.h new file mode 100644 index 0000000000..5480ebe82f --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_kdf_blake2b.h @@ -0,0 +1,42 @@ +#ifndef crypto_kdf_blake2b_H +#define crypto_kdf_blake2b_H + +#include +#include + +#include "crypto_kdf_blake2b.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_kdf_blake2b_BYTES_MIN 16 +SODIUM_EXPORT +size_t crypto_kdf_blake2b_bytes_min(void); + +#define crypto_kdf_blake2b_BYTES_MAX 64 +SODIUM_EXPORT +size_t crypto_kdf_blake2b_bytes_max(void); + +#define crypto_kdf_blake2b_CONTEXTBYTES 8 +SODIUM_EXPORT +size_t crypto_kdf_blake2b_contextbytes(void); + +#define crypto_kdf_blake2b_KEYBYTES 32 +SODIUM_EXPORT +size_t crypto_kdf_blake2b_keybytes(void); + +SODIUM_EXPORT +int crypto_kdf_blake2b_derive_from_key(unsigned char *subkey, size_t subkey_len, + uint64_t subkey_id, + const char ctx[crypto_kdf_blake2b_CONTEXTBYTES], + const unsigned char key[crypto_kdf_blake2b_KEYBYTES]); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_kx.h b/libs/libsodium/src/include/sodium/crypto_kx.h new file mode 100644 index 0000000000..d1fce90da5 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_kx.h @@ -0,0 +1,64 @@ +#ifndef crypto_kx_H +#define crypto_kx_H + +#include + +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_kx_PUBLICKEYBYTES 32 +SODIUM_EXPORT +size_t crypto_kx_publickeybytes(void); + +#define crypto_kx_SECRETKEYBYTES 32 +SODIUM_EXPORT +size_t crypto_kx_secretkeybytes(void); + +#define crypto_kx_SEEDBYTES 32 +SODIUM_EXPORT +size_t crypto_kx_seedbytes(void); + +#define crypto_kx_SESSIONKEYBYTES 32 +SODIUM_EXPORT +size_t crypto_kx_sessionkeybytes(void); + +#define crypto_kx_PRIMITIVE "x25519blake2b" +SODIUM_EXPORT +const char *crypto_kx_primitive(void); + +SODIUM_EXPORT +int crypto_kx_seed_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], + unsigned char sk[crypto_kx_SECRETKEYBYTES], + const unsigned char seed[crypto_kx_SEEDBYTES]); + +SODIUM_EXPORT +int crypto_kx_keypair(unsigned char pk[crypto_kx_PUBLICKEYBYTES], + unsigned char sk[crypto_kx_SECRETKEYBYTES]); + +SODIUM_EXPORT +int crypto_kx_client_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], + unsigned char tx[crypto_kx_SESSIONKEYBYTES], + const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES], + const unsigned char client_sk[crypto_kx_SECRETKEYBYTES], + const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES]) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_kx_server_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES], + unsigned char tx[crypto_kx_SESSIONKEYBYTES], + const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES], + const unsigned char server_sk[crypto_kx_SECRETKEYBYTES], + const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES]) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_onetimeauth.h b/libs/libsodium/src/include/sodium/crypto_onetimeauth.h new file mode 100644 index 0000000000..5951c5b82d --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_onetimeauth.h @@ -0,0 +1,62 @@ +#ifndef crypto_onetimeauth_H +#define crypto_onetimeauth_H + +#include + +#include "crypto_onetimeauth_poly1305.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +typedef crypto_onetimeauth_poly1305_state crypto_onetimeauth_state; + +SODIUM_EXPORT +size_t crypto_onetimeauth_statebytes(void); + +#define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES +SODIUM_EXPORT +size_t crypto_onetimeauth_bytes(void); + +#define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES +SODIUM_EXPORT +size_t crypto_onetimeauth_keybytes(void); + +#define crypto_onetimeauth_PRIMITIVE "poly1305" +SODIUM_EXPORT +const char *crypto_onetimeauth_primitive(void); + +SODIUM_EXPORT +int crypto_onetimeauth(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k); + +SODIUM_EXPORT +int crypto_onetimeauth_verify(const unsigned char *h, const unsigned char *in, + unsigned long long inlen, const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_onetimeauth_init(crypto_onetimeauth_state *state, + const unsigned char *key); + +SODIUM_EXPORT +int crypto_onetimeauth_update(crypto_onetimeauth_state *state, + const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_onetimeauth_final(crypto_onetimeauth_state *state, + unsigned char *out); + +SODIUM_EXPORT +void crypto_onetimeauth_keygen(unsigned char k[crypto_onetimeauth_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_onetimeauth_poly1305.h b/libs/libsodium/src/include/sodium/crypto_onetimeauth_poly1305.h new file mode 100644 index 0000000000..4b89c4f019 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_onetimeauth_poly1305.h @@ -0,0 +1,67 @@ +#ifndef crypto_onetimeauth_poly1305_H +#define crypto_onetimeauth_poly1305_H + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#include +#include +#include + +#include + +#include "export.h" + +typedef struct CRYPTO_ALIGN(16) crypto_onetimeauth_poly1305_state { + unsigned char opaque[256]; +} crypto_onetimeauth_poly1305_state; + +SODIUM_EXPORT +size_t crypto_onetimeauth_poly1305_statebytes(void); + +#define crypto_onetimeauth_poly1305_BYTES 16U +SODIUM_EXPORT +size_t crypto_onetimeauth_poly1305_bytes(void); + +#define crypto_onetimeauth_poly1305_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_onetimeauth_poly1305_keybytes(void); + +SODIUM_EXPORT +int crypto_onetimeauth_poly1305(unsigned char *out, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_onetimeauth_poly1305_verify(const unsigned char *h, + const unsigned char *in, + unsigned long long inlen, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_onetimeauth_poly1305_init(crypto_onetimeauth_poly1305_state *state, + const unsigned char *key); + +SODIUM_EXPORT +int crypto_onetimeauth_poly1305_update(crypto_onetimeauth_poly1305_state *state, + const unsigned char *in, + unsigned long long inlen); + +SODIUM_EXPORT +int crypto_onetimeauth_poly1305_final(crypto_onetimeauth_poly1305_state *state, + unsigned char *out); + +SODIUM_EXPORT +void crypto_onetimeauth_poly1305_keygen(unsigned char k[crypto_onetimeauth_poly1305_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_pwhash.h b/libs/libsodium/src/include/sodium/crypto_pwhash.h new file mode 100644 index 0000000000..2c76461f44 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_pwhash.h @@ -0,0 +1,147 @@ +#ifndef crypto_pwhash_H +#define crypto_pwhash_H + +#include + +#include "crypto_pwhash_argon2i.h" +#include "crypto_pwhash_argon2id.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_pwhash_ALG_ARGON2I13 crypto_pwhash_argon2i_ALG_ARGON2I13 +SODIUM_EXPORT +int crypto_pwhash_alg_argon2i13(void); + +#define crypto_pwhash_ALG_ARGON2ID13 crypto_pwhash_argon2id_ALG_ARGON2ID13 +SODIUM_EXPORT +int crypto_pwhash_alg_argon2id13(void); + +#define crypto_pwhash_ALG_DEFAULT crypto_pwhash_ALG_ARGON2ID13 +SODIUM_EXPORT +int crypto_pwhash_alg_default(void); + +#define crypto_pwhash_BYTES_MIN crypto_pwhash_argon2id_BYTES_MIN +SODIUM_EXPORT +size_t crypto_pwhash_bytes_min(void); + +#define crypto_pwhash_BYTES_MAX crypto_pwhash_argon2id_BYTES_MAX +SODIUM_EXPORT +size_t crypto_pwhash_bytes_max(void); + +#define crypto_pwhash_PASSWD_MIN crypto_pwhash_argon2id_PASSWD_MIN +SODIUM_EXPORT +size_t crypto_pwhash_passwd_min(void); + +#define crypto_pwhash_PASSWD_MAX crypto_pwhash_argon2id_PASSWD_MAX +SODIUM_EXPORT +size_t crypto_pwhash_passwd_max(void); + +#define crypto_pwhash_SALTBYTES crypto_pwhash_argon2id_SALTBYTES +SODIUM_EXPORT +size_t crypto_pwhash_saltbytes(void); + +#define crypto_pwhash_STRBYTES crypto_pwhash_argon2id_STRBYTES +SODIUM_EXPORT +size_t crypto_pwhash_strbytes(void); + +#define crypto_pwhash_STRPREFIX crypto_pwhash_argon2id_STRPREFIX +SODIUM_EXPORT +const char *crypto_pwhash_strprefix(void); + +#define crypto_pwhash_OPSLIMIT_MIN crypto_pwhash_argon2id_OPSLIMIT_MIN +SODIUM_EXPORT +size_t crypto_pwhash_opslimit_min(void); + +#define crypto_pwhash_OPSLIMIT_MAX crypto_pwhash_argon2id_OPSLIMIT_MAX +SODIUM_EXPORT +size_t crypto_pwhash_opslimit_max(void); + +#define crypto_pwhash_MEMLIMIT_MIN crypto_pwhash_argon2id_MEMLIMIT_MIN +SODIUM_EXPORT +size_t crypto_pwhash_memlimit_min(void); + +#define crypto_pwhash_MEMLIMIT_MAX crypto_pwhash_argon2id_MEMLIMIT_MAX +SODIUM_EXPORT +size_t crypto_pwhash_memlimit_max(void); + +#define crypto_pwhash_OPSLIMIT_INTERACTIVE crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE +SODIUM_EXPORT +size_t crypto_pwhash_opslimit_interactive(void); + +#define crypto_pwhash_MEMLIMIT_INTERACTIVE crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE +SODIUM_EXPORT +size_t crypto_pwhash_memlimit_interactive(void); + +#define crypto_pwhash_OPSLIMIT_MODERATE crypto_pwhash_argon2id_OPSLIMIT_MODERATE +SODIUM_EXPORT +size_t crypto_pwhash_opslimit_moderate(void); + +#define crypto_pwhash_MEMLIMIT_MODERATE crypto_pwhash_argon2id_MEMLIMIT_MODERATE +SODIUM_EXPORT +size_t crypto_pwhash_memlimit_moderate(void); + +#define crypto_pwhash_OPSLIMIT_SENSITIVE crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE +SODIUM_EXPORT +size_t crypto_pwhash_opslimit_sensitive(void); + +#define crypto_pwhash_MEMLIMIT_SENSITIVE crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE +SODIUM_EXPORT +size_t crypto_pwhash_memlimit_sensitive(void); + +/* + * With this function, do not forget to store all parameters, including the + * algorithm identifier in order to produce deterministic output. + * The crypto_pwhash_* definitions, including crypto_pwhash_ALG_DEFAULT, + * may change. + */ +SODIUM_EXPORT +int crypto_pwhash(unsigned char * const out, unsigned long long outlen, + const char * const passwd, unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, size_t memlimit, int alg) + __attribute__ ((warn_unused_result)); + +/* + * The output string already includes all the required parameters, including + * the algorithm identifier. The string is all that has to be stored in + * order to verify a password. + */ +SODIUM_EXPORT +int crypto_pwhash_str(char out[crypto_pwhash_STRBYTES], + const char * const passwd, unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_str_alg(char out[crypto_pwhash_STRBYTES], + const char * const passwd, unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit, int alg) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_str_verify(const char str[crypto_pwhash_STRBYTES], + const char * const passwd, + unsigned long long passwdlen) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_str_needs_rehash(const char str[crypto_pwhash_STRBYTES], + unsigned long long opslimit, size_t memlimit) + __attribute__ ((warn_unused_result)); + +#define crypto_pwhash_PRIMITIVE "argon2i" +SODIUM_EXPORT +const char *crypto_pwhash_primitive(void) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_pwhash_argon2i.h b/libs/libsodium/src/include/sodium/crypto_pwhash_argon2i.h new file mode 100644 index 0000000000..8e4c1c3531 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_pwhash_argon2i.h @@ -0,0 +1,122 @@ +#ifndef crypto_pwhash_argon2i_H +#define crypto_pwhash_argon2i_H + +#include +#include +#include + +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_pwhash_argon2i_ALG_ARGON2I13 1 +SODIUM_EXPORT +int crypto_pwhash_argon2i_alg_argon2i13(void); + +#define crypto_pwhash_argon2i_BYTES_MIN 16U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_bytes_min(void); + +#define crypto_pwhash_argon2i_BYTES_MAX SODIUM_MIN(SODIUM_SIZE_MAX, 4294967295U) +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_bytes_max(void); + +#define crypto_pwhash_argon2i_PASSWD_MIN 0U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_passwd_min(void); + +#define crypto_pwhash_argon2i_PASSWD_MAX 4294967295U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_passwd_max(void); + +#define crypto_pwhash_argon2i_SALTBYTES 16U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_saltbytes(void); + +#define crypto_pwhash_argon2i_STRBYTES 128U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_strbytes(void); + +#define crypto_pwhash_argon2i_STRPREFIX "$argon2i$" +SODIUM_EXPORT +const char *crypto_pwhash_argon2i_strprefix(void); + +#define crypto_pwhash_argon2i_OPSLIMIT_MIN 3U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_opslimit_min(void); + +#define crypto_pwhash_argon2i_OPSLIMIT_MAX 4294967295U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_opslimit_max(void); + +#define crypto_pwhash_argon2i_MEMLIMIT_MIN 8192U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_memlimit_min(void); + +#define crypto_pwhash_argon2i_MEMLIMIT_MAX \ + ((SIZE_MAX >= 4398046510080U) ? 4398046510080U : (SIZE_MAX >= 2147483648U) ? 2147483648U : 32768U) +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_memlimit_max(void); + +#define crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE 4U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_opslimit_interactive(void); + +#define crypto_pwhash_argon2i_MEMLIMIT_INTERACTIVE 33554432U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_memlimit_interactive(void); + +#define crypto_pwhash_argon2i_OPSLIMIT_MODERATE 6U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_opslimit_moderate(void); + +#define crypto_pwhash_argon2i_MEMLIMIT_MODERATE 134217728U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_memlimit_moderate(void); + +#define crypto_pwhash_argon2i_OPSLIMIT_SENSITIVE 8U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_opslimit_sensitive(void); + +#define crypto_pwhash_argon2i_MEMLIMIT_SENSITIVE 536870912U +SODIUM_EXPORT +size_t crypto_pwhash_argon2i_memlimit_sensitive(void); + +SODIUM_EXPORT +int crypto_pwhash_argon2i(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, + unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, size_t memlimit, + int alg) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_argon2i_str(char out[crypto_pwhash_argon2i_STRBYTES], + const char * const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_argon2i_str_verify(const char str[crypto_pwhash_argon2i_STRBYTES], + const char * const passwd, + unsigned long long passwdlen) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_argon2i_str_needs_rehash(const char str[crypto_pwhash_argon2i_STRBYTES], + unsigned long long opslimit, size_t memlimit) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_pwhash_argon2id.h b/libs/libsodium/src/include/sodium/crypto_pwhash_argon2id.h new file mode 100644 index 0000000000..51b17aa8e3 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_pwhash_argon2id.h @@ -0,0 +1,122 @@ +#ifndef crypto_pwhash_argon2id_H +#define crypto_pwhash_argon2id_H + +#include +#include +#include + +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_pwhash_argon2id_ALG_ARGON2ID13 2 +SODIUM_EXPORT +int crypto_pwhash_argon2id_alg_argon2id13(void); + +#define crypto_pwhash_argon2id_BYTES_MIN 16U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_bytes_min(void); + +#define crypto_pwhash_argon2id_BYTES_MAX SODIUM_MIN(SODIUM_SIZE_MAX, 4294967295U) +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_bytes_max(void); + +#define crypto_pwhash_argon2id_PASSWD_MIN 0U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_passwd_min(void); + +#define crypto_pwhash_argon2id_PASSWD_MAX 4294967295U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_passwd_max(void); + +#define crypto_pwhash_argon2id_SALTBYTES 16U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_saltbytes(void); + +#define crypto_pwhash_argon2id_STRBYTES 128U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_strbytes(void); + +#define crypto_pwhash_argon2id_STRPREFIX "$argon2id$" +SODIUM_EXPORT +const char *crypto_pwhash_argon2id_strprefix(void); + +#define crypto_pwhash_argon2id_OPSLIMIT_MIN 1U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_opslimit_min(void); + +#define crypto_pwhash_argon2id_OPSLIMIT_MAX 4294967295U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_opslimit_max(void); + +#define crypto_pwhash_argon2id_MEMLIMIT_MIN 8192U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_memlimit_min(void); + +#define crypto_pwhash_argon2id_MEMLIMIT_MAX \ + ((SIZE_MAX >= 4398046510080U) ? 4398046510080U : (SIZE_MAX >= 2147483648U) ? 2147483648U : 32768U) +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_memlimit_max(void); + +#define crypto_pwhash_argon2id_OPSLIMIT_INTERACTIVE 2U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_opslimit_interactive(void); + +#define crypto_pwhash_argon2id_MEMLIMIT_INTERACTIVE 67108864U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_memlimit_interactive(void); + +#define crypto_pwhash_argon2id_OPSLIMIT_MODERATE 3U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_opslimit_moderate(void); + +#define crypto_pwhash_argon2id_MEMLIMIT_MODERATE 268435456U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_memlimit_moderate(void); + +#define crypto_pwhash_argon2id_OPSLIMIT_SENSITIVE 4U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_opslimit_sensitive(void); + +#define crypto_pwhash_argon2id_MEMLIMIT_SENSITIVE 1073741824U +SODIUM_EXPORT +size_t crypto_pwhash_argon2id_memlimit_sensitive(void); + +SODIUM_EXPORT +int crypto_pwhash_argon2id(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, + unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, size_t memlimit, + int alg) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_argon2id_str(char out[crypto_pwhash_argon2id_STRBYTES], + const char * const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, size_t memlimit) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_argon2id_str_verify(const char str[crypto_pwhash_argon2id_STRBYTES], + const char * const passwd, + unsigned long long passwdlen) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_argon2id_str_needs_rehash(const char str[crypto_pwhash_argon2id_STRBYTES], + unsigned long long opslimit, size_t memlimit) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_pwhash_scryptsalsa208sha256.h b/libs/libsodium/src/include/sodium/crypto_pwhash_scryptsalsa208sha256.h new file mode 100644 index 0000000000..951b87b962 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_pwhash_scryptsalsa208sha256.h @@ -0,0 +1,120 @@ +#ifndef crypto_pwhash_scryptsalsa208sha256_H +#define crypto_pwhash_scryptsalsa208sha256_H + +#include +#include +#include + +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_pwhash_scryptsalsa208sha256_BYTES_MIN 16U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_bytes_min(void); + +#define crypto_pwhash_scryptsalsa208sha256_BYTES_MAX \ + SODIUM_MIN(SODIUM_SIZE_MAX, 0x1fffffffe0ULL) +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_bytes_max(void); + +#define crypto_pwhash_scryptsalsa208sha256_PASSWD_MIN 0U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_passwd_min(void); + +#define crypto_pwhash_scryptsalsa208sha256_PASSWD_MAX SODIUM_SIZE_MAX +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_passwd_max(void); + +#define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_saltbytes(void); + +#define crypto_pwhash_scryptsalsa208sha256_STRBYTES 102U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_strbytes(void); + +#define crypto_pwhash_scryptsalsa208sha256_STRPREFIX "$7$" +SODIUM_EXPORT +const char *crypto_pwhash_scryptsalsa208sha256_strprefix(void); + +#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MIN 32768U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_opslimit_min(void); + +#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_MAX 4294967295U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_opslimit_max(void); + +#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MIN 16777216U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_memlimit_min(void); + +#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_MAX \ + SODIUM_MIN(SIZE_MAX, 68719476736ULL) +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_memlimit_max(void); + +#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 524288U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void); + +#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 16777216U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void); + +#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void); + +#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, + unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, + size_t memlimit) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, + size_t memlimit) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_str_needs_rehash(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + unsigned long long opslimit, + size_t memlimit) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_scalarmult.h b/libs/libsodium/src/include/sodium/crypto_scalarmult.h new file mode 100644 index 0000000000..f7fa6f8f39 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_scalarmult.h @@ -0,0 +1,45 @@ +#ifndef crypto_scalarmult_H +#define crypto_scalarmult_H + +#include + +#include "crypto_scalarmult_curve25519.h" +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES +SODIUM_EXPORT +size_t crypto_scalarmult_bytes(void); + +#define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES +SODIUM_EXPORT +size_t crypto_scalarmult_scalarbytes(void); + +#define crypto_scalarmult_PRIMITIVE "curve25519" +SODIUM_EXPORT +const char *crypto_scalarmult_primitive(void); + +SODIUM_EXPORT +int crypto_scalarmult_base(unsigned char *q, const unsigned char *n); + +/* + * NOTE: Do not use the result of this function directly. + * + * Hash the result with the public keys in order to compute a shared + * secret key: H(q || client_pk || server_pk) + * + * Or unless this is not an option, use the crypto_kx() API instead. + */ +SODIUM_EXPORT +int crypto_scalarmult(unsigned char *q, const unsigned char *n, + const unsigned char *p) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_scalarmult_curve25519.h b/libs/libsodium/src/include/sodium/crypto_scalarmult_curve25519.h new file mode 100644 index 0000000000..ae85eadc22 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_scalarmult_curve25519.h @@ -0,0 +1,40 @@ +#ifndef crypto_scalarmult_curve25519_H +#define crypto_scalarmult_curve25519_H + +#include + +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_scalarmult_curve25519_BYTES 32U +SODIUM_EXPORT +size_t crypto_scalarmult_curve25519_bytes(void); + +#define crypto_scalarmult_curve25519_SCALARBYTES 32U +SODIUM_EXPORT +size_t crypto_scalarmult_curve25519_scalarbytes(void); + +/* + * NOTE: Do not use the result of this function directly. + * + * Hash the result with the public keys in order to compute a shared + * secret key: H(q || client_pk || server_pk) + * + * Or unless this is not an option, use the crypto_kx() API instead. + */ +SODIUM_EXPORT +int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n, + const unsigned char *p) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_scalarmult_curve25519_base(unsigned char *q, const unsigned char *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_scalarmult_ed25519.h b/libs/libsodium/src/include/sodium/crypto_scalarmult_ed25519.h new file mode 100644 index 0000000000..3d51235112 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_scalarmult_ed25519.h @@ -0,0 +1,41 @@ + +#ifndef crypto_scalarmult_ed25519_H +#define crypto_scalarmult_ed25519_H + +#include + +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_scalarmult_ed25519_BYTES 32U +SODIUM_EXPORT +size_t crypto_scalarmult_ed25519_bytes(void); + +#define crypto_scalarmult_ed25519_SCALARBYTES 32U +SODIUM_EXPORT +size_t crypto_scalarmult_ed25519_scalarbytes(void); + +/* + * NOTE: Do not use the result of this function directly. + * + * Hash the result with the public keys in order to compute a shared + * secret key: H(q || client_pk || server_pk) + * + * Or unless this is not an option, use the crypto_kx() API instead. + */ +SODIUM_EXPORT +int crypto_scalarmult_ed25519(unsigned char *q, const unsigned char *n, + const unsigned char *p) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_scalarmult_ed25519_base(unsigned char *q, const unsigned char *n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_secretbox.h b/libs/libsodium/src/include/sodium/crypto_secretbox.h new file mode 100644 index 0000000000..55e94a0292 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_secretbox.h @@ -0,0 +1,91 @@ +#ifndef crypto_secretbox_H +#define crypto_secretbox_H + +#include + +#include "crypto_secretbox_xsalsa20poly1305.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES +SODIUM_EXPORT +size_t crypto_secretbox_keybytes(void); + +#define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES +SODIUM_EXPORT +size_t crypto_secretbox_noncebytes(void); + +#define crypto_secretbox_MACBYTES crypto_secretbox_xsalsa20poly1305_MACBYTES +SODIUM_EXPORT +size_t crypto_secretbox_macbytes(void); + +#define crypto_secretbox_PRIMITIVE "xsalsa20poly1305" +SODIUM_EXPORT +const char *crypto_secretbox_primitive(void); + +#define crypto_secretbox_MESSAGEBYTES_MAX crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX +SODIUM_EXPORT +size_t crypto_secretbox_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_secretbox_easy(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_secretbox_open_easy(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_secretbox_detached(unsigned char *c, unsigned char *mac, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_secretbox_open_detached(unsigned char *m, + const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +void crypto_secretbox_keygen(unsigned char k[crypto_secretbox_KEYBYTES]); + +/* -- NaCl compatibility interface ; Requires padding -- */ + +#define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES +SODIUM_EXPORT +size_t crypto_secretbox_zerobytes(void); + +#define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES +SODIUM_EXPORT +size_t crypto_secretbox_boxzerobytes(void); + +SODIUM_EXPORT +int crypto_secretbox(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_secretbox_open(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_secretbox_xchacha20poly1305.h b/libs/libsodium/src/include/sodium/crypto_secretbox_xchacha20poly1305.h new file mode 100644 index 0000000000..2919da161c --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_secretbox_xchacha20poly1305.h @@ -0,0 +1,68 @@ +#ifndef crypto_secretbox_xchacha20poly1305_H +#define crypto_secretbox_xchacha20poly1305_H + +#include +#include "crypto_stream_xchacha20.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_secretbox_xchacha20poly1305_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_secretbox_xchacha20poly1305_keybytes(void); + +#define crypto_secretbox_xchacha20poly1305_NONCEBYTES 24U +SODIUM_EXPORT +size_t crypto_secretbox_xchacha20poly1305_noncebytes(void); + +#define crypto_secretbox_xchacha20poly1305_MACBYTES 16U +SODIUM_EXPORT +size_t crypto_secretbox_xchacha20poly1305_macbytes(void); + +#define crypto_secretbox_xchacha20poly1305_MESSAGEBYTES_MAX \ + (crypto_stream_xchacha20_MESSAGEBYTES_MAX - crypto_secretbox_xchacha20poly1305_MACBYTES) +SODIUM_EXPORT +size_t crypto_secretbox_xchacha20poly1305_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_secretbox_xchacha20poly1305_easy(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_secretbox_xchacha20poly1305_open_easy(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_secretbox_xchacha20poly1305_detached(unsigned char *c, + unsigned char *mac, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_secretbox_xchacha20poly1305_open_detached(unsigned char *m, + const unsigned char *c, + const unsigned char *mac, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_secretbox_xsalsa20poly1305.h b/libs/libsodium/src/include/sodium/crypto_secretbox_xsalsa20poly1305.h new file mode 100644 index 0000000000..4b8c7c8ea2 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_secretbox_xsalsa20poly1305.h @@ -0,0 +1,67 @@ +#ifndef crypto_secretbox_xsalsa20poly1305_H +#define crypto_secretbox_xsalsa20poly1305_H + +#include +#include "crypto_stream_xsalsa20.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_secretbox_xsalsa20poly1305_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_secretbox_xsalsa20poly1305_keybytes(void); + +#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES 24U +SODIUM_EXPORT +size_t crypto_secretbox_xsalsa20poly1305_noncebytes(void); + +#define crypto_secretbox_xsalsa20poly1305_MACBYTES 16U +SODIUM_EXPORT +size_t crypto_secretbox_xsalsa20poly1305_macbytes(void); + +/* Only for the libsodium API - The NaCl compatibility API would require BOXZEROBYTES extra bytes */ +#define crypto_secretbox_xsalsa20poly1305_MESSAGEBYTES_MAX \ + (crypto_stream_xsalsa20_MESSAGEBYTES_MAX - crypto_secretbox_xsalsa20poly1305_MACBYTES) +SODIUM_EXPORT +size_t crypto_secretbox_xsalsa20poly1305_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_secretbox_xsalsa20poly1305(unsigned char *c, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_secretbox_xsalsa20poly1305_open(unsigned char *m, + const unsigned char *c, + unsigned long long clen, + const unsigned char *n, + const unsigned char *k) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +void crypto_secretbox_xsalsa20poly1305_keygen(unsigned char k[crypto_secretbox_xsalsa20poly1305_KEYBYTES]); + +/* -- NaCl compatibility interface ; Requires padding -- */ + +#define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES 16U +SODIUM_EXPORT +size_t crypto_secretbox_xsalsa20poly1305_boxzerobytes(void); + +#define crypto_secretbox_xsalsa20poly1305_ZEROBYTES \ + (crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES + \ + crypto_secretbox_xsalsa20poly1305_MACBYTES) +SODIUM_EXPORT +size_t crypto_secretbox_xsalsa20poly1305_zerobytes(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_secretstream_xchacha20poly1305.h b/libs/libsodium/src/include/sodium/crypto_secretstream_xchacha20poly1305.h new file mode 100644 index 0000000000..7d3fa2a9e3 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_secretstream_xchacha20poly1305.h @@ -0,0 +1,102 @@ +#ifndef crypto_secretstream_xchacha20poly1305_H +#define crypto_secretstream_xchacha20poly1305_H + +#include + +#include "crypto_aead_xchacha20poly1305.h" +#include "crypto_stream_chacha20.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_secretstream_xchacha20poly1305_ABYTES \ + (1U + crypto_aead_xchacha20poly1305_ietf_ABYTES) +SODIUM_EXPORT +size_t crypto_secretstream_xchacha20poly1305_abytes(void); + +#define crypto_secretstream_xchacha20poly1305_HEADERBYTES \ + crypto_aead_xchacha20poly1305_ietf_NPUBBYTES +SODIUM_EXPORT +size_t crypto_secretstream_xchacha20poly1305_headerbytes(void); + +#define crypto_secretstream_xchacha20poly1305_KEYBYTES \ + crypto_aead_xchacha20poly1305_ietf_KEYBYTES +SODIUM_EXPORT +size_t crypto_secretstream_xchacha20poly1305_keybytes(void); + +#define crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX \ + SODIUM_MIN(SODIUM_SIZE_MAX, ((1ULL << 32) - 2ULL) * 64ULL) +SODIUM_EXPORT +size_t crypto_secretstream_xchacha20poly1305_messagebytes_max(void); + +#define crypto_secretstream_xchacha20poly1305_TAG_MESSAGE 0x00 +SODIUM_EXPORT +unsigned char crypto_secretstream_xchacha20poly1305_tag_message(void); + +#define crypto_secretstream_xchacha20poly1305_TAG_PUSH 0x01 +SODIUM_EXPORT +unsigned char crypto_secretstream_xchacha20poly1305_tag_push(void); + +#define crypto_secretstream_xchacha20poly1305_TAG_REKEY 0x02 +SODIUM_EXPORT +unsigned char crypto_secretstream_xchacha20poly1305_tag_rekey(void); + +#define crypto_secretstream_xchacha20poly1305_TAG_FINAL \ + (crypto_secretstream_xchacha20poly1305_TAG_PUSH | \ + crypto_secretstream_xchacha20poly1305_TAG_REKEY) +SODIUM_EXPORT +unsigned char crypto_secretstream_xchacha20poly1305_tag_final(void); + +typedef struct crypto_secretstream_xchacha20poly1305_state { + unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]; + unsigned char nonce[crypto_stream_chacha20_ietf_NONCEBYTES]; + unsigned char _pad[8]; +} crypto_secretstream_xchacha20poly1305_state; + +SODIUM_EXPORT +size_t crypto_secretstream_xchacha20poly1305_statebytes(void); + +SODIUM_EXPORT +void crypto_secretstream_xchacha20poly1305_keygen + (unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_init_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_push + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *c, unsigned long long *clen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, unsigned char tag); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_init_pull + (crypto_secretstream_xchacha20poly1305_state *state, + const unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES], + const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES]); + +SODIUM_EXPORT +int crypto_secretstream_xchacha20poly1305_pull + (crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *m, unsigned long long *mlen_p, unsigned char *tag_p, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen); + +SODIUM_EXPORT +void crypto_secretstream_xchacha20poly1305_rekey + (crypto_secretstream_xchacha20poly1305_state *state); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_shorthash.h b/libs/libsodium/src/include/sodium/crypto_shorthash.h new file mode 100644 index 0000000000..a498808247 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_shorthash.h @@ -0,0 +1,39 @@ +#ifndef crypto_shorthash_H +#define crypto_shorthash_H + +#include + +#include "crypto_shorthash_siphash24.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_shorthash_BYTES crypto_shorthash_siphash24_BYTES +SODIUM_EXPORT +size_t crypto_shorthash_bytes(void); + +#define crypto_shorthash_KEYBYTES crypto_shorthash_siphash24_KEYBYTES +SODIUM_EXPORT +size_t crypto_shorthash_keybytes(void); + +#define crypto_shorthash_PRIMITIVE "siphash24" +SODIUM_EXPORT +const char *crypto_shorthash_primitive(void); + +SODIUM_EXPORT +int crypto_shorthash(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k); + +SODIUM_EXPORT +void crypto_shorthash_keygen(unsigned char k[crypto_shorthash_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_shorthash_siphash24.h b/libs/libsodium/src/include/sodium/crypto_shorthash_siphash24.h new file mode 100644 index 0000000000..745ed48fae --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_shorthash_siphash24.h @@ -0,0 +1,48 @@ +#ifndef crypto_shorthash_siphash24_H +#define crypto_shorthash_siphash24_H + +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +/* -- 64-bit output -- */ + +#define crypto_shorthash_siphash24_BYTES 8U +SODIUM_EXPORT +size_t crypto_shorthash_siphash24_bytes(void); + +#define crypto_shorthash_siphash24_KEYBYTES 16U +SODIUM_EXPORT +size_t crypto_shorthash_siphash24_keybytes(void); + +SODIUM_EXPORT +int crypto_shorthash_siphash24(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k); + +#ifndef SODIUM_LIBRARY_MINIMAL +/* -- 128-bit output -- */ + +#define crypto_shorthash_siphashx24_BYTES 16U +SODIUM_EXPORT +size_t crypto_shorthash_siphashx24_bytes(void); + +#define crypto_shorthash_siphashx24_KEYBYTES 16U +SODIUM_EXPORT +size_t crypto_shorthash_siphashx24_keybytes(void); + +SODIUM_EXPORT +int crypto_shorthash_siphashx24(unsigned char *out, const unsigned char *in, + unsigned long long inlen, const unsigned char *k); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_sign.h b/libs/libsodium/src/include/sodium/crypto_sign.h new file mode 100644 index 0000000000..85aff0c9db --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_sign.h @@ -0,0 +1,103 @@ +#ifndef crypto_sign_H +#define crypto_sign_H + +/* + * THREAD SAFETY: crypto_sign_keypair() is thread-safe, + * provided that sodium_init() was called before. + * + * Other functions, including crypto_sign_seed_keypair() are always thread-safe. + */ + +#include + +#include "crypto_sign_ed25519.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +typedef crypto_sign_ed25519ph_state crypto_sign_state; + +SODIUM_EXPORT +size_t crypto_sign_statebytes(void); + +#define crypto_sign_BYTES crypto_sign_ed25519_BYTES +SODIUM_EXPORT +size_t crypto_sign_bytes(void); + +#define crypto_sign_SEEDBYTES crypto_sign_ed25519_SEEDBYTES +SODIUM_EXPORT +size_t crypto_sign_seedbytes(void); + +#define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES +SODIUM_EXPORT +size_t crypto_sign_publickeybytes(void); + +#define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES +SODIUM_EXPORT +size_t crypto_sign_secretkeybytes(void); + +#define crypto_sign_MESSAGEBYTES_MAX crypto_sign_ed25519_MESSAGEBYTES_MAX +SODIUM_EXPORT +size_t crypto_sign_messagebytes_max(void); + +#define crypto_sign_PRIMITIVE "ed25519" +SODIUM_EXPORT +const char *crypto_sign_primitive(void); + +SODIUM_EXPORT +int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, + const unsigned char *seed); + +SODIUM_EXPORT +int crypto_sign_keypair(unsigned char *pk, unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign(unsigned char *sm, unsigned long long *smlen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign_open(unsigned char *m, unsigned long long *mlen_p, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_sign_detached(unsigned char *sig, unsigned long long *siglen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign_verify_detached(const unsigned char *sig, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_sign_init(crypto_sign_state *state); + +SODIUM_EXPORT +int crypto_sign_update(crypto_sign_state *state, + const unsigned char *m, unsigned long long mlen); + +SODIUM_EXPORT +int crypto_sign_final_create(crypto_sign_state *state, unsigned char *sig, + unsigned long long *siglen_p, + const unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign_final_verify(crypto_sign_state *state, unsigned char *sig, + const unsigned char *pk) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_sign_ed25519.h b/libs/libsodium/src/include/sodium/crypto_sign_ed25519.h new file mode 100644 index 0000000000..38d2b9dd63 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_sign_ed25519.h @@ -0,0 +1,114 @@ +#ifndef crypto_sign_ed25519_H +#define crypto_sign_ed25519_H + +#include +#include "crypto_hash_sha512.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +typedef struct crypto_sign_ed25519ph_state { + crypto_hash_sha512_state hs; +} crypto_sign_ed25519ph_state; + +SODIUM_EXPORT +size_t crypto_sign_ed25519ph_statebytes(void); + +#define crypto_sign_ed25519_BYTES 64U +SODIUM_EXPORT +size_t crypto_sign_ed25519_bytes(void); + +#define crypto_sign_ed25519_SEEDBYTES 32U +SODIUM_EXPORT +size_t crypto_sign_ed25519_seedbytes(void); + +#define crypto_sign_ed25519_PUBLICKEYBYTES 32U +SODIUM_EXPORT +size_t crypto_sign_ed25519_publickeybytes(void); + +#define crypto_sign_ed25519_SECRETKEYBYTES (32U + 32U) +SODIUM_EXPORT +size_t crypto_sign_ed25519_secretkeybytes(void); + +#define crypto_sign_ed25519_MESSAGEBYTES_MAX (SODIUM_SIZE_MAX - crypto_sign_ed25519_BYTES) +SODIUM_EXPORT +size_t crypto_sign_ed25519_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_sign_ed25519(unsigned char *sm, unsigned long long *smlen_p, + const unsigned char *m, unsigned long long mlen, + const unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign_ed25519_open(unsigned char *m, unsigned long long *mlen_p, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_sign_ed25519_detached(unsigned char *sig, + unsigned long long *siglen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign_ed25519_verify_detached(const unsigned char *sig, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *pk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_sign_ed25519_keypair(unsigned char *pk, unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign_ed25519_seed_keypair(unsigned char *pk, unsigned char *sk, + const unsigned char *seed); + +SODIUM_EXPORT +int crypto_sign_ed25519_pk_to_curve25519(unsigned char *curve25519_pk, + const unsigned char *ed25519_pk) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int crypto_sign_ed25519_sk_to_curve25519(unsigned char *curve25519_sk, + const unsigned char *ed25519_sk); + +SODIUM_EXPORT +int crypto_sign_ed25519_sk_to_seed(unsigned char *seed, + const unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign_ed25519_sk_to_pk(unsigned char *pk, const unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign_ed25519ph_init(crypto_sign_ed25519ph_state *state); + +SODIUM_EXPORT +int crypto_sign_ed25519ph_update(crypto_sign_ed25519ph_state *state, + const unsigned char *m, + unsigned long long mlen); + +SODIUM_EXPORT +int crypto_sign_ed25519ph_final_create(crypto_sign_ed25519ph_state *state, + unsigned char *sig, + unsigned long long *siglen_p, + const unsigned char *sk); + +SODIUM_EXPORT +int crypto_sign_ed25519ph_final_verify(crypto_sign_ed25519ph_state *state, + unsigned char *sig, + const unsigned char *pk) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_sign_edwards25519sha512batch.h b/libs/libsodium/src/include/sodium/crypto_sign_edwards25519sha512batch.h new file mode 100644 index 0000000000..4bb9192470 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_sign_edwards25519sha512batch.h @@ -0,0 +1,55 @@ +#ifndef crypto_sign_edwards25519sha512batch_H +#define crypto_sign_edwards25519sha512batch_H + +/* + * WARNING: This construction was a prototype, which should not be used + * any more in new projects. + * + * crypto_sign_edwards25519sha512batch is provided for applications + * initially built with NaCl, but as recommended by the author of this + * construction, new applications should use ed25519 instead. + * + * In Sodium, you should use the high-level crypto_sign_*() functions instead. + */ + +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_sign_edwards25519sha512batch_BYTES 64U +#define crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES 32U +#define crypto_sign_edwards25519sha512batch_SECRETKEYBYTES (32U + 32U) +#define crypto_sign_edwards25519sha512batch_MESSAGEBYTES_MAX (SODIUM_SIZE_MAX - crypto_sign_edwards25519sha512batch_BYTES) + +SODIUM_EXPORT +int crypto_sign_edwards25519sha512batch(unsigned char *sm, + unsigned long long *smlen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *sk) + __attribute__ ((deprecated)); + +SODIUM_EXPORT +int crypto_sign_edwards25519sha512batch_open(unsigned char *m, + unsigned long long *mlen_p, + const unsigned char *sm, + unsigned long long smlen, + const unsigned char *pk) + __attribute__ ((deprecated)); + +SODIUM_EXPORT +int crypto_sign_edwards25519sha512batch_keypair(unsigned char *pk, + unsigned char *sk) + __attribute__ ((deprecated)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_stream.h b/libs/libsodium/src/include/sodium/crypto_stream.h new file mode 100644 index 0000000000..d288f0b6dd --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_stream.h @@ -0,0 +1,56 @@ +#ifndef crypto_stream_H +#define crypto_stream_H + +/* + * WARNING: This is just a stream cipher. It is NOT authenticated encryption. + * While it provides some protection against eavesdropping, it does NOT + * provide any security against active attacks. + * Unless you know what you're doing, what you are looking for is probably + * the crypto_box functions. + */ + +#include + +#include "crypto_stream_xsalsa20.h" +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES +SODIUM_EXPORT +size_t crypto_stream_keybytes(void); + +#define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES +SODIUM_EXPORT +size_t crypto_stream_noncebytes(void); + +#define crypto_stream_MESSAGEBYTES_MAX crypto_stream_xsalsa20_MESSAGEBYTES_MAX +SODIUM_EXPORT +size_t crypto_stream_messagebytes_max(void); + +#define crypto_stream_PRIMITIVE "xsalsa20" +SODIUM_EXPORT +const char *crypto_stream_primitive(void); + +SODIUM_EXPORT +int crypto_stream(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +void crypto_stream_keygen(unsigned char k[crypto_stream_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_stream_chacha20.h b/libs/libsodium/src/include/sodium/crypto_stream_chacha20.h new file mode 100644 index 0000000000..d3e2b234ef --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_stream_chacha20.h @@ -0,0 +1,98 @@ +#ifndef crypto_stream_chacha20_H +#define crypto_stream_chacha20_H + +/* + * WARNING: This is just a stream cipher. It is NOT authenticated encryption. + * While it provides some protection against eavesdropping, it does NOT + * provide any security against active attacks. + * Unless you know what you're doing, what you are looking for is probably + * the crypto_box functions. + */ + +#include +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_stream_chacha20_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_stream_chacha20_keybytes(void); + +#define crypto_stream_chacha20_NONCEBYTES 8U +SODIUM_EXPORT +size_t crypto_stream_chacha20_noncebytes(void); + +#define crypto_stream_chacha20_MESSAGEBYTES_MAX SODIUM_SIZE_MAX +SODIUM_EXPORT +size_t crypto_stream_chacha20_messagebytes_max(void); + +/* ChaCha20 with a 64-bit nonce and a 64-bit counter, as originally designed */ + +SODIUM_EXPORT +int crypto_stream_chacha20(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_chacha20_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_chacha20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k); + +SODIUM_EXPORT +void crypto_stream_chacha20_keygen(unsigned char k[crypto_stream_chacha20_KEYBYTES]); + +/* ChaCha20 with a 96-bit nonce and a 32-bit counter (IETF) */ + +#define crypto_stream_chacha20_ietf_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_stream_chacha20_ietf_keybytes(void); + +#define crypto_stream_chacha20_ietf_NONCEBYTES 12U +SODIUM_EXPORT +size_t crypto_stream_chacha20_ietf_noncebytes(void); + +#define crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX \ + SODIUM_MIN(SODIUM_SIZE_MAX, 64ULL * (1ULL << 32)) +SODIUM_EXPORT +size_t crypto_stream_chacha20_ietf_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_stream_chacha20_ietf(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_chacha20_ietf_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_chacha20_ietf_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint32_t ic, + const unsigned char *k); + +SODIUM_EXPORT +void crypto_stream_chacha20_ietf_keygen(unsigned char k[crypto_stream_chacha20_ietf_KEYBYTES]); + +/* Aliases */ + +#define crypto_stream_chacha20_IETF_KEYBYTES crypto_stream_chacha20_ietf_KEYBYTES +#define crypto_stream_chacha20_IETF_NONCEBYTES crypto_stream_chacha20_ietf_NONCEBYTES +#define crypto_stream_chacha20_IETF_MESSAGEBYTES_MAX crypto_stream_chacha20_ietf_MESSAGEBYTES_MAX + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_stream_salsa20.h b/libs/libsodium/src/include/sodium/crypto_stream_salsa20.h new file mode 100644 index 0000000000..0c7688c736 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_stream_salsa20.h @@ -0,0 +1,57 @@ +#ifndef crypto_stream_salsa20_H +#define crypto_stream_salsa20_H + +/* + * WARNING: This is just a stream cipher. It is NOT authenticated encryption. + * While it provides some protection against eavesdropping, it does NOT + * provide any security against active attacks. + * Unless you know what you're doing, what you are looking for is probably + * the crypto_box functions. + */ + +#include +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_stream_salsa20_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_stream_salsa20_keybytes(void); + +#define crypto_stream_salsa20_NONCEBYTES 8U +SODIUM_EXPORT +size_t crypto_stream_salsa20_noncebytes(void); + +#define crypto_stream_salsa20_MESSAGEBYTES_MAX SODIUM_SIZE_MAX +SODIUM_EXPORT +size_t crypto_stream_salsa20_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_stream_salsa20(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_salsa20_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_salsa20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k); + +SODIUM_EXPORT +void crypto_stream_salsa20_keygen(unsigned char k[crypto_stream_salsa20_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_stream_salsa2012.h b/libs/libsodium/src/include/sodium/crypto_stream_salsa2012.h new file mode 100644 index 0000000000..c93d1c81f8 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_stream_salsa2012.h @@ -0,0 +1,50 @@ +#ifndef crypto_stream_salsa2012_H +#define crypto_stream_salsa2012_H + +/* + * WARNING: This is just a stream cipher. It is NOT authenticated encryption. + * While it provides some protection against eavesdropping, it does NOT + * provide any security against active attacks. + * Unless you know what you're doing, what you are looking for is probably + * the crypto_box functions. + */ + +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_stream_salsa2012_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_stream_salsa2012_keybytes(void); + +#define crypto_stream_salsa2012_NONCEBYTES 8U +SODIUM_EXPORT +size_t crypto_stream_salsa2012_noncebytes(void); + +#define crypto_stream_salsa2012_MESSAGEBYTES_MAX SODIUM_SIZE_MAX +SODIUM_EXPORT +size_t crypto_stream_salsa2012_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_stream_salsa2012(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_salsa2012_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +void crypto_stream_salsa2012_keygen(unsigned char k[crypto_stream_salsa2012_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_stream_salsa208.h b/libs/libsodium/src/include/sodium/crypto_stream_salsa208.h new file mode 100644 index 0000000000..653f6504bd --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_stream_salsa208.h @@ -0,0 +1,56 @@ +#ifndef crypto_stream_salsa208_H +#define crypto_stream_salsa208_H + +/* + * WARNING: This is just a stream cipher. It is NOT authenticated encryption. + * While it provides some protection against eavesdropping, it does NOT + * provide any security against active attacks. + * Unless you know what you're doing, what you are looking for is probably + * the crypto_box functions. + */ + +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_stream_salsa208_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_stream_salsa208_keybytes(void) + __attribute__ ((deprecated)); + +#define crypto_stream_salsa208_NONCEBYTES 8U +SODIUM_EXPORT +size_t crypto_stream_salsa208_noncebytes(void) + __attribute__ ((deprecated)); + +#define crypto_stream_salsa208_MESSAGEBYTES_MAX SODIUM_SIZE_MAX + SODIUM_EXPORT +size_t crypto_stream_salsa208_messagebytes_max(void) + __attribute__ ((deprecated)); + +SODIUM_EXPORT +int crypto_stream_salsa208(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k) + __attribute__ ((deprecated)); + +SODIUM_EXPORT +int crypto_stream_salsa208_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k) + __attribute__ ((deprecated)); + +SODIUM_EXPORT +void crypto_stream_salsa208_keygen(unsigned char k[crypto_stream_salsa208_KEYBYTES]) + __attribute__ ((deprecated)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_stream_xchacha20.h b/libs/libsodium/src/include/sodium/crypto_stream_xchacha20.h new file mode 100644 index 0000000000..cf0407ffa7 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_stream_xchacha20.h @@ -0,0 +1,57 @@ +#ifndef crypto_stream_xchacha20_H +#define crypto_stream_xchacha20_H + +/* + * WARNING: This is just a stream cipher. It is NOT authenticated encryption. + * While it provides some protection against eavesdropping, it does NOT + * provide any security against active attacks. + * Unless you know what you're doing, what you are looking for is probably + * the crypto_box functions. + */ + +#include +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_stream_xchacha20_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_stream_xchacha20_keybytes(void); + +#define crypto_stream_xchacha20_NONCEBYTES 24U +SODIUM_EXPORT +size_t crypto_stream_xchacha20_noncebytes(void); + +#define crypto_stream_xchacha20_MESSAGEBYTES_MAX SODIUM_SIZE_MAX +SODIUM_EXPORT +size_t crypto_stream_xchacha20_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_stream_xchacha20(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_xchacha20_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_xchacha20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k); + +SODIUM_EXPORT +void crypto_stream_xchacha20_keygen(unsigned char k[crypto_stream_xchacha20_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_stream_xsalsa20.h b/libs/libsodium/src/include/sodium/crypto_stream_xsalsa20.h new file mode 100644 index 0000000000..cb4c44a8b8 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_stream_xsalsa20.h @@ -0,0 +1,57 @@ +#ifndef crypto_stream_xsalsa20_H +#define crypto_stream_xsalsa20_H + +/* + * WARNING: This is just a stream cipher. It is NOT authenticated encryption. + * While it provides some protection against eavesdropping, it does NOT + * provide any security against active attacks. + * Unless you know what you're doing, what you are looking for is probably + * the crypto_box functions. + */ + +#include +#include +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_stream_xsalsa20_KEYBYTES 32U +SODIUM_EXPORT +size_t crypto_stream_xsalsa20_keybytes(void); + +#define crypto_stream_xsalsa20_NONCEBYTES 24U +SODIUM_EXPORT +size_t crypto_stream_xsalsa20_noncebytes(void); + +#define crypto_stream_xsalsa20_MESSAGEBYTES_MAX SODIUM_SIZE_MAX +SODIUM_EXPORT +size_t crypto_stream_xsalsa20_messagebytes_max(void); + +SODIUM_EXPORT +int crypto_stream_xsalsa20(unsigned char *c, unsigned long long clen, + const unsigned char *n, const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_xsalsa20_xor(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +SODIUM_EXPORT +int crypto_stream_xsalsa20_xor_ic(unsigned char *c, const unsigned char *m, + unsigned long long mlen, + const unsigned char *n, uint64_t ic, + const unsigned char *k); + +SODIUM_EXPORT +void crypto_stream_xsalsa20_keygen(unsigned char k[crypto_stream_xsalsa20_KEYBYTES]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_verify_16.h b/libs/libsodium/src/include/sodium/crypto_verify_16.h new file mode 100644 index 0000000000..5e9eeabee8 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_verify_16.h @@ -0,0 +1,23 @@ +#ifndef crypto_verify_16_H +#define crypto_verify_16_H + +#include +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_verify_16_BYTES 16U +SODIUM_EXPORT +size_t crypto_verify_16_bytes(void); + +SODIUM_EXPORT +int crypto_verify_16(const unsigned char *x, const unsigned char *y) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_verify_32.h b/libs/libsodium/src/include/sodium/crypto_verify_32.h new file mode 100644 index 0000000000..281b5a1bb7 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_verify_32.h @@ -0,0 +1,23 @@ +#ifndef crypto_verify_32_H +#define crypto_verify_32_H + +#include +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_verify_32_BYTES 32U +SODIUM_EXPORT +size_t crypto_verify_32_bytes(void); + +SODIUM_EXPORT +int crypto_verify_32(const unsigned char *x, const unsigned char *y) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/crypto_verify_64.h b/libs/libsodium/src/include/sodium/crypto_verify_64.h new file mode 100644 index 0000000000..0dc7c304a9 --- /dev/null +++ b/libs/libsodium/src/include/sodium/crypto_verify_64.h @@ -0,0 +1,23 @@ +#ifndef crypto_verify_64_H +#define crypto_verify_64_H + +#include +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define crypto_verify_64_BYTES 64U +SODIUM_EXPORT +size_t crypto_verify_64_bytes(void); + +SODIUM_EXPORT +int crypto_verify_64(const unsigned char *x, const unsigned char *y) + __attribute__ ((warn_unused_result)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/export.h b/libs/libsodium/src/include/sodium/export.h new file mode 100644 index 0000000000..0f624ae3c5 --- /dev/null +++ b/libs/libsodium/src/include/sodium/export.h @@ -0,0 +1,53 @@ + +#ifndef sodium_export_H +#define sodium_export_H + +#ifndef __GNUC__ +# ifdef __attribute__ +# undef __attribute__ +# endif +# define __attribute__(a) +#endif + +#ifdef SODIUM_STATIC +# define SODIUM_EXPORT +# define SODIUM_EXPORT_WEAK +#else +# if defined(_MSC_VER) +# ifdef SODIUM_DLL_EXPORT +# define SODIUM_EXPORT __declspec(dllexport) +# else +# define SODIUM_EXPORT __declspec(dllimport) +# endif +# else +# if defined(__SUNPRO_C) +# ifndef __GNU_C__ +# define SODIUM_EXPORT __attribute__ (visibility(__global)) +# else +# define SODIUM_EXPORT __attribute__ __global +# endif +# elif defined(_MSG_VER) +# define SODIUM_EXPORT extern __declspec(dllexport) +# else +# define SODIUM_EXPORT __attribute__ ((visibility ("default"))) +# endif +# endif +# if defined(__ELF__) && !defined(SODIUM_DISABLE_WEAK_FUNCTIONS) +# define SODIUM_EXPORT_WEAK SODIUM_EXPORT __attribute__((weak)) +# else +# define SODIUM_EXPORT_WEAK SODIUM_EXPORT +# endif +#endif + +#ifndef CRYPTO_ALIGN +# if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# define CRYPTO_ALIGN(x) __declspec(align(x)) +# else +# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) +# endif +#endif + +#define SODIUM_MIN(A, B) ((A) < (B) ? (A) : (B)) +#define SODIUM_SIZE_MAX SODIUM_MIN(UINT64_MAX, SIZE_MAX) + +#endif diff --git a/libs/libsodium/src/include/sodium/private/common.h b/libs/libsodium/src/include/sodium/private/common.h new file mode 100644 index 0000000000..954d02ccd7 --- /dev/null +++ b/libs/libsodium/src/include/sodium/private/common.h @@ -0,0 +1,246 @@ +#ifndef common_H +#define common_H 1 + +#include +#include +#include + +#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) + +#ifdef HAVE_TI_MODE +# if defined(__SIZEOF_INT128__) +typedef unsigned __int128 uint128_t; +# else +typedef unsigned uint128_t __attribute__((mode(TI))); +# endif +#endif + +#define ROTL32(X, B) rotl32((X), (B)) +static inline uint32_t +rotl32(const uint32_t x, const int b) +{ + return (x << b) | (x >> (32 - b)); +} + +#define ROTL64(X, B) rotl64((X), (B)) +static inline uint64_t +rotl64(const uint64_t x, const int b) +{ + return (x << b) | (x >> (64 - b)); +} + +#define ROTR32(X, B) rotr32((X), (B)) +static inline uint32_t +rotr32(const uint32_t x, const int b) +{ + return (x >> b) | (x << (32 - b)); +} + +#define ROTR64(X, B) rotr64((X), (B)) +static inline uint64_t +rotr64(const uint64_t x, const int b) +{ + return (x >> b) | (x << (64 - b)); +} + +#define LOAD64_LE(SRC) load64_le(SRC) +static inline uint64_t +load64_le(const uint8_t src[8]) +{ +#ifdef NATIVE_LITTLE_ENDIAN + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + uint64_t w = (uint64_t) src[0]; + w |= (uint64_t) src[1] << 8; + w |= (uint64_t) src[2] << 16; + w |= (uint64_t) src[3] << 24; + w |= (uint64_t) src[4] << 32; + w |= (uint64_t) src[5] << 40; + w |= (uint64_t) src[6] << 48; + w |= (uint64_t) src[7] << 56; + return w; +#endif +} + +#define STORE64_LE(DST, W) store64_le((DST), (W)) +static inline void +store64_le(uint8_t dst[8], uint64_t w) +{ +#ifdef NATIVE_LITTLE_ENDIAN + memcpy(dst, &w, sizeof w); +#else + dst[0] = (uint8_t) w; w >>= 8; + dst[1] = (uint8_t) w; w >>= 8; + dst[2] = (uint8_t) w; w >>= 8; + dst[3] = (uint8_t) w; w >>= 8; + dst[4] = (uint8_t) w; w >>= 8; + dst[5] = (uint8_t) w; w >>= 8; + dst[6] = (uint8_t) w; w >>= 8; + dst[7] = (uint8_t) w; +#endif +} + +#define LOAD32_LE(SRC) load32_le(SRC) +static inline uint32_t +load32_le(const uint8_t src[4]) +{ +#ifdef NATIVE_LITTLE_ENDIAN + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + uint32_t w = (uint32_t) src[0]; + w |= (uint32_t) src[1] << 8; + w |= (uint32_t) src[2] << 16; + w |= (uint32_t) src[3] << 24; + return w; +#endif +} + +#define STORE32_LE(DST, W) store32_le((DST), (W)) +static inline void +store32_le(uint8_t dst[4], uint32_t w) +{ +#ifdef NATIVE_LITTLE_ENDIAN + memcpy(dst, &w, sizeof w); +#else + dst[0] = (uint8_t) w; w >>= 8; + dst[1] = (uint8_t) w; w >>= 8; + dst[2] = (uint8_t) w; w >>= 8; + dst[3] = (uint8_t) w; +#endif +} + +/* ----- */ + +#define LOAD64_BE(SRC) load64_be(SRC) +static inline uint64_t +load64_be(const uint8_t src[8]) +{ +#ifdef NATIVE_BIG_ENDIAN + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + uint64_t w = (uint64_t) src[7]; + w |= (uint64_t) src[6] << 8; + w |= (uint64_t) src[5] << 16; + w |= (uint64_t) src[4] << 24; + w |= (uint64_t) src[3] << 32; + w |= (uint64_t) src[2] << 40; + w |= (uint64_t) src[1] << 48; + w |= (uint64_t) src[0] << 56; + return w; +#endif +} + +#define STORE64_BE(DST, W) store64_be((DST), (W)) +static inline void +store64_be(uint8_t dst[8], uint64_t w) +{ +#ifdef NATIVE_BIG_ENDIAN + memcpy(dst, &w, sizeof w); +#else + dst[7] = (uint8_t) w; w >>= 8; + dst[6] = (uint8_t) w; w >>= 8; + dst[5] = (uint8_t) w; w >>= 8; + dst[4] = (uint8_t) w; w >>= 8; + dst[3] = (uint8_t) w; w >>= 8; + dst[2] = (uint8_t) w; w >>= 8; + dst[1] = (uint8_t) w; w >>= 8; + dst[0] = (uint8_t) w; +#endif +} + +#define LOAD32_BE(SRC) load32_be(SRC) +static inline uint32_t +load32_be(const uint8_t src[4]) +{ +#ifdef NATIVE_BIG_ENDIAN + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + uint32_t w = (uint32_t) src[3]; + w |= (uint32_t) src[2] << 8; + w |= (uint32_t) src[1] << 16; + w |= (uint32_t) src[0] << 24; + return w; +#endif +} + +#define STORE32_BE(DST, W) store32_be((DST), (W)) +static inline void +store32_be(uint8_t dst[4], uint32_t w) +{ +#ifdef NATIVE_BIG_ENDIAN + memcpy(dst, &w, sizeof w); +#else + dst[3] = (uint8_t) w; w >>= 8; + dst[2] = (uint8_t) w; w >>= 8; + dst[1] = (uint8_t) w; w >>= 8; + dst[0] = (uint8_t) w; +#endif +} + +#define XOR_BUF(OUT, IN, N) xor_buf((OUT), (IN), (N)) +static inline void +xor_buf(unsigned char *out, const unsigned char *in, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) { + out[i] ^= in[i]; + } +} + +#ifndef __GNUC__ +# ifdef __attribute__ +# undef __attribute__ +# endif +# define __attribute__(a) +#endif + +#ifndef CRYPTO_ALIGN +# if defined(__INTEL_COMPILER) || defined(_MSC_VER) +# define CRYPTO_ALIGN(x) __declspec(align(x)) +# else +# define CRYPTO_ALIGN(x) __attribute__ ((aligned(x))) +# endif +#endif + +#if defined(_MSC_VER) && \ + (defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86)) + +# include + +# define HAVE_INTRIN_H 1 +# define HAVE_MMINTRIN_H 1 +# define HAVE_EMMINTRIN_H 1 +# define HAVE_PMMINTRIN_H 1 +# define HAVE_TMMINTRIN_H 1 +# define HAVE_SMMINTRIN_H 1 +# define HAVE_AVXINTRIN_H 1 +# if _MSC_VER >= 1600 +# define HAVE_WMMINTRIN_H 1 +# endif +# if _MSC_VER >= 1700 && defined(_M_X64) +# define HAVE_AVX2INTRIN_H 1 +# endif +#elif defined(HAVE_INTRIN_H) +# include +#endif + +#ifdef HAVE_LIBCTGRIND +extern void ct_poison (const void *, size_t); +extern void ct_unpoison(const void *, size_t); +# define POISON(X, L) ct_poison((X), (L)) +# define UNPOISON(X, L) ct_unpoison((X), (L)) +#else +# define POISON(X, L) (void) 0 +# define UNPOISON(X, L) (void) 0 +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/private/ed25519_ref10.h b/libs/libsodium/src/include/sodium/private/ed25519_ref10.h new file mode 100644 index 0000000000..42fcd98139 --- /dev/null +++ b/libs/libsodium/src/include/sodium/private/ed25519_ref10.h @@ -0,0 +1,125 @@ +#ifndef ed25519_ref10_H +#define ed25519_ref10_H + +#include +#include + +/* + fe means field element. + Here the field is \Z/(2^255-19). + */ + +#ifdef HAVE_TI_MODE +typedef uint64_t fe25519[5]; +#else +typedef int32_t fe25519[10]; +#endif + +void fe25519_invert(fe25519 out, const fe25519 z); +void fe25519_frombytes(fe25519 h, const unsigned char *s); +void fe25519_tobytes(unsigned char *s, const fe25519 h); + +#ifdef HAVE_TI_MODE +# include "ed25519_ref10_fe_51.h" +#else +# include "ed25519_ref10_fe_25_5.h" +#endif + + +/* + ge means group element. + + Here the group is the set of pairs (x,y) of field elements + satisfying -x^2 + y^2 = 1 + d x^2y^2 + where d = -121665/121666. + + Representations: + ge25519_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z + ge25519_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT + ge25519_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T + ge25519_precomp (Duif): (y+x,y-x,2dxy) + */ + +typedef struct { + fe25519 X; + fe25519 Y; + fe25519 Z; +} ge25519_p2; + +typedef struct { + fe25519 X; + fe25519 Y; + fe25519 Z; + fe25519 T; +} ge25519_p3; + +typedef struct { + fe25519 X; + fe25519 Y; + fe25519 Z; + fe25519 T; +} ge25519_p1p1; + +typedef struct { + fe25519 yplusx; + fe25519 yminusx; + fe25519 xy2d; +} ge25519_precomp; + +typedef struct { + fe25519 YplusX; + fe25519 YminusX; + fe25519 Z; + fe25519 T2d; +} ge25519_cached; + +void ge25519_tobytes(unsigned char *s, const ge25519_p2 *h); + +void ge25519_p3_tobytes(unsigned char *s, const ge25519_p3 *h); + +int ge25519_frombytes(ge25519_p3 *h, const unsigned char *s); + +int ge25519_frombytes_negate_vartime(ge25519_p3 *h, const unsigned char *s); + +void ge25519_p3_to_cached(ge25519_cached *r, const ge25519_p3 *p); + +void ge25519_p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p); + +void ge25519_p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p); + +void ge25519_add(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_cached *q); + +void ge25519_sub(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_cached *q); + +void ge25519_scalarmult_base(ge25519_p3 *h, const unsigned char *a); + +void ge25519_double_scalarmult_vartime(ge25519_p2 *r, const unsigned char *a, + const ge25519_p3 *A, + const unsigned char *b); + +void ge25519_scalarmult(ge25519_p3 *h, const unsigned char *a, + const ge25519_p3 *p); + +int ge25519_is_canonical(const unsigned char *s); + +int ge25519_is_on_curve(const ge25519_p3 *p); + +int ge25519_is_on_main_subgroup(const ge25519_p3 *p); + +int ge25519_has_small_order(const unsigned char s[32]); + +void ge25519_from_uniform(unsigned char s[32], const unsigned char r[32]); + +/* + The set of scalars is \Z/l + where l = 2^252 + 27742317777372353535851937790883648493. + */ + +void sc25519_reduce(unsigned char *s); + +void sc25519_muladd(unsigned char *s, const unsigned char *a, + const unsigned char *b, const unsigned char *c); + +int sc25519_is_canonical(const unsigned char *s); + +#endif diff --git a/libs/libsodium/src/include/sodium/private/ed25519_ref10_fe_25_5.h b/libs/libsodium/src/include/sodium/private/ed25519_ref10_fe_25_5.h new file mode 100644 index 0000000000..5a0b6148b7 --- /dev/null +++ b/libs/libsodium/src/include/sodium/private/ed25519_ref10_fe_25_5.h @@ -0,0 +1,1050 @@ +#include + +#include "private/common.h" +#include "utils.h" + +/* + h = 0 + */ + +static inline void +fe25519_0(fe25519 h) +{ + memset(&h[0], 0, 10 * sizeof h[0]); +} + +/* + h = 1 + */ + +static inline void +fe25519_1(fe25519 h) +{ + h[0] = 1; + h[1] = 0; + memset(&h[2], 0, 8 * sizeof h[0]); +} + +/* + h = f + g + Can overlap h with f or g. + * + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + +static inline void +fe25519_add(fe25519 h, const fe25519 f, const fe25519 g) +{ + int32_t h0 = f[0] + g[0]; + int32_t h1 = f[1] + g[1]; + int32_t h2 = f[2] + g[2]; + int32_t h3 = f[3] + g[3]; + int32_t h4 = f[4] + g[4]; + int32_t h5 = f[5] + g[5]; + int32_t h6 = f[6] + g[6]; + int32_t h7 = f[7] + g[7]; + int32_t h8 = f[8] + g[8]; + int32_t h9 = f[9] + g[9]; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* + h = f - g + Can overlap h with f or g. + * + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + +static void +fe25519_sub(fe25519 h, const fe25519 f, const fe25519 g) +{ + int32_t h0 = f[0] - g[0]; + int32_t h1 = f[1] - g[1]; + int32_t h2 = f[2] - g[2]; + int32_t h3 = f[3] - g[3]; + int32_t h4 = f[4] - g[4]; + int32_t h5 = f[5] - g[5]; + int32_t h6 = f[6] - g[6]; + int32_t h7 = f[7] - g[7]; + int32_t h8 = f[8] - g[8]; + int32_t h9 = f[9] - g[9]; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* + h = -f + * + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * + Postconditions: + |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + */ + +static inline void +fe25519_neg(fe25519 h, const fe25519 f) +{ + int32_t h0 = -f[0]; + int32_t h1 = -f[1]; + int32_t h2 = -f[2]; + int32_t h3 = -f[3]; + int32_t h4 = -f[4]; + int32_t h5 = -f[5]; + int32_t h6 = -f[6]; + int32_t h7 = -f[7]; + int32_t h8 = -f[8]; + int32_t h9 = -f[9]; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* + Replace (f,g) with (g,g) if b == 1; + replace (f,g) with (f,g) if b == 0. + * + Preconditions: b in {0,1}. + */ + +static void +fe25519_cmov(fe25519 f, const fe25519 g, unsigned int b) +{ + const uint32_t mask = (uint32_t) (-(int32_t) b); + + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t x0 = f0 ^ g[0]; + int32_t x1 = f1 ^ g[1]; + int32_t x2 = f2 ^ g[2]; + int32_t x3 = f3 ^ g[3]; + int32_t x4 = f4 ^ g[4]; + int32_t x5 = f5 ^ g[5]; + int32_t x6 = f6 ^ g[6]; + int32_t x7 = f7 ^ g[7]; + int32_t x8 = f8 ^ g[8]; + int32_t x9 = f9 ^ g[9]; + + x0 &= mask; + x1 &= mask; + x2 &= mask; + x3 &= mask; + x4 &= mask; + x5 &= mask; + x6 &= mask; + x7 &= mask; + x8 &= mask; + x9 &= mask; + + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + f[5] = f5 ^ x5; + f[6] = f6 ^ x6; + f[7] = f7 ^ x7; + f[8] = f8 ^ x8; + f[9] = f9 ^ x9; +} + +static void +fe25519_cswap(fe25519 f, fe25519 g, unsigned int b) +{ + const uint32_t mask = (uint32_t) (-(int64_t) b); + + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + + int32_t x0 = f0 ^ g0; + int32_t x1 = f1 ^ g1; + int32_t x2 = f2 ^ g2; + int32_t x3 = f3 ^ g3; + int32_t x4 = f4 ^ g4; + int32_t x5 = f5 ^ g5; + int32_t x6 = f6 ^ g6; + int32_t x7 = f7 ^ g7; + int32_t x8 = f8 ^ g8; + int32_t x9 = f9 ^ g9; + + x0 &= mask; + x1 &= mask; + x2 &= mask; + x3 &= mask; + x4 &= mask; + x5 &= mask; + x6 &= mask; + x7 &= mask; + x8 &= mask; + x9 &= mask; + + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + f[5] = f5 ^ x5; + f[6] = f6 ^ x6; + f[7] = f7 ^ x7; + f[8] = f8 ^ x8; + f[9] = f9 ^ x9; + + g[0] = g0 ^ x0; + g[1] = g1 ^ x1; + g[2] = g2 ^ x2; + g[3] = g3 ^ x3; + g[4] = g4 ^ x4; + g[5] = g5 ^ x5; + g[6] = g6 ^ x6; + g[7] = g7 ^ x7; + g[8] = g8 ^ x8; + g[9] = g9 ^ x9; +} + +/* + h = f + */ + +static inline void +fe25519_copy(fe25519 h, const fe25519 f) +{ + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + h[0] = f0; + h[1] = f1; + h[2] = f2; + h[3] = f3; + h[4] = f4; + h[5] = f5; + h[6] = f6; + h[7] = f7; + h[8] = f8; + h[9] = f9; +} + +/* + return 1 if f is in {1,3,5,...,q-2} + return 0 if f is in {0,2,4,...,q-1} + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + +static inline int +fe25519_isnegative(const fe25519 f) +{ + unsigned char s[32]; + + fe25519_tobytes(s, f); + + return s[0] & 1; +} + +/* + return 1 if f == 0 + return 0 if f != 0 + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + +static inline int +fe25519_iszero(const fe25519 f) +{ + unsigned char s[32]; + + fe25519_tobytes(s, f); + + return sodium_is_zero(s, 32); +} + +/* + h = f * g + Can overlap h with f or g. + * + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + * + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + +/* + Notes on implementation strategy: + * + Using schoolbook multiplication. + Karatsuba would save a little in some cost models. + * + Most multiplications by 2 and 19 are 32-bit precomputations; + cheaper than 64-bit postcomputations. + * + There is one remaining multiplication by 19 in the carry chain; + one *19 precomputation can be merged into this, + but the resulting data flow is considerably less clean. + * + There are 12 carries below. + 10 of them are 2-way parallelizable and vectorizable. + Can get away with 11 carries, but then data flow is much deeper. + * + With tighter constraints on inputs can squeeze carries into int32. + */ + +static void +fe25519_mul(fe25519 h, const fe25519 f, const fe25519 g) +{ + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + + int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */ + int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + int32_t g3_19 = 19 * g3; + int32_t g4_19 = 19 * g4; + int32_t g5_19 = 19 * g5; + int32_t g6_19 = 19 * g6; + int32_t g7_19 = 19 * g7; + int32_t g8_19 = 19 * g8; + int32_t g9_19 = 19 * g9; + int32_t f1_2 = 2 * f1; + int32_t f3_2 = 2 * f3; + int32_t f5_2 = 2 * f5; + int32_t f7_2 = 2 * f7; + int32_t f9_2 = 2 * f9; + + int64_t f0g0 = f0 * (int64_t) g0; + int64_t f0g1 = f0 * (int64_t) g1; + int64_t f0g2 = f0 * (int64_t) g2; + int64_t f0g3 = f0 * (int64_t) g3; + int64_t f0g4 = f0 * (int64_t) g4; + int64_t f0g5 = f0 * (int64_t) g5; + int64_t f0g6 = f0 * (int64_t) g6; + int64_t f0g7 = f0 * (int64_t) g7; + int64_t f0g8 = f0 * (int64_t) g8; + int64_t f0g9 = f0 * (int64_t) g9; + int64_t f1g0 = f1 * (int64_t) g0; + int64_t f1g1_2 = f1_2 * (int64_t) g1; + int64_t f1g2 = f1 * (int64_t) g2; + int64_t f1g3_2 = f1_2 * (int64_t) g3; + int64_t f1g4 = f1 * (int64_t) g4; + int64_t f1g5_2 = f1_2 * (int64_t) g5; + int64_t f1g6 = f1 * (int64_t) g6; + int64_t f1g7_2 = f1_2 * (int64_t) g7; + int64_t f1g8 = f1 * (int64_t) g8; + int64_t f1g9_38 = f1_2 * (int64_t) g9_19; + int64_t f2g0 = f2 * (int64_t) g0; + int64_t f2g1 = f2 * (int64_t) g1; + int64_t f2g2 = f2 * (int64_t) g2; + int64_t f2g3 = f2 * (int64_t) g3; + int64_t f2g4 = f2 * (int64_t) g4; + int64_t f2g5 = f2 * (int64_t) g5; + int64_t f2g6 = f2 * (int64_t) g6; + int64_t f2g7 = f2 * (int64_t) g7; + int64_t f2g8_19 = f2 * (int64_t) g8_19; + int64_t f2g9_19 = f2 * (int64_t) g9_19; + int64_t f3g0 = f3 * (int64_t) g0; + int64_t f3g1_2 = f3_2 * (int64_t) g1; + int64_t f3g2 = f3 * (int64_t) g2; + int64_t f3g3_2 = f3_2 * (int64_t) g3; + int64_t f3g4 = f3 * (int64_t) g4; + int64_t f3g5_2 = f3_2 * (int64_t) g5; + int64_t f3g6 = f3 * (int64_t) g6; + int64_t f3g7_38 = f3_2 * (int64_t) g7_19; + int64_t f3g8_19 = f3 * (int64_t) g8_19; + int64_t f3g9_38 = f3_2 * (int64_t) g9_19; + int64_t f4g0 = f4 * (int64_t) g0; + int64_t f4g1 = f4 * (int64_t) g1; + int64_t f4g2 = f4 * (int64_t) g2; + int64_t f4g3 = f4 * (int64_t) g3; + int64_t f4g4 = f4 * (int64_t) g4; + int64_t f4g5 = f4 * (int64_t) g5; + int64_t f4g6_19 = f4 * (int64_t) g6_19; + int64_t f4g7_19 = f4 * (int64_t) g7_19; + int64_t f4g8_19 = f4 * (int64_t) g8_19; + int64_t f4g9_19 = f4 * (int64_t) g9_19; + int64_t f5g0 = f5 * (int64_t) g0; + int64_t f5g1_2 = f5_2 * (int64_t) g1; + int64_t f5g2 = f5 * (int64_t) g2; + int64_t f5g3_2 = f5_2 * (int64_t) g3; + int64_t f5g4 = f5 * (int64_t) g4; + int64_t f5g5_38 = f5_2 * (int64_t) g5_19; + int64_t f5g6_19 = f5 * (int64_t) g6_19; + int64_t f5g7_38 = f5_2 * (int64_t) g7_19; + int64_t f5g8_19 = f5 * (int64_t) g8_19; + int64_t f5g9_38 = f5_2 * (int64_t) g9_19; + int64_t f6g0 = f6 * (int64_t) g0; + int64_t f6g1 = f6 * (int64_t) g1; + int64_t f6g2 = f6 * (int64_t) g2; + int64_t f6g3 = f6 * (int64_t) g3; + int64_t f6g4_19 = f6 * (int64_t) g4_19; + int64_t f6g5_19 = f6 * (int64_t) g5_19; + int64_t f6g6_19 = f6 * (int64_t) g6_19; + int64_t f6g7_19 = f6 * (int64_t) g7_19; + int64_t f6g8_19 = f6 * (int64_t) g8_19; + int64_t f6g9_19 = f6 * (int64_t) g9_19; + int64_t f7g0 = f7 * (int64_t) g0; + int64_t f7g1_2 = f7_2 * (int64_t) g1; + int64_t f7g2 = f7 * (int64_t) g2; + int64_t f7g3_38 = f7_2 * (int64_t) g3_19; + int64_t f7g4_19 = f7 * (int64_t) g4_19; + int64_t f7g5_38 = f7_2 * (int64_t) g5_19; + int64_t f7g6_19 = f7 * (int64_t) g6_19; + int64_t f7g7_38 = f7_2 * (int64_t) g7_19; + int64_t f7g8_19 = f7 * (int64_t) g8_19; + int64_t f7g9_38 = f7_2 * (int64_t) g9_19; + int64_t f8g0 = f8 * (int64_t) g0; + int64_t f8g1 = f8 * (int64_t) g1; + int64_t f8g2_19 = f8 * (int64_t) g2_19; + int64_t f8g3_19 = f8 * (int64_t) g3_19; + int64_t f8g4_19 = f8 * (int64_t) g4_19; + int64_t f8g5_19 = f8 * (int64_t) g5_19; + int64_t f8g6_19 = f8 * (int64_t) g6_19; + int64_t f8g7_19 = f8 * (int64_t) g7_19; + int64_t f8g8_19 = f8 * (int64_t) g8_19; + int64_t f8g9_19 = f8 * (int64_t) g9_19; + int64_t f9g0 = f9 * (int64_t) g0; + int64_t f9g1_38 = f9_2 * (int64_t) g1_19; + int64_t f9g2_19 = f9 * (int64_t) g2_19; + int64_t f9g3_38 = f9_2 * (int64_t) g3_19; + int64_t f9g4_19 = f9 * (int64_t) g4_19; + int64_t f9g5_38 = f9_2 * (int64_t) g5_19; + int64_t f9g6_19 = f9 * (int64_t) g6_19; + int64_t f9g7_38 = f9_2 * (int64_t) g7_19; + int64_t f9g8_19 = f9 * (int64_t) g8_19; + int64_t f9g9_38 = f9_2 * (int64_t) g9_19; + + int64_t h0 = f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38; + int64_t h1 = f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + + f7g4_19 + f8g3_19 + f9g2_19; + int64_t h2 = f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + + f7g5_38 + f8g4_19 + f9g3_38; + int64_t h3 = f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + + f7g6_19 + f8g5_19 + f9g4_19; + int64_t h4 = f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + + f7g7_38 + f8g6_19 + f9g5_38; + int64_t h5 = f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + + f8g7_19 + f9g6_19; + int64_t h6 = f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + + f7g9_38 + f8g8_19 + f9g7_38; + int64_t h7 = f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + + f8g9_19 + f9g8_19; + int64_t h8 = f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + + f8g0 + f9g9_38; + int64_t h9 = + f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + /* + |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + (int64_t)(1L << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((uint64_t) 1L << 25); + carry5 = (h5 + (int64_t)(1L << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((uint64_t) 1L << 25); + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + (int64_t)(1L << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((uint64_t) 1L << 26); + carry6 = (h6 + (int64_t)(1L << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((uint64_t) 1L << 26); + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + (int64_t)(1L << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((uint64_t) 1L << 25); + carry7 = (h7 + (int64_t)(1L << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((uint64_t) 1L << 25); + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + carry8 = (h8 + (int64_t)(1L << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((uint64_t) 1L << 26); + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + (int64_t)(1L << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((uint64_t) 1L << 25); + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + +/* + h = f * f + Can overlap h with f. + * + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + * + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + +static void +fe25519_sq(fe25519 h, const fe25519 f) +{ + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + + int64_t h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + int64_t h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + int64_t h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + int64_t h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + int64_t h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + int64_t h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + int64_t h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + int64_t h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + int64_t h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + int64_t h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + + carry1 = (h1 + (int64_t)(1L << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((uint64_t) 1L << 25); + carry5 = (h5 + (int64_t)(1L << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((uint64_t) 1L << 25); + + carry2 = (h2 + (int64_t)(1L << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((uint64_t) 1L << 26); + carry6 = (h6 + (int64_t)(1L << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((uint64_t) 1L << 26); + + carry3 = (h3 + (int64_t)(1L << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((uint64_t) 1L << 25); + carry7 = (h7 + (int64_t)(1L << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((uint64_t) 1L << 25); + + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + carry8 = (h8 + (int64_t)(1L << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((uint64_t) 1L << 26); + + carry9 = (h9 + (int64_t)(1L << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((uint64_t) 1L << 25); + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + +/* + h = 2 * f * f + Can overlap h with f. + * + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + * + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + +static void +fe25519_sq2(fe25519 h, const fe25519 f) +{ + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + + int64_t h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + int64_t h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + int64_t h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + int64_t h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + int64_t h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + int64_t h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + int64_t h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + int64_t h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + int64_t h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + int64_t h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + + carry1 = (h1 + (int64_t)(1L << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((uint64_t) 1L << 25); + carry5 = (h5 + (int64_t)(1L << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((uint64_t) 1L << 25); + + carry2 = (h2 + (int64_t)(1L << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((uint64_t) 1L << 26); + carry6 = (h6 + (int64_t)(1L << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((uint64_t) 1L << 26); + + carry3 = (h3 + (int64_t)(1L << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((uint64_t) 1L << 25); + carry7 = (h7 + (int64_t)(1L << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((uint64_t) 1L << 25); + + carry4 = (h4 + (int64_t)(1L << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((uint64_t) 1L << 26); + carry8 = (h8 + (int64_t)(1L << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((uint64_t) 1L << 26); + + carry9 = (h9 + (int64_t)(1L << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((uint64_t) 1L << 25); + + carry0 = (h0 + (int64_t)(1L << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((uint64_t) 1L << 26); + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + +static void +fe25519_scalar_product(fe25519 h, const fe25519 f, uint32_t n) +{ + int64_t sn = (int64_t) n; + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int64_t h0 = f0 * sn; + int64_t h1 = f1 * sn; + int64_t h2 = f2 * sn; + int64_t h3 = f3 * sn; + int64_t h4 = f4 * sn; + int64_t h5 = f5 * sn; + int64_t h6 = f6 * sn; + int64_t h7 = f7 * sn; + int64_t h8 = f8 * sn; + int64_t h9 = f9 * sn; + int64_t carry0, carry1, carry2, carry3, carry4, carry5, carry6, carry7, + carry8, carry9; + + carry9 = (h9 + ((int64_t) 1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 * ((int64_t) 1 << 25); + carry1 = (h1 + ((int64_t) 1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 * ((int64_t) 1 << 25); + carry3 = (h3 + ((int64_t) 1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 * ((int64_t) 1 << 25); + carry5 = (h5 + ((int64_t) 1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 * ((int64_t) 1 << 25); + carry7 = (h7 + ((int64_t) 1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 * ((int64_t) 1 << 25); + + carry0 = (h0 + ((int64_t) 1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 * ((int64_t) 1 << 26); + carry2 = (h2 + ((int64_t) 1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 * ((int64_t) 1 << 26); + carry4 = (h4 + ((int64_t) 1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 * ((int64_t) 1 << 26); + carry6 = (h6 + ((int64_t) 1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 * ((int64_t) 1 << 26); + carry8 = (h8 + ((int64_t) 1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 * ((int64_t) 1 << 26); + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} diff --git a/libs/libsodium/src/include/sodium/private/ed25519_ref10_fe_51.h b/libs/libsodium/src/include/sodium/private/ed25519_ref10_fe_51.h new file mode 100644 index 0000000000..3a30f30148 --- /dev/null +++ b/libs/libsodium/src/include/sodium/private/ed25519_ref10_fe_51.h @@ -0,0 +1,518 @@ +#include + +#include "private/common.h" +#include "utils.h" + +/* + h = 0 + */ + +static inline void +fe25519_0(fe25519 h) +{ + memset(&h[0], 0, 5 * sizeof h[0]); +} + +/* + h = 1 + */ + +static inline void +fe25519_1(fe25519 h) +{ + h[0] = 1; + memset(&h[1], 0, 4 * sizeof h[0]); +} + +/* + h = f + g + Can overlap h with f or g. + */ + +static inline void +fe25519_add(fe25519 h, const fe25519 f, const fe25519 g) +{ + uint64_t h0 = f[0] + g[0]; + uint64_t h1 = f[1] + g[1]; + uint64_t h2 = f[2] + g[2]; + uint64_t h3 = f[3] + g[3]; + uint64_t h4 = f[4] + g[4]; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; +} + +/* + h = f - g + */ + +static void +fe25519_sub(fe25519 h, const fe25519 f, const fe25519 g) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint64_t h0, h1, h2, h3, h4; + + h0 = g[0]; + h1 = g[1]; + h2 = g[2]; + h3 = g[3]; + h4 = g[4]; + + h1 += h0 >> 51; + h0 &= mask; + h2 += h1 >> 51; + h1 &= mask; + h3 += h2 >> 51; + h2 &= mask; + h4 += h3 >> 51; + h3 &= mask; + h0 += 19ULL * (h4 >> 51); + h4 &= mask; + + h0 = (f[0] + 0xfffffffffffdaULL) - h0; + h1 = (f[1] + 0xffffffffffffeULL) - h1; + h2 = (f[2] + 0xffffffffffffeULL) - h2; + h3 = (f[3] + 0xffffffffffffeULL) - h3; + h4 = (f[4] + 0xffffffffffffeULL) - h4; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; +} + +/* + h = -f + */ + +static inline void +fe25519_neg(fe25519 h, const fe25519 f) +{ + fe25519 zero; + + fe25519_0(zero); + fe25519_sub(h, zero, f); +} + +/* + Replace (f,g) with (g,g) if b == 1; + replace (f,g) with (f,g) if b == 0. + * + Preconditions: b in {0,1}. + */ + +static void +fe25519_cmov(fe25519 f, const fe25519 g, unsigned int b) +{ + const uint64_t mask = (uint64_t) (-(int64_t) b); + + uint64_t f0 = f[0]; + uint64_t f1 = f[1]; + uint64_t f2 = f[2]; + uint64_t f3 = f[3]; + uint64_t f4 = f[4]; + + uint64_t x0 = f0 ^ g[0]; + uint64_t x1 = f1 ^ g[1]; + uint64_t x2 = f2 ^ g[2]; + uint64_t x3 = f3 ^ g[3]; + uint64_t x4 = f4 ^ g[4]; + + x0 &= mask; + x1 &= mask; + x2 &= mask; + x3 &= mask; + x4 &= mask; + + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; +} + +/* +Replace (f,g) with (g,f) if b == 1; +replace (f,g) with (f,g) if b == 0. + +Preconditions: b in {0,1}. +*/ + +static void +fe25519_cswap(fe25519 f, fe25519 g, unsigned int b) +{ + const uint64_t mask = (uint64_t) (-(int64_t) b); + + uint64_t f0 = f[0]; + uint64_t f1 = f[1]; + uint64_t f2 = f[2]; + uint64_t f3 = f[3]; + uint64_t f4 = f[4]; + + uint64_t g0 = g[0]; + uint64_t g1 = g[1]; + uint64_t g2 = g[2]; + uint64_t g3 = g[3]; + uint64_t g4 = g[4]; + + uint64_t x0 = f0 ^ g0; + uint64_t x1 = f1 ^ g1; + uint64_t x2 = f2 ^ g2; + uint64_t x3 = f3 ^ g3; + uint64_t x4 = f4 ^ g4; + + x0 &= mask; + x1 &= mask; + x2 &= mask; + x3 &= mask; + x4 &= mask; + + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + + g[0] = g0 ^ x0; + g[1] = g1 ^ x1; + g[2] = g2 ^ x2; + g[3] = g3 ^ x3; + g[4] = g4 ^ x4; +} + +/* + h = f + */ + +static inline void +fe25519_copy(fe25519 h, const fe25519 f) +{ + uint64_t f0 = f[0]; + uint64_t f1 = f[1]; + uint64_t f2 = f[2]; + uint64_t f3 = f[3]; + uint64_t f4 = f[4]; + + h[0] = f0; + h[1] = f1; + h[2] = f2; + h[3] = f3; + h[4] = f4; +} + +/* + return 1 if f is in {1,3,5,...,q-2} + return 0 if f is in {0,2,4,...,q-1} + */ + +static inline int +fe25519_isnegative(const fe25519 f) +{ + unsigned char s[32]; + + fe25519_tobytes(s, f); + + return s[0] & 1; +} + +/* + return 1 if f == 0 + return 0 if f != 0 + */ + +static inline int +fe25519_iszero(const fe25519 f) +{ + unsigned char s[32]; + + fe25519_tobytes(s, f); + + return sodium_is_zero(s, 32); +} + +/* + h = f * g + Can overlap h with f or g. + */ + +static void +fe25519_mul(fe25519 h, const fe25519 f, const fe25519 g) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t r0, r1, r2, r3, r4, carry; + uint64_t f0, f1, f2, f3, f4; + uint64_t f1_19, f2_19, f3_19, f4_19; + uint64_t g0, g1, g2, g3, g4; + uint64_t r00, r01, r02, r03, r04; + + f0 = f[0]; + f1 = f[1]; + f2 = f[2]; + f3 = f[3]; + f4 = f[4]; + + g0 = g[0]; + g1 = g[1]; + g2 = g[2]; + g3 = g[3]; + g4 = g[4]; + + f1_19 = 19ULL * f1; + f2_19 = 19ULL * f2; + f3_19 = 19ULL * f3; + f4_19 = 19ULL * f4; + + r0 = ((uint128_t) f0 ) * ((uint128_t) g0); + r0 += ((uint128_t) f1_19) * ((uint128_t) g4); + r0 += ((uint128_t) f2_19) * ((uint128_t) g3); + r0 += ((uint128_t) f3_19) * ((uint128_t) g2); + r0 += ((uint128_t) f4_19) * ((uint128_t) g1); + + r1 = ((uint128_t) f0 ) * ((uint128_t) g1); + r1 += ((uint128_t) f1 ) * ((uint128_t) g0); + r1 += ((uint128_t) f2_19) * ((uint128_t) g4); + r1 += ((uint128_t) f3_19) * ((uint128_t) g3); + r1 += ((uint128_t) f4_19) * ((uint128_t) g2); + + r2 = ((uint128_t) f0 ) * ((uint128_t) g2); + r2 += ((uint128_t) f1 ) * ((uint128_t) g1); + r2 += ((uint128_t) f2 ) * ((uint128_t) g0); + r2 += ((uint128_t) f3_19) * ((uint128_t) g4); + r2 += ((uint128_t) f4_19) * ((uint128_t) g3); + + r3 = ((uint128_t) f0 ) * ((uint128_t) g3); + r3 += ((uint128_t) f1 ) * ((uint128_t) g2); + r3 += ((uint128_t) f2 ) * ((uint128_t) g1); + r3 += ((uint128_t) f3 ) * ((uint128_t) g0); + r3 += ((uint128_t) f4_19) * ((uint128_t) g4); + + r4 = ((uint128_t) f0 ) * ((uint128_t) g4); + r4 += ((uint128_t) f1 ) * ((uint128_t) g3); + r4 += ((uint128_t) f2 ) * ((uint128_t) g2); + r4 += ((uint128_t) f3 ) * ((uint128_t) g1); + r4 += ((uint128_t) f4 ) * ((uint128_t) g0); + + r00 = ((uint64_t) r0) & mask; + carry = r0 >> 51; + r1 += carry; + r01 = ((uint64_t) r1) & mask; + carry = r1 >> 51; + r2 += carry; + r02 = ((uint64_t) r2) & mask; + carry = r2 >> 51; + r3 += carry; + r03 = ((uint64_t) r3) & mask; + carry = r3 >> 51; + r4 += carry; + r04 = ((uint64_t) r4) & mask; + carry = r4 >> 51; + r00 += 19ULL * (uint64_t) carry; + carry = r00 >> 51; + r00 &= mask; + r01 += (uint64_t) carry; + carry = r01 >> 51; + r01 &= mask; + r02 += (uint64_t) carry; + + h[0] = r00; + h[1] = r01; + h[2] = r02; + h[3] = r03; + h[4] = r04; +} + +/* + h = f * f + Can overlap h with f. + */ + +static void +fe25519_sq(fe25519 h, const fe25519 f) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t r0, r1, r2, r3, r4, carry; + uint64_t f0, f1, f2, f3, f4; + uint64_t f0_2, f1_2, f1_38, f2_38, f3_38, f3_19, f4_19; + uint64_t r00, r01, r02, r03, r04; + + f0 = f[0]; + f1 = f[1]; + f2 = f[2]; + f3 = f[3]; + f4 = f[4]; + + f0_2 = f0 << 1; + f1_2 = f1 << 1; + + f1_38 = 38ULL * f1; + f2_38 = 38ULL * f2; + f3_38 = 38ULL * f3; + + f3_19 = 19ULL * f3; + f4_19 = 19ULL * f4; + + r0 = ((uint128_t) f0 ) * ((uint128_t) f0); + r0 += ((uint128_t) f1_38) * ((uint128_t) f4); + r0 += ((uint128_t) f2_38) * ((uint128_t) f3); + + r1 = ((uint128_t) f0_2 ) * ((uint128_t) f1); + r1 += ((uint128_t) f2_38) * ((uint128_t) f4); + r1 += ((uint128_t) f3_19) * ((uint128_t) f3); + + r2 = ((uint128_t) f0_2 ) * ((uint128_t) f2); + r2 += ((uint128_t) f1 ) * ((uint128_t) f1); + r2 += ((uint128_t) f3_38) * ((uint128_t) f4); + + r3 = ((uint128_t) f0_2 ) * ((uint128_t) f3); + r3 += ((uint128_t) f1_2 ) * ((uint128_t) f2); + r3 += ((uint128_t) f4_19) * ((uint128_t) f4); + + r4 = ((uint128_t) f0_2 ) * ((uint128_t) f4); + r4 += ((uint128_t) f1_2 ) * ((uint128_t) f3); + r4 += ((uint128_t) f2 ) * ((uint128_t) f2); + + r00 = ((uint64_t) r0) & mask; + carry = r0 >> 51; + r1 += carry; + r01 = ((uint64_t) r1) & mask; + carry = r1 >> 51; + r2 += carry; + r02 = ((uint64_t) r2) & mask; + carry = r2 >> 51; + r3 += carry; + r03 = ((uint64_t) r3) & mask; + carry = r3 >> 51; + r4 += carry; + r04 = ((uint64_t) r4) & mask; + carry = r4 >> 51; + r00 += 19ULL * (uint64_t) carry; + carry = r00 >> 51; + r00 &= mask; + r01 += (uint64_t) carry; + carry = r01 >> 51; + r01 &= mask; + r02 += (uint64_t) carry; + + h[0] = r00; + h[1] = r01; + h[2] = r02; + h[3] = r03; + h[4] = r04; +} + +/* + h = 2 * f * f + Can overlap h with f. +*/ + +static void +fe25519_sq2(fe25519 h, const fe25519 f) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t r0, r1, r2, r3, r4, carry; + uint64_t f0, f1, f2, f3, f4; + uint64_t f0_2, f1_2, f1_38, f2_38, f3_38, f3_19, f4_19; + uint64_t r00, r01, r02, r03, r04; + + f0 = f[0]; + f1 = f[1]; + f2 = f[2]; + f3 = f[3]; + f4 = f[4]; + + f0_2 = f0 << 1; + f1_2 = f1 << 1; + + f1_38 = 38ULL * f1; + f2_38 = 38ULL * f2; + f3_38 = 38ULL * f3; + + f3_19 = 19ULL * f3; + f4_19 = 19ULL * f4; + + r0 = ((uint128_t) f0 ) * ((uint128_t) f0); + r0 += ((uint128_t) f1_38) * ((uint128_t) f4); + r0 += ((uint128_t) f2_38) * ((uint128_t) f3); + + r1 = ((uint128_t) f0_2 ) * ((uint128_t) f1); + r1 += ((uint128_t) f2_38) * ((uint128_t) f4); + r1 += ((uint128_t) f3_19) * ((uint128_t) f3); + + r2 = ((uint128_t) f0_2 ) * ((uint128_t) f2); + r2 += ((uint128_t) f1 ) * ((uint128_t) f1); + r2 += ((uint128_t) f3_38) * ((uint128_t) f4); + + r3 = ((uint128_t) f0_2 ) * ((uint128_t) f3); + r3 += ((uint128_t) f1_2 ) * ((uint128_t) f2); + r3 += ((uint128_t) f4_19) * ((uint128_t) f4); + + r4 = ((uint128_t) f0_2 ) * ((uint128_t) f4); + r4 += ((uint128_t) f1_2 ) * ((uint128_t) f3); + r4 += ((uint128_t) f2 ) * ((uint128_t) f2); + + r0 <<= 1; + r1 <<= 1; + r2 <<= 1; + r3 <<= 1; + r4 <<= 1; + + r00 = ((uint64_t) r0) & mask; + carry = r0 >> 51; + r1 += carry; + r01 = ((uint64_t) r1) & mask; + carry = r1 >> 51; + r2 += carry; + r02 = ((uint64_t) r2) & mask; + carry = r2 >> 51; + r3 += carry; + r03 = ((uint64_t) r3) & mask; + carry = r3 >> 51; + r4 += carry; + r04 = ((uint64_t) r4) & mask; + carry = r4 >> 51; + r00 += 19ULL * (uint64_t) carry; + carry = r00 >> 51; + r00 &= mask; + r01 += (uint64_t) carry; + carry = r01 >> 51; + r01 &= mask; + r02 += (uint64_t) carry; + + h[0] = r00; + h[1] = r01; + h[2] = r02; + h[3] = r03; + h[4] = r04; +} + +static void +fe25519_scalar_product(fe25519 h, const fe25519 f, uint32_t n) +{ + const uint64_t mask = 0x7ffffffffffffULL; + uint128_t a; + uint128_t sn = (uint128_t) n; + uint64_t h0, h1, h2, h3, h4; + + a = f[0] * sn; + h0 = ((uint64_t) a) & mask; + a = f[1] * sn + ((uint64_t) (a >> 51)); + h1 = ((uint64_t) a) & mask; + a = f[2] * sn + ((uint64_t) (a >> 51)); + h2 = ((uint64_t) a) & mask; + a = f[3] * sn + ((uint64_t) (a >> 51)); + h3 = ((uint64_t) a) & mask; + a = f[4] * sn + ((uint64_t) (a >> 51)); + h4 = ((uint64_t) a) & mask; + + h0 += (a >> 51) * 19ULL; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; +} diff --git a/libs/libsodium/src/include/sodium/private/implementations.h b/libs/libsodium/src/include/sodium/private/implementations.h new file mode 100644 index 0000000000..c7237f851d --- /dev/null +++ b/libs/libsodium/src/include/sodium/private/implementations.h @@ -0,0 +1,11 @@ +#ifndef implementations_H +#define implementations_H + +int _crypto_generichash_blake2b_pick_best_implementation(void); +int _crypto_onetimeauth_poly1305_pick_best_implementation(void); +int _crypto_pwhash_argon2_pick_best_implementation(void); +int _crypto_scalarmult_curve25519_pick_best_implementation(void); +int _crypto_stream_chacha20_pick_best_implementation(void); +int _crypto_stream_salsa20_pick_best_implementation(void); + +#endif diff --git a/libs/libsodium/src/include/sodium/private/mutex.h b/libs/libsodium/src/include/sodium/private/mutex.h new file mode 100644 index 0000000000..322b6742b2 --- /dev/null +++ b/libs/libsodium/src/include/sodium/private/mutex.h @@ -0,0 +1,7 @@ +#ifndef mutex_H +#define mutex_H 1 + +extern int sodium_crit_enter(void); +extern int sodium_crit_leave(void); + +#endif diff --git a/libs/libsodium/src/include/sodium/private/sse2_64_32.h b/libs/libsodium/src/include/sodium/private/sse2_64_32.h new file mode 100644 index 0000000000..d0455b41b4 --- /dev/null +++ b/libs/libsodium/src/include/sodium/private/sse2_64_32.h @@ -0,0 +1,50 @@ +#ifndef sse2_64_32_H +#define sse2_64_32_H 1 + +#include "common.h" + +#ifdef HAVE_INTRIN_H +# include +#endif + +#if defined(HAVE_EMMINTRIN_H) && \ + !(defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || \ + defined(_M_X64) || defined(_M_AMD64)) + +# include +# include + +# ifndef _mm_set_epi64x +# define _mm_set_epi64x(Q0, Q1) sodium__mm_set_epi64x((Q0), (Q1)) +static inline __m128i +sodium__mm_set_epi64x(int64_t q1, int64_t q0) +{ + union { int64_t as64; int32_t as32[2]; } x0, x1; + x0.as64 = q0; x1.as64 = q1; + return _mm_set_epi32(x1.as32[1], x1.as32[0], x0.as32[1], x0.as32[0]); +} +# endif + +# ifndef _mm_set1_epi64x +# define _mm_set1_epi64x(Q) sodium__mm_set1_epi64x(Q) +static inline __m128i +sodium__mm_set1_epi64x(int64_t q) +{ + return _mm_set_epi64x(q, q); +} +# endif + +# ifndef _mm_cvtsi64_si128 +# define _mm_cvtsi64_si128(Q) sodium__mm_cvtsi64_si128(Q) +static inline __m128i +sodium__mm_cvtsi64_si128(int64_t q) +{ + union { int64_t as64; int32_t as32[2]; } x; + x.as64 = q; + return _mm_setr_epi32(x.as32[0], x.as32[1], 0, 0); +} +# endif + +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/randombytes.h b/libs/libsodium/src/include/sodium/randombytes.h new file mode 100644 index 0000000000..d19f684ed6 --- /dev/null +++ b/libs/libsodium/src/include/sodium/randombytes.h @@ -0,0 +1,68 @@ + +#ifndef randombytes_H +#define randombytes_H + +#include +#include + +#include + +#include "export.h" + +#ifdef __cplusplus +# ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +typedef struct randombytes_implementation { + const char *(*implementation_name)(void); /* required */ + uint32_t (*random)(void); /* required */ + void (*stir)(void); /* optional */ + uint32_t (*uniform)(const uint32_t upper_bound); /* optional, a default implementation will be used if NULL */ + void (*buf)(void * const buf, const size_t size); /* required */ + int (*close)(void); /* optional */ +} randombytes_implementation; + +#define randombytes_BYTES_MAX SODIUM_MIN(SODIUM_SIZE_MAX, 0xffffffffUL) + +#define randombytes_SEEDBYTES 32U +SODIUM_EXPORT +size_t randombytes_seedbytes(void); + +SODIUM_EXPORT +void randombytes_buf(void * const buf, const size_t size); + +SODIUM_EXPORT +void randombytes_buf_deterministic(void * const buf, const size_t size, + const unsigned char seed[randombytes_SEEDBYTES]); + +SODIUM_EXPORT +uint32_t randombytes_random(void); + +SODIUM_EXPORT +uint32_t randombytes_uniform(const uint32_t upper_bound); + +SODIUM_EXPORT +void randombytes_stir(void); + +SODIUM_EXPORT +int randombytes_close(void); + +SODIUM_EXPORT +int randombytes_set_implementation(randombytes_implementation *impl); + +SODIUM_EXPORT +const char *randombytes_implementation_name(void); + +/* -- NaCl compatibility interface -- */ + +SODIUM_EXPORT +void randombytes(unsigned char * const buf, const unsigned long long buf_len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/randombytes_nativeclient.h b/libs/libsodium/src/include/sodium/randombytes_nativeclient.h new file mode 100644 index 0000000000..5158d8c3c3 --- /dev/null +++ b/libs/libsodium/src/include/sodium/randombytes_nativeclient.h @@ -0,0 +1,23 @@ + +#ifndef randombytes_nativeclient_H +#define randombytes_nativeclient_H + +#ifdef __native_client__ + +# include "export.h" +# include "randombytes.h" + +# ifdef __cplusplus +extern "C" { +# endif + +SODIUM_EXPORT +extern struct randombytes_implementation randombytes_nativeclient_implementation; + +# ifdef __cplusplus +} +# endif + +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/randombytes_salsa20_random.h b/libs/libsodium/src/include/sodium/randombytes_salsa20_random.h new file mode 100644 index 0000000000..4deae15b6d --- /dev/null +++ b/libs/libsodium/src/include/sodium/randombytes_salsa20_random.h @@ -0,0 +1,19 @@ + +#ifndef randombytes_salsa20_random_H +#define randombytes_salsa20_random_H + +#include "export.h" +#include "randombytes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SODIUM_EXPORT +extern struct randombytes_implementation randombytes_salsa20_implementation; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/randombytes_sysrandom.h b/libs/libsodium/src/include/sodium/randombytes_sysrandom.h new file mode 100644 index 0000000000..9e27b674c7 --- /dev/null +++ b/libs/libsodium/src/include/sodium/randombytes_sysrandom.h @@ -0,0 +1,19 @@ + +#ifndef randombytes_sysrandom_H +#define randombytes_sysrandom_H + +#include "export.h" +#include "randombytes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SODIUM_EXPORT +extern struct randombytes_implementation randombytes_sysrandom_implementation; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/runtime.h b/libs/libsodium/src/include/sodium/runtime.h new file mode 100644 index 0000000000..7f15d58e7c --- /dev/null +++ b/libs/libsodium/src/include/sodium/runtime.h @@ -0,0 +1,52 @@ + +#ifndef sodium_runtime_H +#define sodium_runtime_H + +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_neon(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_sse2(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_sse3(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_ssse3(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_sse41(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_avx(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_avx2(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_avx512f(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_pclmul(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_aesni(void); + +SODIUM_EXPORT_WEAK +int sodium_runtime_has_rdrand(void); + +/* ------------------------------------------------------------------------- */ + +int _sodium_runtime_get_cpu_features(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/utils.h b/libs/libsodium/src/include/sodium/utils.h new file mode 100644 index 0000000000..46eb331cfd --- /dev/null +++ b/libs/libsodium/src/include/sodium/utils.h @@ -0,0 +1,170 @@ + +#ifndef sodium_utils_H +#define sodium_utils_H + +#include + +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SODIUM_C99 +# if defined(__cplusplus) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L +# define SODIUM_C99(X) +# else +# define SODIUM_C99(X) X +# endif +#endif + +SODIUM_EXPORT +void sodium_memzero(void * const pnt, const size_t len); + +SODIUM_EXPORT +void sodium_stackzero(const size_t len); + +/* + * WARNING: sodium_memcmp() must be used to verify if two secret keys + * are equal, in constant time. + * It returns 0 if the keys are equal, and -1 if they differ. + * This function is not designed for lexicographical comparisons. + */ +SODIUM_EXPORT +int sodium_memcmp(const void * const b1_, const void * const b2_, size_t len) + __attribute__ ((warn_unused_result)); + +/* + * sodium_compare() returns -1 if b1_ < b2_, 1 if b1_ > b2_ and 0 if b1_ == b2_ + * It is suitable for lexicographical comparisons, or to compare nonces + * and counters stored in little-endian format. + * However, it is slower than sodium_memcmp(). + */ +SODIUM_EXPORT +int sodium_compare(const unsigned char *b1_, const unsigned char *b2_, + size_t len) + __attribute__ ((warn_unused_result)); + +SODIUM_EXPORT +int sodium_is_zero(const unsigned char *n, const size_t nlen); + +SODIUM_EXPORT +void sodium_increment(unsigned char *n, const size_t nlen); + +SODIUM_EXPORT +void sodium_add(unsigned char *a, const unsigned char *b, const size_t len); + +SODIUM_EXPORT +char *sodium_bin2hex(char * const hex, const size_t hex_maxlen, + const unsigned char * const bin, const size_t bin_len); + +SODIUM_EXPORT +int sodium_hex2bin(unsigned char * const bin, const size_t bin_maxlen, + const char * const hex, const size_t hex_len, + const char * const ignore, size_t * const bin_len, + const char ** const hex_end); + +#define sodium_base64_VARIANT_ORIGINAL 1 +#define sodium_base64_VARIANT_ORIGINAL_NO_PADDING 3 +#define sodium_base64_VARIANT_URLSAFE 5 +#define sodium_base64_VARIANT_URLSAFE_NO_PADDING 7 + +/* + * Computes the required length to encode BIN_LEN bytes as a base64 string + * using the given variant. The computed length includes a trailing \0. + */ +#define sodium_base64_ENCODED_LEN(BIN_LEN, VARIANT) \ + (((BIN_LEN) / 3U) * 4U + \ + ((((BIN_LEN) - ((BIN_LEN) / 3U) * 3U) | (((BIN_LEN) - ((BIN_LEN) / 3U) * 3U) >> 1)) & 1U) * \ + (4U - (~((((VARIANT) & 2U) >> 1) - 1U) & (3U - ((BIN_LEN) - ((BIN_LEN) / 3U) * 3U)))) + 1U) + +SODIUM_EXPORT +size_t sodium_base64_encoded_len(const size_t bin_len, const int variant); + +SODIUM_EXPORT +char *sodium_bin2base64(char * const b64, const size_t b64_maxlen, + const unsigned char * const bin, const size_t bin_len, + const int variant); + +SODIUM_EXPORT +int sodium_base642bin(unsigned char * const bin, const size_t bin_maxlen, + const char * const b64, const size_t b64_len, + const char * const ignore, size_t * const bin_len, + const char ** const b64_end, const int variant); + +SODIUM_EXPORT +int sodium_mlock(void * const addr, const size_t len); + +SODIUM_EXPORT +int sodium_munlock(void * const addr, const size_t len); + +/* WARNING: sodium_malloc() and sodium_allocarray() are not general-purpose + * allocation functions. + * + * They return a pointer to a region filled with 0xd0 bytes, immediately + * followed by a guard page. + * As a result, accessing a single byte after the requested allocation size + * will intentionally trigger a segmentation fault. + * + * A canary and an additional guard page placed before the beginning of the + * region may also kill the process if a buffer underflow is detected. + * + * The memory layout is: + * [unprotected region size (read only)][guard page (no access)][unprotected pages (read/write)][guard page (no access)] + * With the layout of the unprotected pages being: + * [optional padding][16-bytes canary][user region] + * + * However: + * - These functions are significantly slower than standard functions + * - Each allocation requires 3 or 4 additional pages + * - The returned address will not be aligned if the allocation size is not + * a multiple of the required alignment. For this reason, these functions + * are designed to store data, such as secret keys and messages. + * + * sodium_malloc() can be used to allocate any libsodium data structure. + * + * The crypto_generichash_state structure is packed and its length is + * either 357 or 361 bytes. For this reason, when using sodium_malloc() to + * allocate a crypto_generichash_state structure, padding must be added in + * order to ensure proper alignment. crypto_generichash_statebytes() + * returns the rounded up structure size, and should be prefered to sizeof(): + * state = sodium_malloc(crypto_generichash_statebytes()); + */ + +SODIUM_EXPORT +void *sodium_malloc(const size_t size) + __attribute__ ((malloc)); + +SODIUM_EXPORT +void *sodium_allocarray(size_t count, size_t size) + __attribute__ ((malloc)); + +SODIUM_EXPORT +void sodium_free(void *ptr); + +SODIUM_EXPORT +int sodium_mprotect_noaccess(void *ptr); + +SODIUM_EXPORT +int sodium_mprotect_readonly(void *ptr); + +SODIUM_EXPORT +int sodium_mprotect_readwrite(void *ptr); + +SODIUM_EXPORT +int sodium_pad(size_t *padded_buflen_p, unsigned char *buf, + size_t unpadded_buflen, size_t blocksize, size_t max_buflen); + +SODIUM_EXPORT +int sodium_unpad(size_t *unpadded_buflen_p, const unsigned char *buf, + size_t padded_buflen, size_t blocksize); + +/* -------- */ + +int _sodium_alloc_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/include/sodium/version.h b/libs/libsodium/src/include/sodium/version.h new file mode 100644 index 0000000000..56ec2b9550 --- /dev/null +++ b/libs/libsodium/src/include/sodium/version.h @@ -0,0 +1,32 @@ + +#ifndef sodium_version_H +#define sodium_version_H + +#include "export.h" + +#define SODIUM_VERSION_STRING "1.0.16" + +#define SODIUM_LIBRARY_VERSION_MAJOR 10 +#define SODIUM_LIBRARY_VERSION_MINOR 1 + +#ifdef __cplusplus +extern "C" { +#endif + +SODIUM_EXPORT +const char *sodium_version_string(void); + +SODIUM_EXPORT +int sodium_library_version_major(void); + +SODIUM_EXPORT +int sodium_library_version_minor(void); + +SODIUM_EXPORT +int sodium_library_minimal(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libsodium/src/randombytes/nativeclient/randombytes_nativeclient.c b/libs/libsodium/src/randombytes/nativeclient/randombytes_nativeclient.c new file mode 100644 index 0000000000..85ffa9b29b --- /dev/null +++ b/libs/libsodium/src/randombytes/nativeclient/randombytes_nativeclient.c @@ -0,0 +1,61 @@ + +#include +#include +#include + +#ifdef __native_client__ +# include + +# include "core.h" +# include "utils.h" +# include "randombytes.h" +# include "randombytes_nativeclient.h" + +static void +randombytes_nativeclient_buf(void * const buf, const size_t size) +{ + unsigned char *buf_ = (unsigned char *) buf; + struct nacl_irt_random rand_intf; + size_t readnb = (size_t) 0U; + size_t toread = size; + + if (nacl_interface_query(NACL_IRT_RANDOM_v0_1, &rand_intf, + sizeof rand_intf) != sizeof rand_intf) { + sodium_misuse(); + } + while (toread > (size_t) 0U) { + if (rand_intf.get_random_bytes(buf_, size, &readnb) != 0 || + readnb > size) { + sodium_misuse(); + } + toread -= readnb; + buf_ += readnb; + } +} + +static uint32_t +randombytes_nativeclient_random(void) +{ + uint32_t r; + + randombytes_nativeclient_buf(&r, sizeof r); + + return r; +} + +static const char * +randombytes_nativeclient_implementation_name(void) +{ + return "nativeclient"; +} + +struct randombytes_implementation randombytes_nativeclient_implementation = { + SODIUM_C99(.implementation_name =) randombytes_nativeclient_implementation_name, + SODIUM_C99(.random =) randombytes_nativeclient_random, + SODIUM_C99(.stir =) NULL, + SODIUM_C99(.uniform =) NULL, + SODIUM_C99(.buf =) randombytes_nativeclient_buf, + SODIUM_C99(.close =) NULL +}; + +#endif diff --git a/libs/libsodium/src/randombytes/randombytes.c b/libs/libsodium/src/randombytes/randombytes.c new file mode 100644 index 0000000000..708616b8aa --- /dev/null +++ b/libs/libsodium/src/randombytes/randombytes.c @@ -0,0 +1,206 @@ + +#include +#include +#include +#include + +#include + +#ifdef __EMSCRIPTEN__ +# include +#endif + +#include "core.h" +#include "crypto_stream_chacha20.h" +#include "randombytes.h" +#ifdef RANDOMBYTES_DEFAULT_IMPLEMENTATION +# include "randombytes_default.h" +#else +# ifdef __native_client__ +# include "randombytes_nativeclient.h" +# else +# include "randombytes_sysrandom.h" +# endif +#endif +#include "private/common.h" + +/* C++Builder defines a "random" macro */ +#undef random + +static const randombytes_implementation *implementation; + +#ifndef RANDOMBYTES_DEFAULT_IMPLEMENTATION +# ifdef __EMSCRIPTEN__ +# define RANDOMBYTES_DEFAULT_IMPLEMENTATION NULL +# else +# ifdef __native_client__ +# define RANDOMBYTES_DEFAULT_IMPLEMENTATION &randombytes_nativeclient_implementation; +# else +# define RANDOMBYTES_DEFAULT_IMPLEMENTATION &randombytes_sysrandom_implementation; +# endif +# endif +#endif + +static void +randombytes_init_if_needed(void) +{ + if (implementation == NULL) { + implementation = RANDOMBYTES_DEFAULT_IMPLEMENTATION; + randombytes_stir(); + } +} + +int +randombytes_set_implementation(randombytes_implementation *impl) +{ + implementation = impl; + + return 0; +} + +const char * +randombytes_implementation_name(void) +{ +#ifndef __EMSCRIPTEN__ + randombytes_init_if_needed(); + return implementation->implementation_name(); +#else + return "js"; +#endif +} + +uint32_t +randombytes_random(void) +{ +#ifndef __EMSCRIPTEN__ + randombytes_init_if_needed(); + return implementation->random(); +#else + return EM_ASM_INT_V({ + return Module.getRandomValue(); + }); +#endif +} + +void +randombytes_stir(void) +{ +#ifndef __EMSCRIPTEN__ + randombytes_init_if_needed(); + if (implementation->stir != NULL) { + implementation->stir(); + } +#else + EM_ASM({ + if (Module.getRandomValue === undefined) { + try { + var window_ = 'object' === typeof window ? window : self; + var crypto_ = typeof window_.crypto !== 'undefined' ? window_.crypto : window_.msCrypto; + var randomValuesStandard = function() { + var buf = new Uint32Array(1); + crypto_.getRandomValues(buf); + return buf[0] >>> 0; + }; + randomValuesStandard(); + Module.getRandomValue = randomValuesStandard; + } catch (e) { + try { + var crypto = require('crypto'); + var randomValueNodeJS = function() { + var buf = crypto.randomBytes(4); + return (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]) >>> 0; + }; + randomValueNodeJS(); + Module.getRandomValue = randomValueNodeJS; + } catch (e) { + throw 'No secure random number generator found'; + } + } + } + }); +#endif +} + +uint32_t +randombytes_uniform(const uint32_t upper_bound) +{ + uint32_t min; + uint32_t r; + +#ifndef __EMSCRIPTEN__ + randombytes_init_if_needed(); + if (implementation->uniform != NULL) { + return implementation->uniform(upper_bound); + } +#endif + if (upper_bound < 2) { + return 0; + } + min = (1U + ~upper_bound) % upper_bound; /* = 2**32 mod upper_bound */ + do { + r = randombytes_random(); + } while (r < min); + /* r is now clamped to a set whose size mod upper_bound == 0 + * the worst case (2**31+1) requires ~ 2 attempts */ + + return r % upper_bound; +} + +void +randombytes_buf(void * const buf, const size_t size) +{ +#ifndef __EMSCRIPTEN__ + randombytes_init_if_needed(); + if (size > (size_t) 0U) { + implementation->buf(buf, size); + } +#else + unsigned char *p = (unsigned char *) buf; + size_t i; + + for (i = (size_t) 0U; i < size; i++) { + p[i] = (unsigned char) randombytes_random(); + } +#endif +} + +void +randombytes_buf_deterministic(void * const buf, const size_t size, + const unsigned char seed[randombytes_SEEDBYTES]) +{ + static const unsigned char nonce[crypto_stream_chacha20_ietf_NONCEBYTES] = { + 'L', 'i', 'b', 's', 'o', 'd', 'i', 'u', 'm', 'D', 'R', 'G' + }; + + COMPILER_ASSERT(randombytes_SEEDBYTES == crypto_stream_chacha20_ietf_KEYBYTES); +#if SIZE_MAX > 0x4000000000ULL + COMPILER_ASSERT(randombytes_BYTES_MAX <= 0x4000000000ULL); + if (size > 0x4000000000ULL) { + sodium_misuse(); + } +#endif + crypto_stream_chacha20_ietf((unsigned char *) buf, (unsigned long long) size, + nonce, seed); +} + +size_t +randombytes_seedbytes(void) +{ + return randombytes_SEEDBYTES; +} + +int +randombytes_close(void) +{ + if (implementation != NULL && implementation->close != NULL) { + return implementation->close(); + } + return 0; +} + +void +randombytes(unsigned char * const buf, const unsigned long long buf_len) +{ + assert(buf_len <= SIZE_MAX); + randombytes_buf(buf, (size_t) buf_len); +} diff --git a/libs/libsodium/src/randombytes/salsa20/randombytes_salsa20_random.c b/libs/libsodium/src/randombytes/salsa20/randombytes_salsa20_random.c new file mode 100644 index 0000000000..79916eabc0 --- /dev/null +++ b/libs/libsodium/src/randombytes/salsa20/randombytes_salsa20_random.c @@ -0,0 +1,564 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(_MSC_VER) && !defined(__BORLANDC__) +# include +#endif + +#include +#ifndef _WIN32 +# include +# include +#endif +#ifdef __linux__ +# ifdef __dietlibc__ +# define _LINUX_SOURCE +# else +# include +# endif +# include +#endif +#ifdef HAVE_RDRAND +# pragma GCC target("rdrnd") +# include +#endif + +#include "core.h" +#include "crypto_core_salsa20.h" +#include "crypto_stream_salsa20.h" +#include "private/common.h" +#include "randombytes.h" +#include "randombytes_salsa20_random.h" +#include "runtime.h" +#include "utils.h" + +#ifdef _WIN32 +# include +# include +# define RtlGenRandom SystemFunction036 +# if defined(__cplusplus) +extern "C" +# endif +BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); +# pragma comment(lib, "advapi32.lib") +# ifdef __BORLANDC__ +# define _ftime ftime +# define _timeb timeb +# endif +#endif + +#define SALSA20_RANDOM_BLOCK_SIZE crypto_core_salsa20_OUTPUTBYTES + +#if defined(__OpenBSD__) || defined(__CloudABI__) +# define HAVE_SAFE_ARC4RANDOM 1 +#endif + +#ifndef SSIZE_MAX +# define SSIZE_MAX (SIZE_MAX / 2 - 1) +#endif +#ifndef S_ISNAM +# ifdef __COMPCERT__ +# define S_ISNAM(X) 1 +# else +# define S_ISNAM(X) 0 +# endif +#endif + +#ifndef TLS +# ifdef _WIN32 +# define TLS __declspec(thread) +# else +# define TLS +# endif +#endif + +typedef struct Salsa20RandomGlobal_ { + int initialized; + int random_data_source_fd; + int getrandom_available; + int rdrand_available; +#ifdef HAVE_GETPID + pid_t pid; +#endif +} Salsa20RandomGlobal; + +typedef struct Salsa20Random_ { + int initialized; + size_t rnd32_outleft; + unsigned char key[crypto_stream_salsa20_KEYBYTES]; + unsigned char rnd32[16U * SALSA20_RANDOM_BLOCK_SIZE]; + uint64_t nonce; +} Salsa20Random; + +static Salsa20RandomGlobal global = { + SODIUM_C99(.initialized =) 0, + SODIUM_C99(.random_data_source_fd =) -1 +}; + +static TLS Salsa20Random stream = { + SODIUM_C99(.initialized =) 0, + SODIUM_C99(.rnd32_outleft =) (size_t) 0U +}; + + +/* + * Get a high-resolution timestamp, as a uint64_t value + */ + +#ifdef _WIN32 +static uint64_t +sodium_hrtime(void) +{ + struct _timeb tb; +# pragma warning(push) +# pragma warning(disable: 4996) + _ftime(&tb); +# pragma warning(pop) + return ((uint64_t) tb.time) * 1000000U + ((uint64_t) tb.millitm) * 1000U; +} + +#else /* _WIN32 */ + +static uint64_t +sodium_hrtime(void) +{ + struct timeval tv; + + if (gettimeofday(&tv, NULL) != 0) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + return ((uint64_t) tv.tv_sec) * 1000000U + (uint64_t) tv.tv_usec; +} +#endif + +/* + * Initialize the entropy source + */ + +#ifdef _WIN32 + +static void +randombytes_salsa20_random_init(void) +{ + stream.nonce = sodium_hrtime(); + assert(stream.nonce != (uint64_t) 0U); + global.rdrand_available = sodium_runtime_has_rdrand(); +} + +#else /* _WIN32 */ + +static ssize_t +safe_read(const int fd, void * const buf_, size_t size) +{ + unsigned char *buf = (unsigned char *) buf_; + ssize_t readnb; + + assert(size > (size_t) 0U); + assert(size <= SSIZE_MAX); + do { + while ((readnb = read(fd, buf, size)) < (ssize_t) 0 && + (errno == EINTR || errno == EAGAIN)); /* LCOV_EXCL_LINE */ + if (readnb < (ssize_t) 0) { + return readnb; /* LCOV_EXCL_LINE */ + } + if (readnb == (ssize_t) 0) { + break; /* LCOV_EXCL_LINE */ + } + size -= (size_t) readnb; + buf += readnb; + } while (size > (ssize_t) 0); + + return (ssize_t) (buf - (unsigned char *) buf_); +} + +# if defined(__linux__) && !defined(USE_BLOCKING_RANDOM) && !defined(NO_BLOCKING_RANDOM_POLL) +static int +randombytes_block_on_dev_random(void) +{ + struct pollfd pfd; + int fd; + int pret; + + fd = open("/dev/random", O_RDONLY); + if (fd == -1) { + return 0; + } + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + do { + pret = poll(&pfd, 1, -1); + } while (pret < 0 && (errno == EINTR || errno == EAGAIN)); + if (pret != 1) { + (void) close(fd); + errno = EIO; + return -1; + } + return close(fd); +} +# endif + +# ifndef HAVE_SAFE_ARC4RANDOM +static int +randombytes_salsa20_random_random_dev_open(void) +{ +/* LCOV_EXCL_START */ + struct stat st; + static const char *devices[] = { +# ifndef USE_BLOCKING_RANDOM + "/dev/urandom", +# endif + "/dev/random", NULL + }; + const char **device = devices; + int fd; + +# if defined(__linux__) && !defined(USE_BLOCKING_RANDOM) && !defined(NO_BLOCKING_RANDOM_POLL) + if (randombytes_block_on_dev_random() != 0) { + return -1; + } +# endif + do { + fd = open(*device, O_RDONLY); + if (fd != -1) { + if (fstat(fd, &st) == 0 && (S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode))) { +# if defined(F_SETFD) && defined(FD_CLOEXEC) + (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); +# endif + return fd; + } + (void) close(fd); + } else if (errno == EINTR) { + continue; + } + device++; + } while (*device != NULL); + + errno = EIO; + return -1; +/* LCOV_EXCL_STOP */ +} +# endif + +# if defined(__dietlibc__) || (defined(SYS_getrandom) && defined(__NR_getrandom)) +static int +_randombytes_linux_getrandom(void * const buf, const size_t size) +{ + int readnb; + + assert(size <= 256U); + do { +# ifdef __dietlibc__ + readnb = getrandom(buf, size, 0); +# else + readnb = syscall(SYS_getrandom, buf, (int) size, 0); +# endif + } while (readnb < 0 && (errno == EINTR || errno == EAGAIN)); + + return (readnb == (int) size) - 1; +} + +static int +randombytes_linux_getrandom(void * const buf_, size_t size) +{ + unsigned char *buf = (unsigned char *) buf_; + size_t chunk_size = 256U; + + do { + if (size < chunk_size) { + chunk_size = size; + assert(chunk_size > (size_t) 0U); + } + if (_randombytes_linux_getrandom(buf, chunk_size) != 0) { + return -1; + } + size -= chunk_size; + buf += chunk_size; + } while (size > (size_t) 0U); + + return 0; +} +# endif + +static void +randombytes_salsa20_random_init(void) +{ + const int errno_save = errno; + + stream.nonce = sodium_hrtime(); + global.rdrand_available = sodium_runtime_has_rdrand(); + assert(stream.nonce != (uint64_t) 0U); + +# ifdef HAVE_SAFE_ARC4RANDOM + errno = errno_save; +# else + +# if defined(SYS_getrandom) && defined(__NR_getrandom) + { + unsigned char fodder[16]; + + if (randombytes_linux_getrandom(fodder, sizeof fodder) == 0) { + global.getrandom_available = 1; + errno = errno_save; + return; + } + global.getrandom_available = 0; + } +# endif /* SYS_getrandom */ + + if ((global.random_data_source_fd = + randombytes_salsa20_random_random_dev_open()) == -1) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + errno = errno_save; +# endif /* HAVE_SAFE_ARC4RANDOM */ +} + +#endif /* _WIN32 */ + +/* + * (Re)seed the generator using the entropy source + */ + +static void +randombytes_salsa20_random_stir(void) +{ + unsigned char m0[crypto_stream_salsa20_KEYBYTES + + crypto_stream_salsa20_NONCEBYTES]; + + memset(stream.rnd32, 0, sizeof stream.rnd32); + stream.rnd32_outleft = (size_t) 0U; + if (global.initialized == 0) { + randombytes_salsa20_random_init(); + global.initialized = 1; + } +#ifdef HAVE_GETPID + global.pid = getpid(); +#endif + +#ifndef _WIN32 + +# ifdef HAVE_SAFE_ARC4RANDOM + arc4random_buf(m0, sizeof m0); +# elif defined(SYS_getrandom) && defined(__NR_getrandom) + if (global.getrandom_available != 0) { + if (randombytes_linux_getrandom(m0, sizeof m0) != 0) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + } else if (global.random_data_source_fd == -1 || + safe_read(global.random_data_source_fd, m0, + sizeof m0) != (ssize_t) sizeof m0) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +# else + if (global.random_data_source_fd == -1 || + safe_read(global.random_data_source_fd, m0, + sizeof m0) != (ssize_t) sizeof m0) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +# endif + +#else /* _WIN32 */ + if (! RtlGenRandom((PVOID) m0, (ULONG) sizeof m0)) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#endif + + crypto_stream_salsa20(stream.key, sizeof stream.key, + m0 + crypto_stream_salsa20_KEYBYTES, m0); + sodium_memzero(m0, sizeof m0); + stream.initialized = 1; +} + +/* + * Reseed the generator if it hasn't been initialized yet + */ + +static void +randombytes_salsa20_random_stir_if_needed(void) +{ +#ifdef HAVE_GETPID + if (stream.initialized == 0) { + randombytes_salsa20_random_stir(); + } else if (global.pid != getpid()) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#else + if (stream.initialized == 0) { + randombytes_salsa20_random_stir(); + } +#endif +} + +/* + * Close the stream, free global resources + */ + +#ifdef _WIN32 +static int +randombytes_salsa20_random_close(void) +{ + int ret = -1; + + if (global.initialized != 0) { + global.initialized = 0; + ret = 0; + } + sodium_memzero(&stream, sizeof stream); + + return ret; +} +#else +static int +randombytes_salsa20_random_close(void) +{ + int ret = -1; + + if (global.random_data_source_fd != -1 && + close(global.random_data_source_fd) == 0) { + global.random_data_source_fd = -1; + global.initialized = 0; +# ifdef HAVE_GETPID + global.pid = (pid_t) 0; +# endif + ret = 0; + } + +# ifdef HAVE_SAFE_ARC4RANDOM + ret = 0; +# endif + +# if defined(SYS_getrandom) && defined(__NR_getrandom) + if (global.getrandom_available != 0) { + ret = 0; + } +# endif + + sodium_memzero(&stream, sizeof stream); + + return ret; +} +#endif + +/* + * RDRAND is only used to mitigate prediction if a key is compromised + */ + +static void +randombytes_salsa20_random_xorhwrand(void) +{ +/* LCOV_EXCL_START */ +#ifdef HAVE_RDRAND + unsigned int r; + + if (global.rdrand_available == 0) { + return; + } + (void) _rdrand32_step(&r); + * (uint32_t *) (void *) + &stream.key[crypto_stream_salsa20_KEYBYTES - 4] ^= (uint32_t) r; +#endif +/* LCOV_EXCL_STOP */ +} + +/* + * XOR the key with another same-length secret + */ + +static inline void +randombytes_salsa20_random_xorkey(const unsigned char * const mix) +{ + unsigned char *key = stream.key; + size_t i; + + for (i = (size_t) 0U; i < sizeof stream.key; i++) { + key[i] ^= mix[i]; + } +} + +/* + * Put `size` random bytes into `buf` and overwrite the key + */ + +static void +randombytes_salsa20_random_buf(void * const buf, const size_t size) +{ + size_t i; + int ret; + + randombytes_salsa20_random_stir_if_needed(); + COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES); +#if defined(ULONG_LONG_MAX) && defined(SIZE_MAX) +# if SIZE_MAX > ULONG_LONG_MAX + /* coverity[result_independent_of_operands] */ + assert(size <= ULONG_LONG_MAX); +# endif +#endif + ret = crypto_stream_salsa20((unsigned char *) buf, (unsigned long long) size, + (unsigned char *) &stream.nonce, stream.key); + assert(ret == 0); + for (i = 0U; i < sizeof size; i++) { + stream.key[i] ^= ((const unsigned char *) (const void *) &size)[i]; + } + randombytes_salsa20_random_xorhwrand(); + stream.nonce++; + crypto_stream_salsa20_xor(stream.key, stream.key, sizeof stream.key, + (unsigned char *) &stream.nonce, stream.key); +} + +/* + * Pop a 32-bit value from the random pool + * + * Overwrite the key after the pool gets refilled. + */ + +static uint32_t +randombytes_salsa20_random(void) +{ + uint32_t val; + int ret; + + COMPILER_ASSERT(sizeof stream.rnd32 >= (sizeof stream.key) + (sizeof val)); + COMPILER_ASSERT(((sizeof stream.rnd32) - (sizeof stream.key)) + % sizeof val == (size_t) 0U); + if (stream.rnd32_outleft <= (size_t) 0U) { + randombytes_salsa20_random_stir_if_needed(); + COMPILER_ASSERT(sizeof stream.nonce == crypto_stream_salsa20_NONCEBYTES); + ret = crypto_stream_salsa20((unsigned char *) stream.rnd32, + (unsigned long long) sizeof stream.rnd32, + (unsigned char *) &stream.nonce, + stream.key); + assert(ret == 0); + stream.rnd32_outleft = (sizeof stream.rnd32) - (sizeof stream.key); + randombytes_salsa20_random_xorhwrand(); + randombytes_salsa20_random_xorkey(&stream.rnd32[stream.rnd32_outleft]); + memset(&stream.rnd32[stream.rnd32_outleft], 0, sizeof stream.key); + stream.nonce++; + } + stream.rnd32_outleft -= sizeof val; + memcpy(&val, &stream.rnd32[stream.rnd32_outleft], sizeof val); + memset(&stream.rnd32[stream.rnd32_outleft], 0, sizeof val); + + return val; +} + +static const char * +randombytes_salsa20_implementation_name(void) +{ + return "salsa20"; +} + +struct randombytes_implementation randombytes_salsa20_implementation = { + SODIUM_C99(.implementation_name =) randombytes_salsa20_implementation_name, + SODIUM_C99(.random =) randombytes_salsa20_random, + SODIUM_C99(.stir =) randombytes_salsa20_random_stir, + SODIUM_C99(.uniform =) NULL, + SODIUM_C99(.buf =) randombytes_salsa20_random_buf, + SODIUM_C99(.close =) randombytes_salsa20_random_close +}; diff --git a/libs/libsodium/src/randombytes/sysrandom/randombytes_sysrandom.c b/libs/libsodium/src/randombytes/sysrandom/randombytes_sysrandom.c new file mode 100644 index 0000000000..f4dec08f5b --- /dev/null +++ b/libs/libsodium/src/randombytes/sysrandom/randombytes_sysrandom.c @@ -0,0 +1,382 @@ + +#include +#include +#include +#include +#include +#include +#ifndef _WIN32 +# include +#endif + +#include +#include +#ifndef _WIN32 +# include +# include +#endif +#ifdef __linux__ +# ifdef __dietlibc__ +# define _LINUX_SOURCE +# else +# include +# endif +# include +#endif + +#include "core.h" +#include "private/common.h" +#include "randombytes.h" +#include "randombytes_sysrandom.h" +#include "utils.h" + +#ifdef _WIN32 +/* `RtlGenRandom` is used over `CryptGenRandom` on Microsoft Windows based systems: + * - `CryptGenRandom` requires pulling in `CryptoAPI` which causes unnecessary + * memory overhead if this API is not being used for other purposes + * - `RtlGenRandom` is thus called directly instead. A detailed explanation + * can be found here: https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/ + * + * In spite of the disclaimer on the `RtlGenRandom` documentation page that was + * written back in the Windows XP days, this function is here to stay. The CRT + * function `rand_s()` directly depends on it, so touching it would break many + * applications released since Windows XP. + * + * Also note that Rust, Firefox and BoringSSL (thus, Google Chrome and everything + * based on Chromium) also depend on it, and that libsodium allows the RNG to be + * replaced without patching nor recompiling the library. + */ +# include +# define RtlGenRandom SystemFunction036 +# if defined(__cplusplus) +extern "C" +# endif +BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength); +# pragma comment(lib, "advapi32.lib") +#endif + +#if defined(__OpenBSD__) || defined(__CloudABI__) +# define HAVE_SAFE_ARC4RANDOM 1 +#endif + +#ifndef SSIZE_MAX +# define SSIZE_MAX (SIZE_MAX / 2 - 1) +#endif + +#ifdef HAVE_SAFE_ARC4RANDOM + +static uint32_t +randombytes_sysrandom(void) +{ + return arc4random(); +} + +static void +randombytes_sysrandom_stir(void) +{ +} + +static void +randombytes_sysrandom_buf(void * const buf, const size_t size) +{ + arc4random_buf(buf, size); +} + +static int +randombytes_sysrandom_close(void) +{ + return 0; +} + +#else /* __OpenBSD__ */ + +typedef struct SysRandom_ { + int random_data_source_fd; + int initialized; + int getrandom_available; +} SysRandom; + +static SysRandom stream = { + SODIUM_C99(.random_data_source_fd =) -1, + SODIUM_C99(.initialized =) 0, + SODIUM_C99(.getrandom_available =) 0 +}; + +#ifndef _WIN32 +static ssize_t +safe_read(const int fd, void * const buf_, size_t size) +{ + unsigned char *buf = (unsigned char *) buf_; + ssize_t readnb; + + assert(size > (size_t) 0U); + assert(size <= SSIZE_MAX); + do { + while ((readnb = read(fd, buf, size)) < (ssize_t) 0 && + (errno == EINTR || errno == EAGAIN)); /* LCOV_EXCL_LINE */ + if (readnb < (ssize_t) 0) { + return readnb; /* LCOV_EXCL_LINE */ + } + if (readnb == (ssize_t) 0) { + break; /* LCOV_EXCL_LINE */ + } + size -= (size_t) readnb; + buf += readnb; + } while (size > (ssize_t) 0); + + return (ssize_t) (buf - (unsigned char *) buf_); +} +#endif + +#ifndef _WIN32 +# if defined(__linux__) && !defined(USE_BLOCKING_RANDOM) && !defined(NO_BLOCKING_RANDOM_POLL) +static int +randombytes_block_on_dev_random(void) +{ + struct pollfd pfd; + int fd; + int pret; + + fd = open("/dev/random", O_RDONLY); + if (fd == -1) { + return 0; + } + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + do { + pret = poll(&pfd, 1, -1); + } while (pret < 0 && (errno == EINTR || errno == EAGAIN)); + if (pret != 1) { + (void) close(fd); + errno = EIO; + return -1; + } + return close(fd); +} +# endif + +static int +randombytes_sysrandom_random_dev_open(void) +{ +/* LCOV_EXCL_START */ + struct stat st; + static const char *devices[] = { +# ifndef USE_BLOCKING_RANDOM + "/dev/urandom", +# endif + "/dev/random", NULL + }; + const char **device = devices; + int fd; + +# if defined(__linux__) && !defined(USE_BLOCKING_RANDOM) && !defined(NO_BLOCKING_RANDOM_POLL) + if (randombytes_block_on_dev_random() != 0) { + return -1; + } +# endif + do { + fd = open(*device, O_RDONLY); + if (fd != -1) { + if (fstat(fd, &st) == 0 && +# ifdef __COMPCERT__ + 1 +# elif defined(S_ISNAM) + (S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode)) +# else + S_ISCHR(st.st_mode) +# endif + ) { +# if defined(F_SETFD) && defined(FD_CLOEXEC) + (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); +# endif + return fd; + } + (void) close(fd); + } else if (errno == EINTR) { + continue; + } + device++; + } while (*device != NULL); + + errno = EIO; + return -1; +/* LCOV_EXCL_STOP */ +} + +# if defined(__dietlibc__) || (defined(SYS_getrandom) && defined(__NR_getrandom)) +static int +_randombytes_linux_getrandom(void * const buf, const size_t size) +{ + int readnb; + + assert(size <= 256U); + do { +# ifdef __dietlibc__ + readnb = getrandom(buf, size, 0); +# else + readnb = syscall(SYS_getrandom, buf, (int) size, 0); +# endif + } while (readnb < 0 && (errno == EINTR || errno == EAGAIN)); + + return (readnb == (int) size) - 1; +} + +static int +randombytes_linux_getrandom(void * const buf_, size_t size) +{ + unsigned char *buf = (unsigned char *) buf_; + size_t chunk_size = 256U; + + do { + if (size < chunk_size) { + chunk_size = size; + assert(chunk_size > (size_t) 0U); + } + if (_randombytes_linux_getrandom(buf, chunk_size) != 0) { + return -1; + } + size -= chunk_size; + buf += chunk_size; + } while (size > (size_t) 0U); + + return 0; +} +# endif + +static void +randombytes_sysrandom_init(void) +{ + const int errno_save = errno; + +# if defined(SYS_getrandom) && defined(__NR_getrandom) + { + unsigned char fodder[16]; + + if (randombytes_linux_getrandom(fodder, sizeof fodder) == 0) { + stream.getrandom_available = 1; + errno = errno_save; + return; + } + stream.getrandom_available = 0; + } +# endif + + if ((stream.random_data_source_fd = + randombytes_sysrandom_random_dev_open()) == -1) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + errno = errno_save; +} + +#else /* _WIN32 */ + +static void +randombytes_sysrandom_init(void) +{ +} +#endif + +static void +randombytes_sysrandom_stir(void) +{ + if (stream.initialized == 0) { + randombytes_sysrandom_init(); + stream.initialized = 1; + } +} + +static void +randombytes_sysrandom_stir_if_needed(void) +{ + if (stream.initialized == 0) { + randombytes_sysrandom_stir(); + } +} + +static int +randombytes_sysrandom_close(void) +{ + int ret = -1; + +#ifndef _WIN32 + if (stream.random_data_source_fd != -1 && + close(stream.random_data_source_fd) == 0) { + stream.random_data_source_fd = -1; + stream.initialized = 0; + ret = 0; + } +# if defined(SYS_getrandom) && defined(__NR_getrandom) + if (stream.getrandom_available != 0) { + ret = 0; + } +# endif +#else /* _WIN32 */ + if (stream.initialized != 0) { + stream.initialized = 0; + ret = 0; + } +#endif + return ret; +} + +static void +randombytes_sysrandom_buf(void * const buf, const size_t size) +{ + randombytes_sysrandom_stir_if_needed(); +#if defined(ULONG_LONG_MAX) && defined(SIZE_MAX) +# if SIZE_MAX > ULONG_LONG_MAX + /* coverity[result_independent_of_operands] */ + assert(size <= ULONG_LONG_MAX); +# endif +#endif +#ifndef _WIN32 +# if defined(SYS_getrandom) && defined(__NR_getrandom) + if (stream.getrandom_available != 0) { + if (randombytes_linux_getrandom(buf, size) != 0) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + return; + } +# endif + if (stream.random_data_source_fd == -1 || + safe_read(stream.random_data_source_fd, buf, size) != (ssize_t) size) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#else + COMPILER_ASSERT(randombytes_BYTES_MAX <= 0xffffffffUL); + if (size > (size_t) 0xffffffffUL) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + if (! RtlGenRandom((PVOID) buf, (ULONG) size)) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#endif +} + +static uint32_t +randombytes_sysrandom(void) +{ + uint32_t r; + + randombytes_sysrandom_buf(&r, sizeof r); + + return r; +} + +#endif /* __OpenBSD__ */ + +static const char * +randombytes_sysrandom_implementation_name(void) +{ + return "sysrandom"; +} + +struct randombytes_implementation randombytes_sysrandom_implementation = { + SODIUM_C99(.implementation_name =) randombytes_sysrandom_implementation_name, + SODIUM_C99(.random =) randombytes_sysrandom, + SODIUM_C99(.stir =) randombytes_sysrandom_stir, + SODIUM_C99(.uniform =) NULL, + SODIUM_C99(.buf =) randombytes_sysrandom_buf, + SODIUM_C99(.close =) randombytes_sysrandom_close +}; diff --git a/libs/libsodium/src/sodium/codecs.c b/libs/libsodium/src/sodium/codecs.c new file mode 100644 index 0000000000..77fa464cc4 --- /dev/null +++ b/libs/libsodium/src/sodium/codecs.c @@ -0,0 +1,333 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "utils.h" + +/* Derived from original code by CodesInChaos */ +char * +sodium_bin2hex(char *const hex, const size_t hex_maxlen, + const unsigned char *const bin, const size_t bin_len) +{ + size_t i = (size_t) 0U; + unsigned int x; + int b; + int c; + + if (bin_len >= SIZE_MAX / 2 || hex_maxlen <= bin_len * 2U) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + while (i < bin_len) { + c = bin[i] & 0xf; + b = bin[i] >> 4; + x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 | + (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U)); + hex[i * 2U] = (char) x; + x >>= 8; + hex[i * 2U + 1U] = (char) x; + i++; + } + hex[i * 2U] = 0U; + + return hex; +} + +int +sodium_hex2bin(unsigned char *const bin, const size_t bin_maxlen, + const char *const hex, const size_t hex_len, + const char *const ignore, size_t *const bin_len, + const char **const hex_end) +{ + size_t bin_pos = (size_t) 0U; + size_t hex_pos = (size_t) 0U; + int ret = 0; + unsigned char c; + unsigned char c_acc = 0U; + unsigned char c_alpha0, c_alpha; + unsigned char c_num0, c_num; + unsigned char c_val; + unsigned char state = 0U; + + while (hex_pos < hex_len) { + c = (unsigned char) hex[hex_pos]; + c_num = c ^ 48U; + c_num0 = (c_num - 10U) >> 8; + c_alpha = (c & ~32U) - 55U; + c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8; + if ((c_num0 | c_alpha0) == 0U) { + if (ignore != NULL && state == 0U && strchr(ignore, c) != NULL) { + hex_pos++; + continue; + } + break; + } + c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha); + if (bin_pos >= bin_maxlen) { + ret = -1; + errno = ERANGE; + break; + } + if (state == 0U) { + c_acc = c_val * 16U; + } else { + bin[bin_pos++] = c_acc | c_val; + } + state = ~state; + hex_pos++; + } + if (state != 0U) { + hex_pos--; + errno = EINVAL; + ret = -1; + } + if (ret != 0) { + bin_pos = (size_t) 0U; + } + if (hex_end != NULL) { + *hex_end = &hex[hex_pos]; + } else if (hex_pos != hex_len) { + errno = EINVAL; + ret = -1; + } + if (bin_len != NULL) { + *bin_len = bin_pos; + } + return ret; +} + +/* + * Some macros for constant-time comparisons. These work over values in + * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true". + * + * Original code by Thomas Pornin. + */ +#define EQ(x, y) \ + ((((0U - ((unsigned int) (x) ^ (unsigned int) (y))) >> 8) & 0xFF) ^ 0xFF) +#define GT(x, y) ((((unsigned int) (y) - (unsigned int) (x)) >> 8) & 0xFF) +#define GE(x, y) (GT(y, x) ^ 0xFF) +#define LT(x, y) GT(y, x) +#define LE(x, y) GE(y, x) + +static int +b64_byte_to_char(unsigned int x) +{ + return (LT(x, 26) & (x + 'A')) | + (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | + (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') | + (EQ(x, 63) & '/'); +} + +static unsigned int +b64_char_to_byte(int c) +{ + const unsigned int x = + (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | + (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | + (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) | + (EQ(c, '/') & 63); + + return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); +} + +static int +b64_byte_to_urlsafe_char(unsigned int x) +{ + return (LT(x, 26) & (x + 'A')) | + (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) | + (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '-') | + (EQ(x, 63) & '_'); +} + +static unsigned int +b64_urlsafe_char_to_byte(int c) +{ + const unsigned x = + (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) | + (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) | + (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '-') & 62) | + (EQ(c, '_') & 63); + + return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF)); +} + + +#define VARIANT_NO_PADDING_MASK 0x2U +#define VARIANT_URLSAFE_MASK 0x4U + +static void +sodium_base64_check_variant(const int variant) +{ + if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) { + sodium_misuse(); + } +} + +size_t +sodium_base64_encoded_len(const size_t bin_len, const int variant) +{ + sodium_base64_check_variant(variant); + + return sodium_base64_ENCODED_LEN(bin_len, variant); +} + +char * +sodium_bin2base64(char * const b64, const size_t b64_maxlen, + const unsigned char * const bin, const size_t bin_len, + const int variant) +{ + size_t acc_len = (size_t) 0; + size_t b64_len; + size_t b64_pos = (size_t) 0; + size_t bin_pos = (size_t) 0; + size_t nibbles; + size_t remainder; + unsigned int acc = 0U; + + sodium_base64_check_variant(variant); + nibbles = bin_len / 3; + remainder = bin_len - 3 * nibbles; + b64_len = nibbles * 4; + if (remainder != 0) { + if ((((unsigned int) variant) & VARIANT_NO_PADDING_MASK) == 0U) { + b64_len += 4; + } else { + b64_len += 2 + (remainder >> 1); + } + } + if (b64_maxlen <= b64_len) { + sodium_misuse(); + } + if ((((unsigned int) variant) & VARIANT_URLSAFE_MASK) != 0U) { + while (bin_pos < bin_len) { + acc = (acc << 8) + bin[bin_pos++]; + acc_len += 8; + while (acc_len >= 6) { + acc_len -= 6; + b64[b64_pos++] = (char) b64_byte_to_urlsafe_char((acc >> acc_len) & 0x3F); + } + } + if (acc_len > 0) { + b64[b64_pos++] = (char) b64_byte_to_urlsafe_char((acc << (6 - acc_len)) & 0x3F); + } + } else { + while (bin_pos < bin_len) { + acc = (acc << 8) + bin[bin_pos++]; + acc_len += 8; + while (acc_len >= 6) { + acc_len -= 6; + b64[b64_pos++] = (char) b64_byte_to_char((acc >> acc_len) & 0x3F); + } + } + if (acc_len > 0) { + b64[b64_pos++] = (char) b64_byte_to_char((acc << (6 - acc_len)) & 0x3F); + } + } + assert(b64_pos <= b64_len); + while (b64_pos < b64_len) { + b64[b64_pos++] = '='; + } + do { + b64[b64_pos++] = 0U; + } while (b64_pos < b64_maxlen); + + return b64; +} + +static int +_sodium_base642bin_skip_padding(const char * const b64, const size_t b64_len, + size_t * const b64_pos_p, + const char * const ignore, size_t padding_len) +{ + int c; + + while (padding_len > 0) { + if (*b64_pos_p >= b64_len) { + errno = ERANGE; + return -1; + } + c = b64[*b64_pos_p]; + if (c == '=') { + padding_len--; + } else if (ignore == NULL || strchr(ignore, c) == NULL) { + errno = EINVAL; + return -1; + } + (*b64_pos_p)++; + } + return 0; +} + +int +sodium_base642bin(unsigned char * const bin, const size_t bin_maxlen, + const char * const b64, const size_t b64_len, + const char * const ignore, size_t * const bin_len, + const char ** const b64_end, const int variant) +{ + size_t acc_len = (size_t) 0; + size_t b64_pos = (size_t) 0; + size_t bin_pos = (size_t) 0; + int is_urlsafe; + int ret = 0; + unsigned int acc = 0U; + unsigned int d; + char c; + + sodium_base64_check_variant(variant); + is_urlsafe = ((unsigned int) variant) & VARIANT_URLSAFE_MASK; + while (b64_pos < b64_len) { + c = b64[b64_pos]; + if (is_urlsafe) { + d = b64_urlsafe_char_to_byte(c); + } else { + d = b64_char_to_byte(c); + } + if (d == 0xFF) { + if (ignore != NULL && strchr(ignore, c) != NULL) { + b64_pos++; + continue; + } + break; + } + acc = (acc << 6) + d; + acc_len += 6; + if (acc_len >= 8) { + acc_len -= 8; + if (bin_pos >= bin_maxlen) { + errno = ERANGE; + ret = -1; + break; + } + bin[bin_pos++] = (acc >> acc_len) & 0xFF; + } + b64_pos++; + } + if (acc_len > 4U || (acc & ((1U << acc_len) - 1U)) != 0U) { + ret = -1; + } else if (ret == 0 && + (((unsigned int) variant) & VARIANT_NO_PADDING_MASK) == 0U) { + ret = _sodium_base642bin_skip_padding(b64, b64_len, &b64_pos, ignore, + acc_len / 2); + } + if (ret != 0) { + bin_pos = (size_t) 0U; + } else if (ignore != NULL) { + while (b64_pos < b64_len && strchr(ignore, b64[b64_pos]) != NULL) { + b64_pos++; + } + } + if (b64_end != NULL) { + *b64_end = &b64[b64_pos]; + } else if (b64_pos != b64_len) { + errno = EINVAL; + ret = -1; + } + if (bin_len != NULL) { + *bin_len = bin_pos; + } + return ret; +} diff --git a/libs/libsodium/src/sodium/core.c b/libs/libsodium/src/sodium/core.c new file mode 100644 index 0000000000..1ac29d09c8 --- /dev/null +++ b/libs/libsodium/src/sodium/core.c @@ -0,0 +1,231 @@ + +#include +#include +#include +#include +#ifdef _WIN32 +# include +#elif defined(HAVE_PTHREAD) +# include +#endif + +#include "core.h" +#include "crypto_generichash.h" +#include "crypto_onetimeauth.h" +#include "crypto_scalarmult.h" +#include "crypto_stream_chacha20.h" +#include "crypto_stream_salsa20.h" +#include "randombytes.h" +#include "runtime.h" +#include "utils.h" +#include "private/implementations.h" +#include "private/mutex.h" + +#if !defined(_MSC_VER) && 0 +# warning *** This is unstable, untested, development code. +# warning It might not compile. It might not work as expected. +# warning It might be totally insecure. +# warning Do not use this in production. +# warning Use releases available at https://download.libsodium.org/libsodium/releases/ instead. +# warning Alternatively, use the "stable" branch in the git repository. +#endif + +#if !defined(_MSC_VER) && (!defined(CONFIGURED) || CONFIGURED != 1) +# warning *** The library is being compiled using an undocumented method. +# warning This is not supported. It has not been tested, it might not +# warning work as expected, and performance is likely to be suboptimal. +#endif + +static volatile int initialized; +static volatile int locked; + +int +sodium_init(void) +{ + if (sodium_crit_enter() != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + if (initialized != 0) { + if (sodium_crit_leave() != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + return 1; + } + _sodium_runtime_get_cpu_features(); + randombytes_stir(); + _sodium_alloc_init(); + _crypto_pwhash_argon2_pick_best_implementation(); + _crypto_generichash_blake2b_pick_best_implementation(); + _crypto_onetimeauth_poly1305_pick_best_implementation(); + _crypto_scalarmult_curve25519_pick_best_implementation(); + _crypto_stream_chacha20_pick_best_implementation(); + _crypto_stream_salsa20_pick_best_implementation(); + initialized = 1; + if (sodium_crit_leave() != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; +} + +#ifdef _WIN32 + +static CRITICAL_SECTION _sodium_lock; +static volatile LONG _sodium_lock_initialized; + +int +_sodium_crit_init(void) +{ + LONG status = 0L; + + while ((status = InterlockedCompareExchange(&_sodium_lock_initialized, + 1L, 0L)) == 1L) { + Sleep(0); + } + + switch (status) { + case 0L: + InitializeCriticalSection(&_sodium_lock); + return InterlockedExchange(&_sodium_lock_initialized, 2L) == 1L ? 0 : -1; + case 2L: + return 0; + default: /* should never be reached */ + return -1; + } +} + +int +sodium_crit_enter(void) +{ + if (_sodium_crit_init() != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + EnterCriticalSection(&_sodium_lock); + assert(locked == 0); + locked = 1; + + return 0; +} + +int +sodium_crit_leave(void) +{ + if (locked == 0) { +# ifdef EPERM + errno = EPERM; +# endif + return -1; + } + locked = 0; + LeaveCriticalSection(&_sodium_lock); + + return 0; +} + +#elif defined(HAVE_PTHREAD) && !defined(__EMSCRIPTEN__) + +static pthread_mutex_t _sodium_lock = PTHREAD_MUTEX_INITIALIZER; + +int +sodium_crit_enter(void) +{ + int ret; + + if ((ret = pthread_mutex_lock(&_sodium_lock)) == 0) { + assert(locked == 0); + locked = 1; + } + return ret; +} + +int +sodium_crit_leave(void) +{ + int ret; + + if (locked == 0) { +# ifdef EPERM + errno = EPERM; +# endif + return -1; + } + locked = 0; + + return pthread_mutex_unlock(&_sodium_lock); +} + +#elif defined(HAVE_ATOMIC_OPS) && !defined(__EMSCRIPTEN__) && !defined(__native_client__) + +static volatile int _sodium_lock; + +int +sodium_crit_enter(void) +{ +# ifdef HAVE_NANOSLEEP + struct timespec q; + memset(&q, 0, sizeof q); +# endif + while (__sync_lock_test_and_set(&_sodium_lock, 1) != 0) { +# ifdef HAVE_NANOSLEEP + (void) nanosleep(&q, NULL); +# elif defined(__x86_64__) || defined(__i386__) + __asm__ __volatile__ ("pause"); +# endif + } + return 0; +} + +int +sodium_crit_leave(void) +{ + __sync_lock_release(&_sodium_lock); + + return 0; +} + +#else + +int +sodium_crit_enter(void) +{ + return 0; +} + +int +sodium_crit_leave(void) +{ + return 0; +} + +#endif + +static void (*_misuse_handler)(void); + +void +sodium_misuse(void) +{ + void (*handler)(void); + + (void) sodium_crit_leave(); + if (sodium_crit_enter() == 0) { + handler = _misuse_handler; + if (handler != NULL) { + handler(); + } + } +/* LCOV_EXCL_START */ + abort(); +} +/* LCOV_EXCL_STOP */ + +int +sodium_set_misuse_handler(void (*handler)(void)) +{ + if (sodium_crit_enter() != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + _misuse_handler = handler; + if (sodium_crit_leave() != 0) { + return -1; /* LCOV_EXCL_LINE */ + } + return 0; +} diff --git a/libs/libsodium/src/sodium/runtime.c b/libs/libsodium/src/sodium/runtime.c new file mode 100644 index 0000000000..ba1000f4dc --- /dev/null +++ b/libs/libsodium/src/sodium/runtime.c @@ -0,0 +1,286 @@ +#include +#include +#ifdef HAVE_ANDROID_GETCPUFEATURES +# include +#endif + +#include "private/common.h" +#include "runtime.h" + +typedef struct CPUFeatures_ { + int initialized; + int has_neon; + int has_sse2; + int has_sse3; + int has_ssse3; + int has_sse41; + int has_avx; + int has_avx2; + int has_avx512f; + int has_pclmul; + int has_aesni; + int has_rdrand; +} CPUFeatures; + +static CPUFeatures _cpu_features; + +#define CPUID_EBX_AVX2 0x00000020 +#define CPUID_EBX_AVX512F 0x00010000 + +#define CPUID_ECX_SSE3 0x00000001 +#define CPUID_ECX_PCLMUL 0x00000002 +#define CPUID_ECX_SSSE3 0x00000200 +#define CPUID_ECX_SSE41 0x00080000 +#define CPUID_ECX_AESNI 0x02000000 +#define CPUID_ECX_XSAVE 0x04000000 +#define CPUID_ECX_OSXSAVE 0x08000000 +#define CPUID_ECX_AVX 0x10000000 +#define CPUID_ECX_RDRAND 0x40000000 + +#define CPUID_EDX_SSE2 0x04000000 + +#define XCR0_SSE 0x00000002 +#define XCR0_AVX 0x00000004 + +static int +_sodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features) +{ +#ifndef __arm__ + cpu_features->has_neon = 0; + return -1; +#else +# ifdef __APPLE__ +# ifdef __ARM_NEON__ + cpu_features->has_neon = 1; +# else + cpu_features->has_neon = 0; +# endif +# elif defined(HAVE_ANDROID_GETCPUFEATURES) && \ + defined(ANDROID_CPU_ARM_FEATURE_NEON) + cpu_features->has_neon = + (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0; +# else + cpu_features->has_neon = 0; +# endif + return 0; +#endif +} + +static void +_cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type) +{ +#if defined(_MSC_VER) && \ + (defined(_M_X64) || defined(_M_AMD64) || defined(_M_IX86)) + __cpuid((int *) cpu_info, cpu_info_type); +#elif defined(HAVE_CPUID) + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; +# ifdef __i386__ + __asm__ __volatile__( + "pushfl; pushfl; " + "popl %0; " + "movl %0, %1; xorl %2, %0; " + "pushl %0; " + "popfl; pushfl; popl %0; popfl" + : "=&r"(cpu_info[0]), "=&r"(cpu_info[1]) + : "i"(0x200000)); + if (((cpu_info[0] ^ cpu_info[1]) & 0x200000) == 0x0) { + return; /* LCOV_EXCL_LINE */ + } +# endif +# ifdef __i386__ + __asm__ __volatile__("xchgl %%ebx, %k1; cpuid; xchgl %%ebx, %k1" + : "=a"(cpu_info[0]), "=&r"(cpu_info[1]), + "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "0"(cpu_info_type), "2"(0U)); +# elif defined(__x86_64__) + __asm__ __volatile__("xchgq %%rbx, %q1; cpuid; xchgq %%rbx, %q1" + : "=a"(cpu_info[0]), "=&r"(cpu_info[1]), + "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "0"(cpu_info_type), "2"(0U)); +# else + __asm__ __volatile__("cpuid" + : "=a"(cpu_info[0]), "=b"(cpu_info[1]), + "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "0"(cpu_info_type), "2"(0U)); +# endif +#else + (void) cpu_info_type; + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; +#endif +} + +static int +_sodium_runtime_intel_cpu_features(CPUFeatures * const cpu_features) +{ + unsigned int cpu_info[4]; + unsigned int id; + + _cpuid(cpu_info, 0x0); + if ((id = cpu_info[0]) == 0U) { + return -1; /* LCOV_EXCL_LINE */ + } + _cpuid(cpu_info, 0x00000001); +#ifdef HAVE_EMMINTRIN_H + cpu_features->has_sse2 = ((cpu_info[3] & CPUID_EDX_SSE2) != 0x0); +#else + cpu_features->has_sse2 = 0; +#endif + +#ifdef HAVE_PMMINTRIN_H + cpu_features->has_sse3 = ((cpu_info[2] & CPUID_ECX_SSE3) != 0x0); +#else + cpu_features->has_sse3 = 0; +#endif + +#ifdef HAVE_TMMINTRIN_H + cpu_features->has_ssse3 = ((cpu_info[2] & CPUID_ECX_SSSE3) != 0x0); +#else + cpu_features->has_ssse3 = 0; +#endif + +#ifdef HAVE_SMMINTRIN_H + cpu_features->has_sse41 = ((cpu_info[2] & CPUID_ECX_SSE41) != 0x0); +#else + cpu_features->has_sse41 = 0; +#endif + + cpu_features->has_avx = 0; +#ifdef HAVE_AVXINTRIN_H + if ((cpu_info[2] & (CPUID_ECX_AVX | CPUID_ECX_XSAVE | CPUID_ECX_OSXSAVE)) == + (CPUID_ECX_AVX | CPUID_ECX_XSAVE | CPUID_ECX_OSXSAVE)) { + uint32_t xcr0 = 0U; +# if defined(HAVE__XGETBV) || \ + (defined(_MSC_VER) && defined(_XCR_XFEATURE_ENABLED_MASK) && _MSC_FULL_VER >= 160040219) + xcr0 = (uint32_t) _xgetbv(0); +# elif defined(_MSC_VER) && defined(_M_IX86) + __asm { + xor ecx, ecx + _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0 + mov xcr0, eax + } +# elif defined(HAVE_AVX_ASM) + __asm__ __volatile__(".byte 0x0f, 0x01, 0xd0" /* XGETBV */ + : "=a"(xcr0) + : "c"((uint32_t) 0U) + : "%edx"); +# endif + if ((xcr0 & (XCR0_SSE | XCR0_AVX)) == (XCR0_SSE | XCR0_AVX)) { + cpu_features->has_avx = 1; + } + } +#endif + + cpu_features->has_avx2 = 0; +#ifdef HAVE_AVX2INTRIN_H + if (cpu_features->has_avx) { + unsigned int cpu_info7[4]; + + _cpuid(cpu_info7, 0x00000007); + cpu_features->has_avx2 = ((cpu_info7[1] & CPUID_EBX_AVX2) != 0x0); + } +#endif + + cpu_features->has_avx512f = 0; +#ifdef HAVE_AVX512FINTRIN_H + if (cpu_features->has_avx2) { + unsigned int cpu_info7[4]; + + _cpuid(cpu_info7, 0x00000007); + cpu_features->has_avx512f = ((cpu_info7[1] & CPUID_EBX_AVX512F) != 0x0); + } +#endif + +#ifdef HAVE_WMMINTRIN_H + cpu_features->has_pclmul = ((cpu_info[2] & CPUID_ECX_PCLMUL) != 0x0); + cpu_features->has_aesni = ((cpu_info[2] & CPUID_ECX_AESNI) != 0x0); +#else + cpu_features->has_pclmul = 0; + cpu_features->has_aesni = 0; +#endif + +#ifdef HAVE_RDRAND + cpu_features->has_rdrand = ((cpu_info[2] & CPUID_ECX_RDRAND) != 0x0); +#else + cpu_features->has_rdrand = 0; +#endif + + return 0; +} + +int +_sodium_runtime_get_cpu_features(void) +{ + int ret = -1; + + ret &= _sodium_runtime_arm_cpu_features(&_cpu_features); + ret &= _sodium_runtime_intel_cpu_features(&_cpu_features); + _cpu_features.initialized = 1; + + return ret; +} + +int +sodium_runtime_has_neon(void) +{ + return _cpu_features.has_neon; +} + +int +sodium_runtime_has_sse2(void) +{ + return _cpu_features.has_sse2; +} + +int +sodium_runtime_has_sse3(void) +{ + return _cpu_features.has_sse3; +} + +int +sodium_runtime_has_ssse3(void) +{ + return _cpu_features.has_ssse3; +} + +int +sodium_runtime_has_sse41(void) +{ + return _cpu_features.has_sse41; +} + +int +sodium_runtime_has_avx(void) +{ + return _cpu_features.has_avx; +} + +int +sodium_runtime_has_avx2(void) +{ + return _cpu_features.has_avx2; +} + +int +sodium_runtime_has_avx512f(void) +{ + return _cpu_features.has_avx512f; +} + +int +sodium_runtime_has_pclmul(void) +{ + return _cpu_features.has_pclmul; +} + +int +sodium_runtime_has_aesni(void) +{ + return _cpu_features.has_aesni; +} + +int +sodium_runtime_has_rdrand(void) +{ + return _cpu_features.has_rdrand; +} diff --git a/libs/libsodium/src/sodium/utils.c b/libs/libsodium/src/sodium/utils.c new file mode 100644 index 0000000000..85aad29200 --- /dev/null +++ b/libs/libsodium/src/sodium/utils.c @@ -0,0 +1,737 @@ +#ifndef __STDC_WANT_LIB_EXT1__ +# define __STDC_WANT_LIB_EXT1__ 1 +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_MMAN_H +# include +#endif + +#ifdef _WIN32 +# include +# include +#else +# include +#endif + +#ifndef HAVE_C_VARARRAYS +# ifdef HAVE_ALLOCA_H +# include +# elif !defined(alloca) +# if defined(__GNUC__) +# define alloca __builtin_alloca +# elif defined _AIX +# define alloca __alloca +# elif defined _MSC_VER +# include +# define alloca _alloca +# else +# include +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +# endif +# endif +#endif + +#include "core.h" +#include "randombytes.h" +#include "utils.h" + +#ifndef ENOSYS +# define ENOSYS ENXIO +#endif + +#if defined(_WIN32) && \ + (!defined(WINAPI_FAMILY) || WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) +# define WINAPI_DESKTOP +#endif + +#define CANARY_SIZE 16U +#define GARBAGE_VALUE 0xdb + +#ifndef MAP_NOCORE +# define MAP_NOCORE 0 +#endif +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +# define MAP_ANON MAP_ANONYMOUS +#endif +#if defined(WINAPI_DESKTOP) || (defined(MAP_ANON) && defined(HAVE_MMAP)) || \ + defined(HAVE_POSIX_MEMALIGN) +# define HAVE_ALIGNED_MALLOC +#endif +#if defined(HAVE_MPROTECT) && \ + !(defined(PROT_NONE) && defined(PROT_READ) && defined(PROT_WRITE)) +# undef HAVE_MPROTECT +#endif +#if defined(HAVE_ALIGNED_MALLOC) && \ + (defined(WINAPI_DESKTOP) || defined(HAVE_MPROTECT)) +# define HAVE_PAGE_PROTECTION +#endif +#if !defined(MADV_DODUMP) && defined(MADV_CORE) +# define MADV_DODUMP MADV_CORE +# define MADV_DONTDUMP MADV_NOCORE +#endif + +static size_t page_size; +static unsigned char canary[CANARY_SIZE]; + +/* LCOV_EXCL_START */ +#ifdef HAVE_WEAK_SYMBOLS +__attribute__((weak)) void +_sodium_dummy_symbol_to_prevent_memzero_lto(void *const pnt, + const size_t len); +__attribute__((weak)) void +_sodium_dummy_symbol_to_prevent_memzero_lto(void *const pnt, + const size_t len) +{ + (void) pnt; /* LCOV_EXCL_LINE */ + (void) len; /* LCOV_EXCL_LINE */ +} +#endif +/* LCOV_EXCL_STOP */ + +void +sodium_memzero(void *const pnt, const size_t len) +{ +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + if (len > 0U && memset_s(pnt, (rsize_t) len, 0, (rsize_t) len) != 0) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif HAVE_WEAK_SYMBOLS + memset(pnt, 0, len); + _sodium_dummy_symbol_to_prevent_memzero_lto(pnt, len); +# ifdef HAVE_AMD64_ASM + __asm__ __volatile__ ("" : : "p"(pnt)); +# endif +#else + volatile unsigned char *volatile pnt_ = + (volatile unsigned char *volatile) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif +} + +void +sodium_stackzero(const size_t len) +{ +#ifdef HAVE_C_VARARRAYS + unsigned char fodder[len]; + sodium_memzero(fodder, len); +#elif HAVE_ALLOCA + sodium_memzero(alloca(len), len); +#endif +} + +#ifdef HAVE_WEAK_SYMBOLS +__attribute__((weak)) void +_sodium_dummy_symbol_to_prevent_memcmp_lto(const unsigned char *b1, + const unsigned char *b2, + const size_t len); +__attribute__((weak)) void +_sodium_dummy_symbol_to_prevent_memcmp_lto(const unsigned char *b1, + const unsigned char *b2, + const size_t len) +{ + (void) b1; + (void) b2; + (void) len; +} +#endif + +int +sodium_memcmp(const void *const b1_, const void *const b2_, size_t len) +{ +#ifdef HAVE_WEAK_SYMBOLS + const unsigned char *b1 = (const unsigned char *) b1_; + const unsigned char *b2 = (const unsigned char *) b2_; +#else + const volatile unsigned char *volatile b1 = + (const volatile unsigned char *volatile) b1_; + const volatile unsigned char *volatile b2 = + (const volatile unsigned char *volatile) b2_; +#endif + size_t i; + volatile unsigned char d = 0U; + +#if HAVE_WEAK_SYMBOLS + _sodium_dummy_symbol_to_prevent_memcmp_lto(b1, b2, len); +#endif + for (i = 0U; i < len; i++) { + d |= b1[i] ^ b2[i]; + } + return (1 & ((d - 1) >> 8)) - 1; +} + +#ifdef HAVE_WEAK_SYMBOLS +__attribute__((weak)) void +_sodium_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1, + const unsigned char *b2, + const size_t len); +__attribute__((weak)) void +_sodium_dummy_symbol_to_prevent_compare_lto(const unsigned char *b1, + const unsigned char *b2, + const size_t len) +{ + (void) b1; + (void) b2; + (void) len; +} +#endif + +int +sodium_compare(const unsigned char *b1_, const unsigned char *b2_, size_t len) +{ +#ifdef HAVE_WEAK_SYMBOLS + const unsigned char *b1 = b1_; + const unsigned char *b2 = b2_; +#else + const volatile unsigned char *volatile b1 = + (const volatile unsigned char *volatile) b1_; + const volatile unsigned char *volatile b2 = + (const volatile unsigned char *volatile) b2_; +#endif + size_t i; + volatile unsigned char gt = 0U; + volatile unsigned char eq = 1U; + uint16_t x1, x2; + +#if HAVE_WEAK_SYMBOLS + _sodium_dummy_symbol_to_prevent_compare_lto(b1, b2, len); +#endif + i = len; + while (i != 0U) { + i--; + x1 = b1[i]; + x2 = b2[i]; + gt |= ((x2 - x1) >> 8) & eq; + eq &= ((x2 ^ x1) - 1) >> 8; + } + return (int) (gt + gt + eq) - 1; +} + +int +sodium_is_zero(const unsigned char *n, const size_t nlen) +{ + size_t i; + volatile unsigned char d = 0U; + + for (i = 0U; i < nlen; i++) { + d |= n[i]; + } + return 1 & ((d - 1) >> 8); +} + +void +sodium_increment(unsigned char *n, const size_t nlen) +{ + size_t i = 0U; + uint_fast16_t c = 1U; + +#ifdef HAVE_AMD64_ASM + uint64_t t64, t64_2; + uint32_t t32; + + if (nlen == 12U) { + __asm__ __volatile__( + "xorq %[t64], %[t64] \n" + "xorl %[t32], %[t32] \n" + "stc \n" + "adcq %[t64], (%[out]) \n" + "adcl %[t32], 8(%[out]) \n" + : [t64] "=&r"(t64), [t32] "=&r"(t32) + : [out] "D"(n) + : "memory", "flags", "cc"); + return; + } else if (nlen == 24U) { + __asm__ __volatile__( + "movq $1, %[t64] \n" + "xorq %[t64_2], %[t64_2] \n" + "addq %[t64], (%[out]) \n" + "adcq %[t64_2], 8(%[out]) \n" + "adcq %[t64_2], 16(%[out]) \n" + : [t64] "=&r"(t64), [t64_2] "=&r"(t64_2) + : [out] "D"(n) + : "memory", "flags", "cc"); + return; + } else if (nlen == 8U) { + __asm__ __volatile__("incq (%[out]) \n" + : + : [out] "D"(n) + : "memory", "flags", "cc"); + return; + } +#endif + for (; i < nlen; i++) { + c += (uint_fast16_t) n[i]; + n[i] = (unsigned char) c; + c >>= 8; + } +} + +void +sodium_add(unsigned char *a, const unsigned char *b, const size_t len) +{ + size_t i = 0U; + uint_fast16_t c = 0U; + +#ifdef HAVE_AMD64_ASM + uint64_t t64, t64_2, t64_3; + uint32_t t32; + + if (len == 12U) { + __asm__ __volatile__( + "movq (%[in]), %[t64] \n" + "movl 8(%[in]), %[t32] \n" + "addq %[t64], (%[out]) \n" + "adcl %[t32], 8(%[out]) \n" + : [t64] "=&r"(t64), [t32] "=&r"(t32) + : [in] "S"(b), [out] "D"(a) + : "memory", "flags", "cc"); + return; + } else if (len == 24U) { + __asm__ __volatile__( + "movq (%[in]), %[t64] \n" + "movq 8(%[in]), %[t64_2] \n" + "movq 16(%[in]), %[t64_3] \n" + "addq %[t64], (%[out]) \n" + "adcq %[t64_2], 8(%[out]) \n" + "adcq %[t64_3], 16(%[out]) \n" + : [t64] "=&r"(t64), [t64_2] "=&r"(t64_2), [t64_3] "=&r"(t64_3) + : [in] "S"(b), [out] "D"(a) + : "memory", "flags", "cc"); + return; + } else if (len == 8U) { + __asm__ __volatile__( + "movq (%[in]), %[t64] \n" + "addq %[t64], (%[out]) \n" + : [t64] "=&r"(t64) + : [in] "S"(b), [out] "D"(a) + : "memory", "flags", "cc"); + return; + } +#endif + for (; i < len; i++) { + c += (uint_fast16_t) a[i] + (uint_fast16_t) b[i]; + a[i] = (unsigned char) c; + c >>= 8; + } +} + +int +_sodium_alloc_init(void) +{ +#ifdef HAVE_ALIGNED_MALLOC +# if defined(_SC_PAGESIZE) + long page_size_ = sysconf(_SC_PAGESIZE); + if (page_size_ > 0L) { + page_size = (size_t) page_size_; + } +# elif defined(WINAPI_DESKTOP) + SYSTEM_INFO si; + GetSystemInfo(&si); + page_size = (size_t) si.dwPageSize; +# endif + if (page_size < CANARY_SIZE || page_size < sizeof(size_t)) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } +#endif + randombytes_buf(canary, sizeof canary); + + return 0; +} + +int +sodium_mlock(void *const addr, const size_t len) +{ +#if defined(MADV_DONTDUMP) && defined(HAVE_MADVISE) + (void) madvise(addr, len, MADV_DONTDUMP); +#endif +#ifdef HAVE_MLOCK + return mlock(addr, len); +#elif defined(WINAPI_DESKTOP) + return -(VirtualLock(addr, len) == 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +int +sodium_munlock(void *const addr, const size_t len) +{ + sodium_memzero(addr, len); +#if defined(MADV_DODUMP) && defined(HAVE_MADVISE) + (void) madvise(addr, len, MADV_DODUMP); +#endif +#ifdef HAVE_MLOCK + return munlock(addr, len); +#elif defined(WINAPI_DESKTOP) + return -(VirtualUnlock(addr, len) == 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +static int +_mprotect_noaccess(void *ptr, size_t size) +{ +#ifdef HAVE_MPROTECT + return mprotect(ptr, size, PROT_NONE); +#elif defined(WINAPI_DESKTOP) + DWORD old; + return -(VirtualProtect(ptr, size, PAGE_NOACCESS, &old) == 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +static int +_mprotect_readonly(void *ptr, size_t size) +{ +#ifdef HAVE_MPROTECT + return mprotect(ptr, size, PROT_READ); +#elif defined(WINAPI_DESKTOP) + DWORD old; + return -(VirtualProtect(ptr, size, PAGE_READONLY, &old) == 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +static int +_mprotect_readwrite(void *ptr, size_t size) +{ +#ifdef HAVE_MPROTECT + return mprotect(ptr, size, PROT_READ | PROT_WRITE); +#elif defined(WINAPI_DESKTOP) + DWORD old; + return -(VirtualProtect(ptr, size, PAGE_READWRITE, &old) == 0); +#else + errno = ENOSYS; + return -1; +#endif +} + +#ifdef HAVE_ALIGNED_MALLOC + +__attribute__((noreturn)) static void +_out_of_bounds(void) +{ +# ifdef SIGSEGV + raise(SIGSEGV); +# elif defined(SIGKILL) + raise(SIGKILL); +# endif + abort(); /* not something we want any higher-level API to catch */ +} /* LCOV_EXCL_LINE */ + +static inline size_t +_page_round(const size_t size) +{ + const size_t page_mask = page_size - 1U; + + return (size + page_mask) & ~page_mask; +} + +static __attribute__((malloc)) unsigned char * +_alloc_aligned(const size_t size) +{ + void *ptr; + +# if defined(MAP_ANON) && defined(HAVE_MMAP) + if ((ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, -1, 0)) == + MAP_FAILED) { + ptr = NULL; /* LCOV_EXCL_LINE */ + } /* LCOV_EXCL_LINE */ +# elif defined(HAVE_POSIX_MEMALIGN) + if (posix_memalign(&ptr, page_size, size) != 0) { + ptr = NULL; /* LCOV_EXCL_LINE */ + } /* LCOV_EXCL_LINE */ +# elif defined(WINAPI_DESKTOP) + ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +# else +# error Bug +# endif + return (unsigned char *) ptr; +} + +static void +_free_aligned(unsigned char *const ptr, const size_t size) +{ +# if defined(MAP_ANON) && defined(HAVE_MMAP) + (void) munmap(ptr, size); +# elif defined(HAVE_POSIX_MEMALIGN) + free(ptr); +# elif defined(WINAPI_DESKTOP) + VirtualFree(ptr, 0U, MEM_RELEASE); +# else +# error Bug +#endif +} + +static unsigned char * +_unprotected_ptr_from_user_ptr(void *const ptr) +{ + uintptr_t unprotected_ptr_u; + unsigned char *canary_ptr; + size_t page_mask; + + canary_ptr = ((unsigned char *) ptr) - sizeof canary; + page_mask = page_size - 1U; + unprotected_ptr_u = ((uintptr_t) canary_ptr & (uintptr_t) ~page_mask); + if (unprotected_ptr_u <= page_size * 2U) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + return (unsigned char *) unprotected_ptr_u; +} + +#endif /* HAVE_ALIGNED_MALLOC */ + +#ifndef HAVE_ALIGNED_MALLOC +static __attribute__((malloc)) void * +_sodium_malloc(const size_t size) +{ + return malloc(size > (size_t) 0U ? size : (size_t) 1U); +} +#else +static __attribute__((malloc)) void * +_sodium_malloc(const size_t size) +{ + void *user_ptr; + unsigned char *base_ptr; + unsigned char *canary_ptr; + unsigned char *unprotected_ptr; + size_t size_with_canary; + size_t total_size; + size_t unprotected_size; + + if (size >= (size_t) SIZE_MAX - page_size * 4U) { + errno = ENOMEM; + return NULL; + } + if (page_size <= sizeof canary || page_size < sizeof unprotected_size) { + sodium_misuse(); /* LCOV_EXCL_LINE */ + } + size_with_canary = (sizeof canary) + size; + unprotected_size = _page_round(size_with_canary); + total_size = page_size + page_size + unprotected_size + page_size; + if ((base_ptr = _alloc_aligned(total_size)) == NULL) { + return NULL; /* LCOV_EXCL_LINE */ + } + unprotected_ptr = base_ptr + page_size * 2U; + _mprotect_noaccess(base_ptr + page_size, page_size); +# ifndef HAVE_PAGE_PROTECTION + memcpy(unprotected_ptr + unprotected_size, canary, sizeof canary); +# endif + _mprotect_noaccess(unprotected_ptr + unprotected_size, page_size); + sodium_mlock(unprotected_ptr, unprotected_size); + canary_ptr = + unprotected_ptr + _page_round(size_with_canary) - size_with_canary; + user_ptr = canary_ptr + sizeof canary; + memcpy(canary_ptr, canary, sizeof canary); + memcpy(base_ptr, &unprotected_size, sizeof unprotected_size); + _mprotect_readonly(base_ptr, page_size); + assert(_unprotected_ptr_from_user_ptr(user_ptr) == unprotected_ptr); + + return user_ptr; +} +#endif /* !HAVE_ALIGNED_MALLOC */ + +__attribute__((malloc)) void * +sodium_malloc(const size_t size) +{ + void *ptr; + + if ((ptr = _sodium_malloc(size)) == NULL) { + return NULL; + } + memset(ptr, (int) GARBAGE_VALUE, size); + + return ptr; +} + +__attribute__((malloc)) void * +sodium_allocarray(size_t count, size_t size) +{ + size_t total_size; + + if (count > (size_t) 0U && size >= (size_t) SIZE_MAX / count) { + errno = ENOMEM; + return NULL; + } + total_size = count * size; + + return sodium_malloc(total_size); +} + +#ifndef HAVE_ALIGNED_MALLOC +void +sodium_free(void *ptr) +{ + free(ptr); +} +#else +void +sodium_free(void *ptr) +{ + unsigned char *base_ptr; + unsigned char *canary_ptr; + unsigned char *unprotected_ptr; + size_t total_size; + size_t unprotected_size; + + if (ptr == NULL) { + return; + } + canary_ptr = ((unsigned char *) ptr) - sizeof canary; + unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr); + base_ptr = unprotected_ptr - page_size * 2U; + memcpy(&unprotected_size, base_ptr, sizeof unprotected_size); + total_size = page_size + page_size + unprotected_size + page_size; + _mprotect_readwrite(base_ptr, total_size); + if (sodium_memcmp(canary_ptr, canary, sizeof canary) != 0) { + _out_of_bounds(); + } +# ifndef HAVE_PAGE_PROTECTION + if (sodium_memcmp(unprotected_ptr + unprotected_size, canary, + sizeof canary) != 0) { + _out_of_bounds(); + } +# endif + sodium_munlock(unprotected_ptr, unprotected_size); + _free_aligned(base_ptr, total_size); +} +#endif /* HAVE_ALIGNED_MALLOC */ + +#ifndef HAVE_PAGE_PROTECTION +static int +_sodium_mprotect(void *ptr, int (*cb)(void *ptr, size_t size)) +{ + (void) ptr; + (void) cb; + errno = ENOSYS; + return -1; +} +#else +static int +_sodium_mprotect(void *ptr, int (*cb)(void *ptr, size_t size)) +{ + unsigned char *base_ptr; + unsigned char *unprotected_ptr; + size_t unprotected_size; + + unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr); + base_ptr = unprotected_ptr - page_size * 2U; + memcpy(&unprotected_size, base_ptr, sizeof unprotected_size); + + return cb(unprotected_ptr, unprotected_size); +} +#endif + +int +sodium_mprotect_noaccess(void *ptr) +{ + return _sodium_mprotect(ptr, _mprotect_noaccess); +} + +int +sodium_mprotect_readonly(void *ptr) +{ + return _sodium_mprotect(ptr, _mprotect_readonly); +} + +int +sodium_mprotect_readwrite(void *ptr) +{ + return _sodium_mprotect(ptr, _mprotect_readwrite); +} + +int +sodium_pad(size_t *padded_buflen_p, unsigned char *buf, + size_t unpadded_buflen, size_t blocksize, size_t max_buflen) +{ + unsigned char *tail; + size_t i; + size_t xpadlen; + size_t xpadded_len; + volatile unsigned char mask; + unsigned char barrier_mask; + + if (blocksize <= 0U) { + return -1; + } + xpadlen = blocksize - 1U; + if ((blocksize & (blocksize - 1U)) == 0U) { + xpadlen -= unpadded_buflen & (blocksize - 1U); + } else { + xpadlen -= unpadded_buflen % blocksize; + } + if ((size_t) SIZE_MAX - unpadded_buflen <= xpadlen) { + sodium_misuse(); + } + xpadded_len = unpadded_buflen + xpadlen; + if (xpadded_len >= max_buflen) { + return -1; + } + tail = &buf[xpadded_len]; + if (padded_buflen_p != NULL) { + *padded_buflen_p = xpadded_len + 1U; + } + mask = 0U; + for (i = 0; i < blocksize; i++) { + barrier_mask = (unsigned char) (((i ^ xpadlen) - 1U) >> 8); + tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask); + mask |= barrier_mask; + } + return 0; +} + +int +sodium_unpad(size_t *unpadded_buflen_p, const unsigned char *buf, + size_t padded_buflen, size_t blocksize) +{ + const unsigned char *tail; + unsigned char acc = 0U; + unsigned char c; + unsigned char valid = 0U; + volatile size_t pad_len = 0U; + size_t i; + size_t is_barrier; + + if (padded_buflen < blocksize || blocksize <= 0U) { + return -1; + } + tail = &buf[padded_buflen - 1U]; + + for (i = 0U; i < blocksize; i++) { + c = tail[-i]; + is_barrier = + (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U; + acc |= c; + pad_len |= i & (1U + ~is_barrier); + valid |= (unsigned char) is_barrier; + } + *unpadded_buflen_p = padded_buflen - 1U - pad_len; + + return (int) (valid - 1U); +} diff --git a/libs/libsodium/src/sodium/version.c b/libs/libsodium/src/sodium/version.c new file mode 100644 index 0000000000..4e584a6ea0 --- /dev/null +++ b/libs/libsodium/src/sodium/version.c @@ -0,0 +1,30 @@ + +#include "version.h" + +const char * +sodium_version_string(void) +{ + return SODIUM_VERSION_STRING; +} + +int +sodium_library_version_major(void) +{ + return SODIUM_LIBRARY_VERSION_MAJOR; +} + +int +sodium_library_version_minor(void) +{ + return SODIUM_LIBRARY_VERSION_MINOR; +} + +int +sodium_library_minimal(void) +{ +#ifdef SODIUM_LIBRARY_MINIMAL + return 1; +#else + return 0; +#endif +} diff --git a/libs/libsodium/src/stdafx.cxx b/libs/libsodium/src/stdafx.cxx new file mode 100644 index 0000000000..1647228cd0 --- /dev/null +++ b/libs/libsodium/src/stdafx.cxx @@ -0,0 +1,2 @@ + +#include "stdafx.h" \ No newline at end of file diff --git a/libs/libsodium/src/stdafx.h b/libs/libsodium/src/stdafx.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtox/docs/CHANGELOG.md b/libs/libtox/docs/CHANGELOG.md new file mode 100644 index 0000000000..e3275a16df --- /dev/null +++ b/libs/libtox/docs/CHANGELOG.md @@ -0,0 +1,450 @@ + + +## v0.1.10 + +### Merged PRs: + +- [#564](https://github.com/TokTok/c-toxcore/pull/564) Fix Windows build +- [#542](https://github.com/TokTok/c-toxcore/pull/542) Save bandwidth by moderating onion pinging + +## v0.1.9 + +### Merged PRs: + +- [#563](https://github.com/TokTok/c-toxcore/pull/563) Release v0.1.9 +- [#561](https://github.com/TokTok/c-toxcore/pull/561) Remove unused variable +- [#560](https://github.com/TokTok/c-toxcore/pull/560) Fix non-portable zeroing out of doubles +- [#559](https://github.com/TokTok/c-toxcore/pull/559) Fix theoretical memory leaks +- [#557](https://github.com/TokTok/c-toxcore/pull/557) Document inverted mutex lock/unlock. +- [#556](https://github.com/TokTok/c-toxcore/pull/556) Build tests on appveyor, the MSVC build, but don't run them yet. +- [#555](https://github.com/TokTok/c-toxcore/pull/555) Fold hstox tests into the general linux test. +- [#554](https://github.com/TokTok/c-toxcore/pull/554) Add a monolith_test that includes all toxcore sources. +- [#553](https://github.com/TokTok/c-toxcore/pull/553) Factor out strict_abi cmake code into a separate module. +- [#552](https://github.com/TokTok/c-toxcore/pull/552) Fix formatting and spelling in version-sync script. +- [#551](https://github.com/TokTok/c-toxcore/pull/551) Forbid undefined symbols in shared libraries. +- [#546](https://github.com/TokTok/c-toxcore/pull/546) Make variable names in file saving test less cryptic +- [#539](https://github.com/TokTok/c-toxcore/pull/539) Make OSX test failures fail the Travis CI build. +- [#537](https://github.com/TokTok/c-toxcore/pull/537) Fix TokTok/c-toxcore#535 +- [#534](https://github.com/TokTok/c-toxcore/pull/534) Fix markdown formatting +- [#530](https://github.com/TokTok/c-toxcore/pull/530) Implement missing TES constant functions. +- [#511](https://github.com/TokTok/c-toxcore/pull/511) Save bandwidth by avoiding superfluous Nodes Requests to peers already on the Close List +- [#506](https://github.com/TokTok/c-toxcore/pull/506) Add test case for title change +- [#498](https://github.com/TokTok/c-toxcore/pull/498) DHT refactoring +- [#487](https://github.com/TokTok/c-toxcore/pull/487) Split daemon's logging backends in separate modules +- [#468](https://github.com/TokTok/c-toxcore/pull/468) Test for memberlist not changing after changing own name +- [#449](https://github.com/TokTok/c-toxcore/pull/449) Use new encoding of `Maybe` in msgpack results. + +### Closed issues: + +- [#482](https://github.com/TokTok/c-toxcore/issues/482) CMake can't detect and compile ToxAV on OSX + +## v0.1.8 + +### Merged PRs: + +- [#538](https://github.com/TokTok/c-toxcore/pull/538) Reverting tox_loop PR changes +- [#536](https://github.com/TokTok/c-toxcore/pull/536) Release v0.1.8 +- [#526](https://github.com/TokTok/c-toxcore/pull/526) Add TOX_NOSPAM_SIZE to the public API. +- [#525](https://github.com/TokTok/c-toxcore/pull/525) Retry autotools tests the same way as cmake tests. +- [#524](https://github.com/TokTok/c-toxcore/pull/524) Reduce ctest timeout to 2 minutes from 5 minutes. +- [#512](https://github.com/TokTok/c-toxcore/pull/512) Add test for DHT pack_nodes and unpack_nodes +- [#504](https://github.com/TokTok/c-toxcore/pull/504) CMake: install bootstrapd if it is built +- [#488](https://github.com/TokTok/c-toxcore/pull/488) Save compiled Android artifacts after CircleCI builds. +- [#473](https://github.com/TokTok/c-toxcore/pull/473) Added missing includes: and +- [#335](https://github.com/TokTok/c-toxcore/pull/335) Implement tox_loop + +### Closed issues: + +- [#535](https://github.com/TokTok/c-toxcore/issues/535) OS X tests failing +- [#503](https://github.com/TokTok/c-toxcore/issues/503) Undefined functions: tox_pass_salt_length, tox_pass_key_length, tox_pass_encryption_extra_length +- [#456](https://github.com/TokTok/c-toxcore/issues/456) Tox.h doesn't expose the size of the nospam. +- [#411](https://github.com/TokTok/c-toxcore/issues/411) Reduce CTest timeout to 2 minutes + +## v0.1.7 + +### Merged PRs: + +- [#523](https://github.com/TokTok/c-toxcore/pull/523) Release v0.1.7 +- [#521](https://github.com/TokTok/c-toxcore/pull/521) Fix appveyor script: install curl from chocolatey. +- [#510](https://github.com/TokTok/c-toxcore/pull/510) Fix list malloc(0) bug +- [#509](https://github.com/TokTok/c-toxcore/pull/509) Fix network malloc(0) bug +- [#497](https://github.com/TokTok/c-toxcore/pull/497) Fix network +- [#496](https://github.com/TokTok/c-toxcore/pull/496) Fix Travis always succeeding despite tests failing +- [#491](https://github.com/TokTok/c-toxcore/pull/491) Add crypto_memzero for temp buffer +- [#490](https://github.com/TokTok/c-toxcore/pull/490) Move c_sleep to helpers.h and misc_tools.h +- [#486](https://github.com/TokTok/c-toxcore/pull/486) Remove empty line in Messenger.c +- [#483](https://github.com/TokTok/c-toxcore/pull/483) Make BUILD_TOXAV an option and fail if dependencies are missing +- [#481](https://github.com/TokTok/c-toxcore/pull/481) Remove dependency on strings.h +- [#480](https://github.com/TokTok/c-toxcore/pull/480) Use VLA macro +- [#479](https://github.com/TokTok/c-toxcore/pull/479) Fix pthreads in AppVeyor build +- [#471](https://github.com/TokTok/c-toxcore/pull/471) Remove statics used in onion comparison functions. +- [#461](https://github.com/TokTok/c-toxcore/pull/461) Replace part of network functions on platform-independent implementation +- [#452](https://github.com/TokTok/c-toxcore/pull/452) Add VLA compatibility macro for C89-ish compilers. + +### Closed issues: + +- [#474](https://github.com/TokTok/c-toxcore/issues/474) TOX_VERSION_PATCH isn't in sync with the version + +## v0.1.6 + +### Merged PRs: + +- [#460](https://github.com/TokTok/c-toxcore/pull/460) Release v0.1.6. +- [#459](https://github.com/TokTok/c-toxcore/pull/459) Add Android build to CI. +- [#454](https://github.com/TokTok/c-toxcore/pull/454) Add appveyor build for native windows tests. +- [#448](https://github.com/TokTok/c-toxcore/pull/448) Only retry failed tests on Circle CI instead of all. +- [#434](https://github.com/TokTok/c-toxcore/pull/434) Replace redundant packet type check in handler with assert. +- [#432](https://github.com/TokTok/c-toxcore/pull/432) Remove some static variables +- [#385](https://github.com/TokTok/c-toxcore/pull/385) Add platform-independent Socket and IP implementation + +### Closed issues: + +- [#415](https://github.com/TokTok/c-toxcore/issues/415) Set up a native windows build on appveyor + +## v0.1.5 + +### Merged PRs: + +- [#447](https://github.com/TokTok/c-toxcore/pull/447) Release v0.1.5. +- [#446](https://github.com/TokTok/c-toxcore/pull/446) Limit number of retries to 3. +- [#445](https://github.com/TokTok/c-toxcore/pull/445) Make Travis tests slightly more robust by re-running them. +- [#443](https://github.com/TokTok/c-toxcore/pull/443) Make building `DHT_bootstrap` in cmake optional. +- [#433](https://github.com/TokTok/c-toxcore/pull/433) Add tutorial and "danger: experimental" banner to README. +- [#431](https://github.com/TokTok/c-toxcore/pull/431) Update license headers and remove redundant file name comment. +- [#424](https://github.com/TokTok/c-toxcore/pull/424) Fixed the FreeBSD build failure due to the undefined MSG_NOSIGNAL. +- [#420](https://github.com/TokTok/c-toxcore/pull/420) Setup autotools to read .so version info from a separate file +- [#418](https://github.com/TokTok/c-toxcore/pull/418) Clarify how the autotools build is done on Travis. +- [#414](https://github.com/TokTok/c-toxcore/pull/414) Explicitly check if compiler supports C99 + +## v0.1.4 + +### Merged PRs: + +- [#422](https://github.com/TokTok/c-toxcore/pull/422) Release v0.1.4. +- [#410](https://github.com/TokTok/c-toxcore/pull/410) Fix NaCl build: tar was called incorrectly. +- [#409](https://github.com/TokTok/c-toxcore/pull/409) Clarify that the pass key `new` function can fail. +- [#407](https://github.com/TokTok/c-toxcore/pull/407) Don't use `git.depth=1` anymore. +- [#404](https://github.com/TokTok/c-toxcore/pull/404) Issue 404: semicolon not found +- [#403](https://github.com/TokTok/c-toxcore/pull/403) Warn on -pedantic, don't error yet. +- [#401](https://github.com/TokTok/c-toxcore/pull/401) Add logging callback to messenger_test. +- [#400](https://github.com/TokTok/c-toxcore/pull/400) Run windows tests but ignore their failures. +- [#398](https://github.com/TokTok/c-toxcore/pull/398) Portability Fixes +- [#397](https://github.com/TokTok/c-toxcore/pull/397) Replace make_quick_sort with qsort +- [#396](https://github.com/TokTok/c-toxcore/pull/396) Add an OSX build that doesn't run tests. +- [#394](https://github.com/TokTok/c-toxcore/pull/394) CMake: Add soversion to library files to generate proper symlinks +- [#393](https://github.com/TokTok/c-toxcore/pull/393) Set up autotools build to build against vanilla NaCl. +- [#392](https://github.com/TokTok/c-toxcore/pull/392) Check that TCP connections aren't dropped in callbacks. +- [#391](https://github.com/TokTok/c-toxcore/pull/391) Minor simplification in `file_seek` code. +- [#390](https://github.com/TokTok/c-toxcore/pull/390) Always kill invalid file transfers when receiving file controls. +- [#388](https://github.com/TokTok/c-toxcore/pull/388) Fix logging condition for IPv6 client timestamp updates. +- [#387](https://github.com/TokTok/c-toxcore/pull/387) Eliminate dead return statement. +- [#386](https://github.com/TokTok/c-toxcore/pull/386) Avoid accessing uninitialised memory in `net_crypto`. +- [#381](https://github.com/TokTok/c-toxcore/pull/381) Remove `TOX_DEBUG` and have asserts always enabled. + +### Closed issues: + +- [#378](https://github.com/TokTok/c-toxcore/issues/378) Replace all uses of `make_quick_sort` with `qsort` +- [#364](https://github.com/TokTok/c-toxcore/issues/364) Delete misc_tools.h after replacing its use by qsort. +- [#363](https://github.com/TokTok/c-toxcore/issues/363) Test against NaCl in addition to libsodium on Travis. + +## v0.1.3 + +### Merged PRs: + +- [#395](https://github.com/TokTok/c-toxcore/pull/395) Revert "Portability fixes" +- [#380](https://github.com/TokTok/c-toxcore/pull/380) Test a few cmake option combinations before the build. +- [#377](https://github.com/TokTok/c-toxcore/pull/377) Fix SSL verification in coveralls. +- [#376](https://github.com/TokTok/c-toxcore/pull/376) Bring back autotools instructions +- [#373](https://github.com/TokTok/c-toxcore/pull/373) Only fetch 1 revision from git during Travis builds. +- [#369](https://github.com/TokTok/c-toxcore/pull/369) Integrate with CircleCI to build artifacts in the future +- [#366](https://github.com/TokTok/c-toxcore/pull/366) Release v0.1.3. +- [#362](https://github.com/TokTok/c-toxcore/pull/362) Remove .cabal-sandbox option from tox-spectest find line. +- [#361](https://github.com/TokTok/c-toxcore/pull/361) Simplify integration as a third-party lib in cmake projects +- [#354](https://github.com/TokTok/c-toxcore/pull/354) Add secure memcmp and memzero implementation. +- [#324](https://github.com/TokTok/c-toxcore/pull/324) Do not compile and install DHT_bootstrap if it was disabled in configure +- [#297](https://github.com/TokTok/c-toxcore/pull/297) Portability fixes + +### Closed issues: + +- [#347](https://github.com/TokTok/c-toxcore/issues/347) Implement our own secure `memcmp` and `memzero` if libsodium isn't available +- [#319](https://github.com/TokTok/c-toxcore/issues/319) toxcore installs `DHT_bootstrap` even though `--disable-daemon` is passed to `./configure` + +## v0.1.2 + +### Merged PRs: + +- [#355](https://github.com/TokTok/c-toxcore/pull/355) Release v0.1.2 +- [#353](https://github.com/TokTok/c-toxcore/pull/353) Fix toxav use after free caused by premature MSI destruction +- [#346](https://github.com/TokTok/c-toxcore/pull/346) Avoid array out of bounds read in friend saving. +- [#344](https://github.com/TokTok/c-toxcore/pull/344) Remove unused get/set salt/key functions from toxencryptsave. +- [#343](https://github.com/TokTok/c-toxcore/pull/343) Wrap all sodium/nacl functions in crypto_core.c. +- [#341](https://github.com/TokTok/c-toxcore/pull/341) Add test to check if tox_new/tox_kill leaks. +- [#336](https://github.com/TokTok/c-toxcore/pull/336) Correct TES docs to reflect how many bytes functions actually require. +- [#333](https://github.com/TokTok/c-toxcore/pull/333) Use `tox_options_set_*` instead of direct member access. + +### Closed issues: + +- [#345](https://github.com/TokTok/c-toxcore/issues/345) Array out of bounds read in "save" function +- [#342](https://github.com/TokTok/c-toxcore/issues/342) Wrap all libsodium functions we use in toxcore in `crypto_core`. +- [#278](https://github.com/TokTok/c-toxcore/issues/278) ToxAV use-after-free bug + +## v0.1.1 + +### Merged PRs: + +- [#337](https://github.com/TokTok/c-toxcore/pull/337) Release v0.1.1 +- [#332](https://github.com/TokTok/c-toxcore/pull/332) Add test for encrypted savedata. +- [#330](https://github.com/TokTok/c-toxcore/pull/330) Strengthen the note about ABI compatibility in tox.h. +- [#328](https://github.com/TokTok/c-toxcore/pull/328) Drop the broken `TOX_VERSION_REQUIRE` macro. +- [#326](https://github.com/TokTok/c-toxcore/pull/326) Fix unresolved reference in toxencryptsave API docs. +- [#309](https://github.com/TokTok/c-toxcore/pull/309) Fixed attempt to join detached threads (fixes toxav test crash) +- [#306](https://github.com/TokTok/c-toxcore/pull/306) Add option to disable local peer discovery + +### Closed issues: + +- [#327](https://github.com/TokTok/c-toxcore/issues/327) The `TOX_VERSION_REQUIRE` macro is broken. +- [#221](https://github.com/TokTok/c-toxcore/issues/221) Option to disable local peer detection + +## v0.1.0 + +### Merged PRs: + +- [#325](https://github.com/TokTok/c-toxcore/pull/325) Fix Libs line in toxcore.pc pkg-config file. +- [#322](https://github.com/TokTok/c-toxcore/pull/322) Add compatibility pkg-config modules: libtoxcore, libtoxav. +- [#318](https://github.com/TokTok/c-toxcore/pull/318) Fix `--enable-logging` flag in autotools configure script. +- [#316](https://github.com/TokTok/c-toxcore/pull/316) Release 0.1.0. +- [#315](https://github.com/TokTok/c-toxcore/pull/315) Fix version compatibility test. +- [#314](https://github.com/TokTok/c-toxcore/pull/314) Fix off by one error in saving our own status message. +- [#313](https://github.com/TokTok/c-toxcore/pull/313) Fix padding being in the wrong place in `SAVED_FRIEND` struct +- [#312](https://github.com/TokTok/c-toxcore/pull/312) Conditionally enable non-portable assert on LP64. +- [#310](https://github.com/TokTok/c-toxcore/pull/310) Add apidsl file for toxencryptsave. +- [#307](https://github.com/TokTok/c-toxcore/pull/307) Clarify toxencryptsave documentation regarding buffer sizes +- [#305](https://github.com/TokTok/c-toxcore/pull/305) Fix static builds +- [#303](https://github.com/TokTok/c-toxcore/pull/303) Don't build nTox by default. +- [#301](https://github.com/TokTok/c-toxcore/pull/301) Renamed messenger functions, prepend `m_`. +- [#299](https://github.com/TokTok/c-toxcore/pull/299) net_crypto give handle_data_packet_helper a better name +- [#294](https://github.com/TokTok/c-toxcore/pull/294) Don't error on warnings by default + +### Closed issues: + +- [#317](https://github.com/TokTok/c-toxcore/issues/317) toxcore fails to build with autotools and debugging level enabled +- [#311](https://github.com/TokTok/c-toxcore/issues/311) Incorrect padding +- [#308](https://github.com/TokTok/c-toxcore/issues/308) Review TES and port it to APIDSL +- [#293](https://github.com/TokTok/c-toxcore/issues/293) error building on ubuntu 14.04 +- [#292](https://github.com/TokTok/c-toxcore/issues/292) Don't build nTox by default with CMake +- [#290](https://github.com/TokTok/c-toxcore/issues/290) User Feed +- [#266](https://github.com/TokTok/c-toxcore/issues/266) Support all levels listed in TOX_DHT_NAT_LEVEL +- [#216](https://github.com/TokTok/c-toxcore/issues/216) When v0.1 release? + +## v0.0.5 + +### Merged PRs: + +- [#289](https://github.com/TokTok/c-toxcore/pull/289) Version Patch v0.0.4 => v0.0.5 +- [#287](https://github.com/TokTok/c-toxcore/pull/287) Add CMake knobs to suppress building tests +- [#286](https://github.com/TokTok/c-toxcore/pull/286) Support float32 and float64 in msgpack type printer. +- [#285](https://github.com/TokTok/c-toxcore/pull/285) Mark `Tox_Options` struct as deprecated. +- [#284](https://github.com/TokTok/c-toxcore/pull/284) Add NONE enumerator to bit mask. +- [#281](https://github.com/TokTok/c-toxcore/pull/281) Made save format platform-independent +- [#277](https://github.com/TokTok/c-toxcore/pull/277) Fix a memory leak in hstox interface +- [#276](https://github.com/TokTok/c-toxcore/pull/276) Fix NULL pointer dereference in log calls +- [#275](https://github.com/TokTok/c-toxcore/pull/275) Fix a memory leak in GroupAV +- [#274](https://github.com/TokTok/c-toxcore/pull/274) Options in `new_messenger()` must never be null. +- [#271](https://github.com/TokTok/c-toxcore/pull/271) Convert to and from network byte order in set/get nospam. +- [#262](https://github.com/TokTok/c-toxcore/pull/262) Add ability to disable UDP hole punching + +### Closed issues: + +- [#254](https://github.com/TokTok/c-toxcore/issues/254) Add option to disable UDP hole punching +- [#215](https://github.com/TokTok/c-toxcore/issues/215) The current tox save format is non-portable +- [#205](https://github.com/TokTok/c-toxcore/issues/205) nospam value is reversed in array returned by `tox_self_get_address()` + +## v0.0.4 + +### Merged PRs: + +- [#272](https://github.com/TokTok/c-toxcore/pull/272) v0.0.4 +- [#265](https://github.com/TokTok/c-toxcore/pull/265) Disable -Wunused-but-set-variable compiler warning flag. +- [#261](https://github.com/TokTok/c-toxcore/pull/261) Work around Travis issue that causes build failures. +- [#260](https://github.com/TokTok/c-toxcore/pull/260) Support arbitrary video resolutions in av_test +- [#257](https://github.com/TokTok/c-toxcore/pull/257) Add decode/encode PlainText test support. +- [#256](https://github.com/TokTok/c-toxcore/pull/256) Add spectest to the cmake test suite. +- [#255](https://github.com/TokTok/c-toxcore/pull/255) Disable some gcc-specific warnings. +- [#249](https://github.com/TokTok/c-toxcore/pull/249) Use apidsl for the crypto_core API. +- [#248](https://github.com/TokTok/c-toxcore/pull/248) Remove new_nonce function in favour of random_nonce. +- [#224](https://github.com/TokTok/c-toxcore/pull/224) Add DHT_create_packet, an abstraction for DHT RPC packets + +## v0.0.3 + +### Merged PRs: + +- [#251](https://github.com/TokTok/c-toxcore/pull/251) Rename log levels to remove the extra "LOG" prefix. +- [#250](https://github.com/TokTok/c-toxcore/pull/250) Release v0.0.3. +- [#245](https://github.com/TokTok/c-toxcore/pull/245) Change packet kind enum to use hex constants. +- [#243](https://github.com/TokTok/c-toxcore/pull/243) Enable address sanitizer on the cmake build. +- [#242](https://github.com/TokTok/c-toxcore/pull/242) Remove assoc +- [#241](https://github.com/TokTok/c-toxcore/pull/241) Move log callback to options. +- [#233](https://github.com/TokTok/c-toxcore/pull/233) Enable all possible C compiler warning flags. +- [#230](https://github.com/TokTok/c-toxcore/pull/230) Move packing and unpacking DHT request packets to DHT module. +- [#228](https://github.com/TokTok/c-toxcore/pull/228) Remove unimplemented "time delta" parameter. +- [#227](https://github.com/TokTok/c-toxcore/pull/227) Compile as C++ for windows builds. +- [#223](https://github.com/TokTok/c-toxcore/pull/223) TravisCI shorten IRC message +- [#220](https://github.com/TokTok/c-toxcore/pull/220) toxav renaming: group.{h,c} -> groupav.{h,c} +- [#218](https://github.com/TokTok/c-toxcore/pull/218) Rename some internal "group chat" thing to "conference". +- [#212](https://github.com/TokTok/c-toxcore/pull/212) Convert series of `NET_PACKET_*` defines into a typedef enum +- [#196](https://github.com/TokTok/c-toxcore/pull/196) Update readme, moved the roadmap to a higher position +- [#193](https://github.com/TokTok/c-toxcore/pull/193) Remove duplicate tests: split tests part 2. + +### Closed issues: + +- [#40](https://github.com/TokTok/c-toxcore/issues/40) Stateless callbacks in toxcore's public API + +## v0.0.2 + +### Merged PRs: + +- [#207](https://github.com/TokTok/c-toxcore/pull/207) docs: correct instructions for cloning & harden agains repo name changes +- [#206](https://github.com/TokTok/c-toxcore/pull/206) Corrected libsodium tag +- [#204](https://github.com/TokTok/c-toxcore/pull/204) Error if format_test can't be executed. +- [#202](https://github.com/TokTok/c-toxcore/pull/202) Version Patch v0.0.2 +- [#190](https://github.com/TokTok/c-toxcore/pull/190) Install libraries with RPATH. +- [#189](https://github.com/TokTok/c-toxcore/pull/189) Use `socklen_t` instead of `unsigned int` in call to `accept`. +- [#188](https://github.com/TokTok/c-toxcore/pull/188) Add option to set test timeout +- [#187](https://github.com/TokTok/c-toxcore/pull/187) Add option to build tox-bootstrapd +- [#185](https://github.com/TokTok/c-toxcore/pull/185) Import the hstox SUT interface from hstox. +- [#183](https://github.com/TokTok/c-toxcore/pull/183) Set log level for DEBUG=ON to LOG_DEBUG. +- [#182](https://github.com/TokTok/c-toxcore/pull/182) Remove return after no-return situation. +- [#181](https://github.com/TokTok/c-toxcore/pull/181) Minor documentation fixes. +- [#180](https://github.com/TokTok/c-toxcore/pull/180) Add the 'Tox' context object to the logger. +- [#179](https://github.com/TokTok/c-toxcore/pull/179) Remove the `_test` suffix in `auto_test` calls. +- [#178](https://github.com/TokTok/c-toxcore/pull/178) Rebuild apidsl'd headers in cmake. +- [#177](https://github.com/TokTok/c-toxcore/pull/177) docs(INSTALL): update compiling instructions for Linux +- [#176](https://github.com/TokTok/c-toxcore/pull/176) Merge irungentoo/toxcore into TokTok/c-toxcore. +- [#173](https://github.com/TokTok/c-toxcore/pull/173) Duplicate tox_test to 4 other files. + +### Closed issues: + +- [#201](https://github.com/TokTok/c-toxcore/issues/201) Logging callback was broken + +## v0.0.1 + +### Merged PRs: + +- [#174](https://github.com/TokTok/c-toxcore/pull/174) Remove redundant callback objects. +- [#171](https://github.com/TokTok/c-toxcore/pull/171) Simple Version tick to v0.0.1 +- [#170](https://github.com/TokTok/c-toxcore/pull/170) C++ the second round. +- [#166](https://github.com/TokTok/c-toxcore/pull/166) Add version-sync script. +- [#164](https://github.com/TokTok/c-toxcore/pull/164) Replace `void*` with `RingBuffer*` to avoid conversions. +- [#163](https://github.com/TokTok/c-toxcore/pull/163) Move ring buffer out of toxcore/util into toxav. +- [#162](https://github.com/TokTok/c-toxcore/pull/162) Allow the OSX build to fail on travis. +- [#161](https://github.com/TokTok/c-toxcore/pull/161) Minor cleanups: unused vars, unreachable code, static globals. +- [#160](https://github.com/TokTok/c-toxcore/pull/160) Work around bug in opencv3 headers. +- [#157](https://github.com/TokTok/c-toxcore/pull/157) Make TCP_Connections module-private. +- [#156](https://github.com/TokTok/c-toxcore/pull/156) Make TCP_Server opaque. +- [#153](https://github.com/TokTok/c-toxcore/pull/153) Fix strict-ld grep expressions to include digits. +- [#151](https://github.com/TokTok/c-toxcore/pull/151) Revert #130 "Make ToxAV stateless" +- [#148](https://github.com/TokTok/c-toxcore/pull/148) Added UB comment r/t deleting a friend w/ active call +- [#146](https://github.com/TokTok/c-toxcore/pull/146) Make group callbacks stateless +- [#145](https://github.com/TokTok/c-toxcore/pull/145) Make internal chat list function take uint32_t* as well. +- [#144](https://github.com/TokTok/c-toxcore/pull/144) Only build toxav if opus and vpx are found. +- [#143](https://github.com/TokTok/c-toxcore/pull/143) Make toxcore code C++ compatible. +- [#142](https://github.com/TokTok/c-toxcore/pull/142) Fix for windows dynamic libraries. +- [#141](https://github.com/TokTok/c-toxcore/pull/141) const-correctness in windows code. +- [#140](https://github.com/TokTok/c-toxcore/pull/140) Use C99 %zu format conversion in printf for size_t. +- [#139](https://github.com/TokTok/c-toxcore/pull/139) Clean up Travis build a bit in preparation for osx/win. +- [#138](https://github.com/TokTok/c-toxcore/pull/138) Remove format-source from travis script. +- [#135](https://github.com/TokTok/c-toxcore/pull/135) Convert old groupchats to new API format +- [#134](https://github.com/TokTok/c-toxcore/pull/134) Add some astyle options to make it do more. +- [#133](https://github.com/TokTok/c-toxcore/pull/133) Ensure that all TODOs have an owner. +- [#132](https://github.com/TokTok/c-toxcore/pull/132) Remove `else` directly after `return`. +- [#130](https://github.com/TokTok/c-toxcore/pull/130) Make ToxAV stateless +- [#129](https://github.com/TokTok/c-toxcore/pull/129) Use TokTok's apidsl instead of the iphydf one. +- [#127](https://github.com/TokTok/c-toxcore/pull/127) Use "phase" script for travis build phases. +- [#126](https://github.com/TokTok/c-toxcore/pull/126) Add option to build static libraries. +- [#125](https://github.com/TokTok/c-toxcore/pull/125) Group #include directives in 3-4 groups. +- [#123](https://github.com/TokTok/c-toxcore/pull/123) Use correct logical operator for tox_test +- [#120](https://github.com/TokTok/c-toxcore/pull/120) make the majority of the callbacks stateless and add some status to a testcase +- [#118](https://github.com/TokTok/c-toxcore/pull/118) Use `const` for version numbers. +- [#117](https://github.com/TokTok/c-toxcore/pull/117) Add STRICT_ABI cmake flag to generate export lists. +- [#116](https://github.com/TokTok/c-toxcore/pull/116) Fix potential null pointer dereference. +- [#115](https://github.com/TokTok/c-toxcore/pull/115) Fix memory leak on error paths in tox_new. +- [#114](https://github.com/TokTok/c-toxcore/pull/114) Fix compilation for Windows. +- [#111](https://github.com/TokTok/c-toxcore/pull/111) Add debugging option to autotools configuration +- [#110](https://github.com/TokTok/c-toxcore/pull/110) Comment intentional switch fallthroughs +- [#109](https://github.com/TokTok/c-toxcore/pull/109) Separate ip_port packing from pack_nodes() and unpack_nodes() +- [#108](https://github.com/TokTok/c-toxcore/pull/108) Prevent `` inclusion by ``. +- [#107](https://github.com/TokTok/c-toxcore/pull/107) Print a message about missing astyle in format-source. +- [#104](https://github.com/TokTok/c-toxcore/pull/104) Merge with irungentoo/master +- [#103](https://github.com/TokTok/c-toxcore/pull/103) Allocate `sizeof(IP_ADAPTER_INFO)` bytes instead of `sizeof(T*)`. +- [#101](https://github.com/TokTok/c-toxcore/pull/101) Add TODO for @mannol. +- [#100](https://github.com/TokTok/c-toxcore/pull/100) Remove the packet mutation in toxav's bwcontroller. +- [#99](https://github.com/TokTok/c-toxcore/pull/99) Make packet data a ptr-to-const. +- [#97](https://github.com/TokTok/c-toxcore/pull/97) Improve static and const correctness. +- [#96](https://github.com/TokTok/c-toxcore/pull/96) Improve C standard compliance. +- [#94](https://github.com/TokTok/c-toxcore/pull/94) Rearrange fields to decrease size of structure +- [#84](https://github.com/TokTok/c-toxcore/pull/84) Remove useless casts. +- [#82](https://github.com/TokTok/c-toxcore/pull/82) Add missing #include to av_test.c. +- [#81](https://github.com/TokTok/c-toxcore/pull/81) Match parameter names in declarations with their definitions. +- [#80](https://github.com/TokTok/c-toxcore/pull/80) Sort #includes in all source files. +- [#79](https://github.com/TokTok/c-toxcore/pull/79) Remove redundant `return` statements. +- [#78](https://github.com/TokTok/c-toxcore/pull/78) Do not use `else` after `return`. +- [#77](https://github.com/TokTok/c-toxcore/pull/77) Add OSX and Windows build to travis config. +- [#76](https://github.com/TokTok/c-toxcore/pull/76) Remove unused and bit-rotten friends_test. +- [#75](https://github.com/TokTok/c-toxcore/pull/75) Enable build of av_test. +- [#74](https://github.com/TokTok/c-toxcore/pull/74) Add missing #includes to headers and rename tox_old to tox_group. +- [#73](https://github.com/TokTok/c-toxcore/pull/73) Add braces to all if statements. +- [#72](https://github.com/TokTok/c-toxcore/pull/72) Add getters/setters for options. +- [#70](https://github.com/TokTok/c-toxcore/pull/70) Expose constants as functions. +- [#68](https://github.com/TokTok/c-toxcore/pull/68) Add address sanitizer option to cmake file. +- [#66](https://github.com/TokTok/c-toxcore/pull/66) Fix plane size calculation in test +- [#65](https://github.com/TokTok/c-toxcore/pull/65) Avoid large stack allocations on thread stacks. +- [#64](https://github.com/TokTok/c-toxcore/pull/64) Comment out useless TODO'd if block. +- [#63](https://github.com/TokTok/c-toxcore/pull/63) Initialise the id in assoc_test. +- [#62](https://github.com/TokTok/c-toxcore/pull/62) Reduce the timeout on travis to something much more reasonable +- [#60](https://github.com/TokTok/c-toxcore/pull/60) Make friend requests stateless +- [#59](https://github.com/TokTok/c-toxcore/pull/59) Replace uint with unsigned int in assoc.c. +- [#58](https://github.com/TokTok/c-toxcore/pull/58) Make Message received receipts stateless +- [#57](https://github.com/TokTok/c-toxcore/pull/57) Make Friend User Status stateless +- [#55](https://github.com/TokTok/c-toxcore/pull/55) docs(INSTALL.md): update instructions for Gentoo +- [#54](https://github.com/TokTok/c-toxcore/pull/54) Make typing change callback stateless +- [#53](https://github.com/TokTok/c-toxcore/pull/53) Add format-source script. +- [#52](https://github.com/TokTok/c-toxcore/pull/52) Build assoc DHT code on travis. +- [#51](https://github.com/TokTok/c-toxcore/pull/51) Fix operation sequencing in TCP_test. +- [#49](https://github.com/TokTok/c-toxcore/pull/49) Apidsl test +- [#48](https://github.com/TokTok/c-toxcore/pull/48) Make friend message callback stateless +- [#46](https://github.com/TokTok/c-toxcore/pull/46) Move logging to a callback. +- [#45](https://github.com/TokTok/c-toxcore/pull/45) Stateless friend status message +- [#43](https://github.com/TokTok/c-toxcore/pull/43) Allow NULL as argument to tox_kill. +- [#41](https://github.com/TokTok/c-toxcore/pull/41) Fix warnings +- [#39](https://github.com/TokTok/c-toxcore/pull/39) Merge irungentoo/toxcore into TokTok/c-toxcore. +- [#38](https://github.com/TokTok/c-toxcore/pull/38) Try searching for libsodium with pkg-config in ./configure. +- [#37](https://github.com/TokTok/c-toxcore/pull/37) Add missing DHT_bootstrap to CMakeLists.txt. +- [#36](https://github.com/TokTok/c-toxcore/pull/36) Make tox_callback_friend_name stateless. +- [#33](https://github.com/TokTok/c-toxcore/pull/33) Update readme with tentative roadmap, removed old todo.md +- [#32](https://github.com/TokTok/c-toxcore/pull/32) Fix a bug I introduced that would make toxcore fail to initialise a second time +- [#31](https://github.com/TokTok/c-toxcore/pull/31) 7. Travis envs +- [#30](https://github.com/TokTok/c-toxcore/pull/30) 2. Hstox test +- [#29](https://github.com/TokTok/c-toxcore/pull/29) 1. Move toxcore travis build scripts out of .travis.yml. +- [#27](https://github.com/TokTok/c-toxcore/pull/27) 8. Stateless +- [#26](https://github.com/TokTok/c-toxcore/pull/26) 6. Cmake bootstrapd +- [#25](https://github.com/TokTok/c-toxcore/pull/25) 5. Coverage clang +- [#24](https://github.com/TokTok/c-toxcore/pull/24) Silence/fix some compiler warnings. +- [#23](https://github.com/TokTok/c-toxcore/pull/23) 4. Cmake +- [#20](https://github.com/TokTok/c-toxcore/pull/20) 3. Travis astyle +- [#13](https://github.com/TokTok/c-toxcore/pull/13) Enable, and report test status +- [#12](https://github.com/TokTok/c-toxcore/pull/12) Fix readme for TokTok +- [#11](https://github.com/TokTok/c-toxcore/pull/11) Documentation: SysVInit workaround for <1024 ports +- [#2](https://github.com/TokTok/c-toxcore/pull/2) Enable toxcore logging when building on Travis. +- [#1](https://github.com/TokTok/c-toxcore/pull/1) Apidsl fixes and start tracking test coverage + +### Closed issues: + +- [#158](https://github.com/TokTok/c-toxcore/issues/158) Error while build with OpenCV 3.1 +- [#147](https://github.com/TokTok/c-toxcore/issues/147) Add comment to m_delfriend about the NULL passing to the internal conn status cb +- [#136](https://github.com/TokTok/c-toxcore/issues/136) Replace astyle by clang-format +- [#113](https://github.com/TokTok/c-toxcore/issues/113) Toxcore tests fail +- [#83](https://github.com/TokTok/c-toxcore/issues/83) Travis tests are hard to quickly parse from their output. +- [#22](https://github.com/TokTok/c-toxcore/issues/22) Make the current tests exercise both ipv4 and ipv6. +- [#9](https://github.com/TokTok/c-toxcore/issues/9) Fix the failing test +- [#8](https://github.com/TokTok/c-toxcore/issues/8) Toxcore should make more liberal use of assertions +- [#4](https://github.com/TokTok/c-toxcore/issues/4) Integrate hstox tests with toxcore Travis build diff --git a/libs/libtox/docs/COPYING b/libs/libtox/docs/COPYING new file mode 100644 index 0000000000..94a9ed024d --- /dev/null +++ b/libs/libtox/docs/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/libs/libtox/docs/DONATORS b/libs/libtox/docs/DONATORS new file mode 100644 index 0000000000..dcce32c869 --- /dev/null +++ b/libs/libtox/docs/DONATORS @@ -0,0 +1,7 @@ +Minnesota > Florida +vdo +Spitfire is best technicolor horse. +if bad people don't hate you, you're doing something wrong +Pinkie Pie is best pony. +JRS was here +qTox is so bloated it doesn't even fit in a 64-bit address space diff --git a/libs/libtox/docs/README.md b/libs/libtox/docs/README.md new file mode 100644 index 0000000000..7a1ffe7ffa --- /dev/null +++ b/libs/libtox/docs/README.md @@ -0,0 +1,174 @@ +# ![Project Tox](https://raw.github.com/TokTok/toxcore/master/other/tox.png "Project Tox") + +**Current build status:** [![Build Status](https://travis-ci.org/TokTok/c-toxcore.svg?branch=master)](https://travis-ci.org/TokTok/c-toxcore) +**Current Coverage:** [![Coverage Status](https://coveralls.io/repos/github/TokTok/toxcore/badge.svg?branch=master)](https://coveralls.io/github/TokTok/toxcore?branch=master) + +[**Website**](https://tox.chat) **|** [**Wiki**](https://wiki.tox.chat/) **|** [**Blog**](https://blog.tox.chat/) **|** [**FAQ**](https://wiki.tox.chat/doku.php?id=users:faq) **|** [**Binaries/Downloads**](https://wiki.tox.chat/Binaries) **|** [**Clients**](https://wiki.tox.chat/doku.php?id=clients) **|** [**Compiling**](/INSTALL.md) + +**IRC Channels:** Users: [#tox@freenode](https://webchat.freenode.net/?channels=tox), Developers: [#toktok@freenode](https://webchat.freenode.net/?channels=toktok) + +## What is Tox + +Tox is a peer to peer (serverless) instant messenger aimed at making security +and privacy easy to obtain for regular users. It uses +[NaCl](https://nacl.cr.yp.to/) for its encryption and authentication. + +## IMPORTANT! + +### ![Danger: Experimental](other/tox-warning.png) + +This is an **experimental** cryptographic network library. It has not been +formally audited by an independent third party that specializes in +cryptography or cryptanalysis. **Use this library at your own risk.** + +The underlying crypto library [NaCl](https://nacl.cr.yp.to/install.html) +provides reliable encryption, but the security model has not yet been fully +specified. See [issue 210](https://github.com/TokTok/c-toxcore/issues/210) for +a discussion on developing a threat model. See other issues for known +weaknesses (e.g. [issue 426](https://github.com/TokTok/c-toxcore/issues/426) +describes what can happen if your secret key is stolen). + +## Toxcore Development Roadmap + +The roadmap and changelog are generated from GitHub issues. You may view them +on the website, where they are updated at least once every 24 hours: + +- Changelog: https://toktok.ltd/changelog/c-toxcore +- Roadmap: https://toktok.ltd/roadmap/c-toxcore + +## Installing toxcore + +Detailed installation instructions can be found in [INSTALL.md](INSTALL.md). + +In a nutshell, if you have [libsodium](https://github.com/jedisct1/libsodium) +or [nacl](https://nacl.cr.yp.to/install.html) installed, run: + +```sh +autoreconf -fi +mkdir _build && cd _build +../configure +make +sudo make install +``` + +If you have [libvpx](https://github.com/webmproject/libvpx) and +[opus](https://github.com/xiph/opus) installed, the above will also build the +A/V library for multimedia chats. + +## Using toxcore + +The simplest "hello world" example could be an echo bot. Here we will walk +through the implementation of a simple bot. + +### Creating the tox instance + +All toxcore API functions work with error parameters. They are enums with one +`OK` value and several error codes that describe the different situations in +which the function might fail. + +```c +TOX_ERR_NEW err_new; +Tox *tox = tox_new(NULL, &err_new); +if (err_new != TOX_ERR_NEW_OK) { + fprintf(stderr, "tox_new failed with error code %d\n", err_new); + exit(1); +} +``` + +Here, we simply exit the program, but in a real client you will probably want +to do some error handling and proper error reporting to the user. The `NULL` +argument given to the first parameter of `tox_new` is the `Tox_Options`. It +contains various write-once network settings and allows you to load a +previously serialised instance. See [toxcore/tox.h](tox.h) for details. + +### Setting up callbacks + +Toxcore works with callbacks that you can register to listen for certain +events. Examples of such events are "friend request received" or "friend sent +a message". Search the API for `tox_callback_*` to find all of them. + +Here, we will set up callbacks for receiving friend requests and receiving +messages. We will always accept any friend request (because we're a bot), and +when we receive a message, we send it back to the sender. + +```c +tox_callback_friend_request(tox, handle_friend_request); +tox_callback_friend_message(tox, handle_friend_message); +``` + +These two function calls set up the callbacks. Now we also need to implement +these "handle" functions. + +### Handle friend requests + +```c +static void handle_friend_request( + Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length, + void *user_data) { + // Accept the friend request: + TOX_ERR_FRIEND_ADD err_friend_add; + tox_friend_add_norequest(tox, public_key, &err_friend_add); + if (err_friend_add != TOX_ERR_FRIEND_ADD_OK) { + fprintf(stderr, "unable to add friend: %d\n", err_friend_add); + } +} +``` + +The `tox_friend_add_norequest` function adds the friend without sending them a +friend request. Since we already got a friend request, this is the right thing +to do. If you wanted to send a friend request yourself, you would use +`tox_friend_add`, which has an extra parameter for the message. + +### Handle messages + +Now, when the friend sends us a message, we want to respond to them by sending +them the same message back. This will be our "echo". + +```c +static void handle_friend_message( + Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, + const uint8_t *message, size_t length, + void *user_data) { + TOX_ERR_FRIEND_SEND_MESSAGE err_send; + tox_friend_send_message(tox, friend_number, type, message, length, + &err_send); + if (err_send != TOX_ERR_FRIEND_SEND_MESSAGE_OK) { + fprintf(stderr, "unable to send message back to friend %d: %d\n", + friend_number, err_send); + } +} +``` + +That's it for the setup. Now we want to actually run the bot. + +### Main event loop + +Toxcore works with a main event loop function `tox_iterate` that you need to +call at a certain frequency dictated by `tox_iteration_interval`. This is a +polling function that receives new network messages and processes them. + +```c +while (true) { + usleep(1000 * tox_iteration_interval(tox)); + tox_iterate(tox, NULL); +} +``` + +That's it! Now you have a working echo bot. The only problem is that since Tox +works with public keys, and you can't really guess your bot's public key, you +can't add it as a friend in your client. For this, we need to call another API +function: `tox_self_get_address(tox, address)`. This will fill the 38 byte +friend address into the `address` buffer. You can then display that binary +string as hex and input it into your client. Writing a `bin2hex` function is +left as exercise for the reader. + +We glossed over a lot of details, such as the user data which we passed to +`tox_iterate` (passing `NULL`), bootstrapping into an actual network (this bot +will work in the LAN, but not on an internet server) and the fact that we now +have no clean way of stopping the bot (`while (true)`). If you want to write a +real bot, you will probably want to read up on all the API functions. Consult +the API documentation in [toxcore/tox.h](tox.h) for more information. + +### Other resources + +- [Another echo bot](https://wiki.tox.chat/developers/client_examples/echo_bot) diff --git a/libs/libtox/libtox.vcxproj b/libs/libtox/libtox.vcxproj new file mode 100644 index 0000000000..466b91cd2f --- /dev/null +++ b/libs/libtox/libtox.vcxproj @@ -0,0 +1,52 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {A21C50CD-28A6-481A-A12B-47189FE66641} + libtox + + + + + $(ProjectDir)..\pthreads\src;$(ProjectDir)..\libsodium\src\include;%(AdditionalIncludeDirectories) + + + + + NotUsing + + + NotUsing + + + NotUsing + + + + + + + {a185b162-6cb6-4502-b03f-b56f7699a8d9} + + + {e0ebb8a5-b577-414c-a5f9-9b4e2a0a66e9} + + + \ No newline at end of file diff --git a/libs/libtox/libtox.vcxproj.filters b/libs/libtox/libtox.vcxproj.filters new file mode 100644 index 0000000000..541f75ffb0 --- /dev/null +++ b/libs/libtox/libtox.vcxproj.filters @@ -0,0 +1,293 @@ + + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/libs/libtox/src/stdafx.cxx b/libs/libtox/src/stdafx.cxx new file mode 100644 index 0000000000..1647228cd0 --- /dev/null +++ b/libs/libtox/src/stdafx.cxx @@ -0,0 +1,2 @@ + +#include "stdafx.h" \ No newline at end of file diff --git a/libs/libtox/src/stdafx.h b/libs/libtox/src/stdafx.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/libtox/src/toxcore/DHT.c b/libs/libtox/src/toxcore/DHT.c new file mode 100644 index 0000000000..4ebe7f3344 --- /dev/null +++ b/libs/libtox/src/toxcore/DHT.c @@ -0,0 +1,2853 @@ +/* + * An implementation of the DHT as seen in docs/updates/DHT.md + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "DHT.h" + +#include "LAN_discovery.h" +#include "logger.h" +#include "network.h" +#include "ping.h" +#include "util.h" + +#include + +/* The timeout after which a node is discarded completely. */ +#define KILL_NODE_TIMEOUT (BAD_NODE_TIMEOUT + PING_INTERVAL) + +/* Ping interval in seconds for each random sending of a get nodes request. */ +#define GET_NODE_INTERVAL 20 + +#define MAX_PUNCHING_PORTS 48 + +/* Interval in seconds between punching attempts*/ +#define PUNCH_INTERVAL 3 + +/* Time in seconds after which punching parameters will be reset */ +#define PUNCH_RESET_TIME 40 + +#define MAX_NORMAL_PUNCHING_TRIES 5 + +#define NAT_PING_REQUEST 0 +#define NAT_PING_RESPONSE 1 + +/* Number of get node requests to send to quickly find close nodes. */ +#define MAX_BOOTSTRAP_TIMES 5 + +#define ASSOC_COUNT 2 + +/* Compares pk1 and pk2 with pk. + * + * return 0 if both are same distance. + * return 1 if pk1 is closer. + * return 2 if pk2 is closer. + */ +int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2) +{ + for (size_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; ++i) { + + uint8_t distance1 = pk[i] ^ pk1[i]; + uint8_t distance2 = pk[i] ^ pk2[i]; + + if (distance1 < distance2) { + return 1; + } + + if (distance1 > distance2) { + return 2; + } + } + + return 0; +} + +/* Return index of first unequal bit number. + */ +static unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2) +{ + unsigned int i; + unsigned int j = 0; + + for (i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; ++i) { + if (pk1[i] == pk2[i]) { + continue; + } + + for (j = 0; j < 8; ++j) { + uint8_t mask = 1 << (7 - j); + + if ((pk1[i] & mask) != (pk2[i] & mask)) { + break; + } + } + + break; + } + + return i * 8 + j; +} + +/* Shared key generations are costly, it is therefor smart to store commonly used + * ones so that they can re used later without being computed again. + * + * If shared key is already in shared_keys, copy it to shared_key. + * else generate it into shared_key and copy it to shared_keys + */ +void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, const uint8_t *secret_key, const uint8_t *public_key) +{ + uint32_t num = ~0; + uint32_t curr = 0; + + for (uint32_t i = 0; i < MAX_KEYS_PER_SLOT; ++i) { + int index = public_key[30] * MAX_KEYS_PER_SLOT + i; + Shared_Key *key = &shared_keys->keys[index]; + + if (key->stored) { + if (id_equal(public_key, key->public_key)) { + memcpy(shared_key, key->shared_key, CRYPTO_SHARED_KEY_SIZE); + ++key->times_requested; + key->time_last_requested = unix_time(); + return; + } + + if (num != 0) { + if (is_timeout(key->time_last_requested, KEYS_TIMEOUT)) { + num = 0; + curr = index; + } else if (num > key->times_requested) { + num = key->times_requested; + curr = index; + } + } + } else if (num != 0) { + num = 0; + curr = index; + } + } + + encrypt_precompute(public_key, secret_key, shared_key); + + if (num != (uint32_t)~0) { + Shared_Key *key = &shared_keys->keys[curr]; + key->stored = 1; + key->times_requested = 1; + memcpy(key->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(key->shared_key, shared_key, CRYPTO_SHARED_KEY_SIZE); + key->time_last_requested = unix_time(); + } +} + +/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key + * for packets that we receive. + */ +void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key) +{ + get_shared_key(&dht->shared_keys_recv, shared_key, dht->self_secret_key, public_key); +} + +/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key + * for packets that we send. + */ +void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key) +{ + get_shared_key(&dht->shared_keys_sent, shared_key, dht->self_secret_key, public_key); +} + +#define CRYPTO_SIZE 1 + CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE + +/* Create a request to peer. + * send_public_key and send_secret_key are the pub/secret keys of the sender. + * recv_public_key is public key of receiver. + * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. + * Data represents the data we send with the request with length being the length of the data. + * request_id is the id of the request (32 = friend request, 254 = ping request). + * + * return -1 on failure. + * return the length of the created packet on success. + */ +int create_request(const uint8_t *send_public_key, const uint8_t *send_secret_key, uint8_t *packet, + const uint8_t *recv_public_key, const uint8_t *data, uint32_t length, uint8_t request_id) +{ + if (!send_public_key || !packet || !recv_public_key || !data) { + return -1; + } + + if (MAX_CRYPTO_REQUEST_SIZE < length + CRYPTO_SIZE + 1 + CRYPTO_MAC_SIZE) { + return -1; + } + + uint8_t *nonce = packet + 1 + CRYPTO_PUBLIC_KEY_SIZE * 2; + random_nonce(nonce); + uint8_t temp[MAX_CRYPTO_REQUEST_SIZE]; + memcpy(temp + 1, data, length); + temp[0] = request_id; + int len = encrypt_data(recv_public_key, send_secret_key, nonce, temp, length + 1, + CRYPTO_SIZE + packet); + + if (len == -1) { + crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE); + return -1; + } + + packet[0] = NET_PACKET_CRYPTO; + memcpy(packet + 1, recv_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, send_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE); + return len + CRYPTO_SIZE; +} + +/* Puts the senders public key in the request in public_key, the data from the request + * in data if a friend or ping request was sent to us and returns the length of the data. + * packet is the request packet and length is its length. + * + * return -1 if not valid request. + */ +int handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, + uint8_t *request_id, const uint8_t *packet, uint16_t length) +{ + if (!self_public_key || !public_key || !data || !request_id || !packet) { + return -1; + } + + if (length <= CRYPTO_SIZE + CRYPTO_MAC_SIZE || length > MAX_CRYPTO_REQUEST_SIZE) { + return -1; + } + + if (!id_equal(packet + 1, self_public_key)) { + return -1; + } + + memcpy(public_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_PUBLIC_KEY_SIZE); + const uint8_t *nonce = packet + 1 + CRYPTO_PUBLIC_KEY_SIZE * 2; + uint8_t temp[MAX_CRYPTO_REQUEST_SIZE]; + int len1 = decrypt_data(public_key, self_secret_key, nonce, + packet + CRYPTO_SIZE, length - CRYPTO_SIZE, temp); + + if (len1 == -1 || len1 == 0) { + crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE); + return -1; + } + + request_id[0] = temp[0]; + --len1; + memcpy(data, temp + 1, len1); + crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE); + return len1; +} + +#define PACKED_NODE_SIZE_IP4 (1 + SIZE_IP4 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE) +#define PACKED_NODE_SIZE_IP6 (1 + SIZE_IP6 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE) + +/* Return packet size of packed node with ip_family on success. + * Return -1 on failure. + */ +int packed_node_size(uint8_t ip_family) +{ + switch (ip_family) { + case TOX_AF_INET: + case TCP_INET: + return PACKED_NODE_SIZE_IP4; + + case TOX_AF_INET6: + case TCP_INET6: + return PACKED_NODE_SIZE_IP6; + + default: + return -1; + } +} + + +/* Packs an IP_Port structure into data of max size length. + * + * Returns size of packed IP_Port data on success + * Return -1 on failure. + */ +static int pack_ip_port(uint8_t *data, uint16_t length, const IP_Port *ip_port) +{ + if (data == NULL) { + return -1; + } + + bool is_ipv4; + uint8_t net_family; + + if (ip_port->ip.family == TOX_AF_INET) { + // TODO(irungentoo): use functions to convert endianness + is_ipv4 = true; + net_family = TOX_AF_INET; + } else if (ip_port->ip.family == TCP_INET) { + is_ipv4 = true; + net_family = TOX_TCP_INET; + } else if (ip_port->ip.family == TOX_AF_INET6) { + is_ipv4 = false; + net_family = TOX_AF_INET6; + } else if (ip_port->ip.family == TCP_INET6) { + is_ipv4 = false; + net_family = TOX_TCP_INET6; + } else { + return -1; + } + + if (is_ipv4) { + uint32_t size = 1 + SIZE_IP4 + sizeof(uint16_t); + + if (size > length) { + return -1; + } + + data[0] = net_family; + memcpy(data + 1, &ip_port->ip.ip4, SIZE_IP4); + memcpy(data + 1 + SIZE_IP4, &ip_port->port, sizeof(uint16_t)); + return size; + } else { + uint32_t size = 1 + SIZE_IP6 + sizeof(uint16_t); + + if (size > length) { + return -1; + } + + data[0] = net_family; + memcpy(data + 1, &ip_port->ip.ip6, SIZE_IP6); + memcpy(data + 1 + SIZE_IP6, &ip_port->port, sizeof(uint16_t)); + return size; + } +} + +static int DHT_create_packet(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE], + const uint8_t *shared_key, const uint8_t type, uint8_t *plain, size_t plain_length, uint8_t *packet) +{ + VLA(uint8_t, encrypted, plain_length + CRYPTO_MAC_SIZE); + uint8_t nonce[CRYPTO_NONCE_SIZE]; + + random_nonce(nonce); + + int encrypted_length = encrypt_data_symmetric(shared_key, nonce, plain, plain_length, encrypted); + + if (encrypted_length == -1) { + return -1; + } + + packet[0] = type; + memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, encrypted, encrypted_length); + + return 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + encrypted_length; +} + +/* Unpack IP_Port structure from data of max size length into ip_port. + * + * Return size of unpacked ip_port on success. + * Return -1 on failure. + */ +static int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, uint8_t tcp_enabled) +{ + if (data == NULL) { + return -1; + } + + bool is_ipv4; + uint8_t host_family; + + if (data[0] == TOX_AF_INET) { + is_ipv4 = true; + host_family = TOX_AF_INET; + } else if (data[0] == TOX_TCP_INET) { + if (!tcp_enabled) { + return -1; + } + + is_ipv4 = true; + host_family = TCP_INET; + } else if (data[0] == TOX_AF_INET6) { + is_ipv4 = false; + host_family = TOX_AF_INET6; + } else if (data[0] == TOX_TCP_INET6) { + if (!tcp_enabled) { + return -1; + } + + is_ipv4 = false; + host_family = TCP_INET6; + } else { + return -1; + } + + if (is_ipv4) { + uint32_t size = 1 + SIZE_IP4 + sizeof(uint16_t); + + if (size > length) { + return -1; + } + + ip_port->ip.family = host_family; + memcpy(&ip_port->ip.ip4, data + 1, SIZE_IP4); + memcpy(&ip_port->port, data + 1 + SIZE_IP4, sizeof(uint16_t)); + return size; + } else { + uint32_t size = 1 + SIZE_IP6 + sizeof(uint16_t); + + if (size > length) { + return -1; + } + + ip_port->ip.family = host_family; + memcpy(&ip_port->ip.ip6, data + 1, SIZE_IP6); + memcpy(&ip_port->port, data + 1 + SIZE_IP6, sizeof(uint16_t)); + return size; + } +} + +/* Pack number of nodes into data of maxlength length. + * + * return length of packed nodes on success. + * return -1 on failure. + */ +int pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number) +{ + uint32_t packed_length = 0; + + for (uint32_t i = 0; i < number && packed_length < length; ++i) { + int ipp_size = pack_ip_port(data + packed_length, length - packed_length, &nodes[i].ip_port); + + if (ipp_size == -1) { + return -1; + } + + packed_length += ipp_size; + + if (packed_length + CRYPTO_PUBLIC_KEY_SIZE > length) { + return -1; + } + + memcpy(data + packed_length, nodes[i].public_key, CRYPTO_PUBLIC_KEY_SIZE); + packed_length += CRYPTO_PUBLIC_KEY_SIZE; + + uint32_t increment = ipp_size + CRYPTO_PUBLIC_KEY_SIZE; + assert(increment == PACKED_NODE_SIZE_IP4 || increment == PACKED_NODE_SIZE_IP6); + } + + return packed_length; +} + +/* Unpack data of length into nodes of size max_num_nodes. + * Put the length of the data processed in processed_data_len. + * tcp_enabled sets if TCP nodes are expected (true) or not (false). + * + * return number of unpacked nodes on success. + * return -1 on failure. + */ +int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data, + uint16_t length, uint8_t tcp_enabled) +{ + uint32_t num = 0, len_processed = 0; + + while (num < max_num_nodes && len_processed < length) { + int ipp_size = unpack_ip_port(&nodes[num].ip_port, data + len_processed, length - len_processed, tcp_enabled); + + if (ipp_size == -1) { + return -1; + } + + len_processed += ipp_size; + + if (len_processed + CRYPTO_PUBLIC_KEY_SIZE > length) { + return -1; + } + + memcpy(nodes[num].public_key, data + len_processed, CRYPTO_PUBLIC_KEY_SIZE); + len_processed += CRYPTO_PUBLIC_KEY_SIZE; + ++num; + + uint32_t increment = ipp_size + CRYPTO_PUBLIC_KEY_SIZE; + assert(increment == PACKED_NODE_SIZE_IP4 || increment == PACKED_NODE_SIZE_IP6); + } + + if (processed_data_len) { + *processed_data_len = len_processed; + } + + return num; +} + +/* Find index of ##type with public_key equal to pk. + * + * return index or UINT32_MAX if not found. + */ +#define INDEX_OF_PK \ + for (uint32_t i = 0; i < size; i++) { \ + if (id_equal(array[i].public_key, pk)) { \ + return i; \ + } \ + } \ + \ + return UINT32_MAX; + +static uint32_t index_of_client_pk(const Client_data *array, uint32_t size, const uint8_t *pk) +{ + INDEX_OF_PK +} + +static uint32_t index_of_friend_pk(const DHT_Friend *array, uint32_t size, const uint8_t *pk) +{ + INDEX_OF_PK +} + +static uint32_t index_of_node_pk(const Node_format *array, uint32_t size, const uint8_t *pk) +{ + INDEX_OF_PK +} + +/* Find index of Client_data with ip_port equal to param ip_port. + * + * return index or UINT32_MAX if not found. + */ +static uint32_t index_of_client_ip_port(const Client_data *array, uint32_t size, const IP_Port *ip_port) +{ + for (uint32_t i = 0; i < size; ++i) { + if (ip_port->ip.family == TOX_AF_INET && ipport_equal(&array[i].assoc4.ip_port, ip_port) || + ip_port->ip.family == TOX_AF_INET6 && ipport_equal(&array[i].assoc6.ip_port, ip_port)) { + return i; + } + } + + return UINT32_MAX; +} + +/* Update ip_port of client if it's needed. + */ +static void update_client(Logger *log, int index, Client_data *client, IP_Port ip_port) +{ + IPPTsPng *assoc; + int ip_version; + + if (ip_port.ip.family == TOX_AF_INET) { + assoc = &client->assoc4; + ip_version = 4; + } else if (ip_port.ip.family == TOX_AF_INET6) { + assoc = &client->assoc6; + ip_version = 6; + } else { + return; + } + + if (!ipport_equal(&assoc->ip_port, &ip_port)) { + char ip_str[IP_NTOA_LEN]; + LOGGER_TRACE(log, "coipil[%u]: switching ipv%d from %s:%u to %s:%u", + index, ip_version, + ip_ntoa(&assoc->ip_port.ip, ip_str, sizeof(ip_str)), + net_ntohs(assoc->ip_port.port), + ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), + net_ntohs(ip_port.port)); + } + + if (LAN_ip(assoc->ip_port.ip) != 0 && LAN_ip(ip_port.ip) == 0) { + return; + } + + assoc->ip_port = ip_port; + assoc->timestamp = unix_time(); +} + +/* Check if client with public_key is already in list of length length. + * If it is then set its corresponding timestamp to current time. + * If the id is already in the list with a different ip_port, update it. + * TODO(irungentoo): Maybe optimize this. + * + * return True(1) or False(0) + */ +static int client_or_ip_port_in_list(Logger *log, Client_data *list, uint16_t length, const uint8_t *public_key, + IP_Port ip_port) +{ + uint64_t temp_time = unix_time(); + uint32_t index = index_of_client_pk(list, length, public_key); + + /* if public_key is in list, find it and maybe overwrite ip_port */ + if (index != UINT32_MAX) { + update_client(log, index, &list[index], ip_port); + return 1; + } + + /* public_key not in list yet: see if we can find an identical ip_port, in + * that case we kill the old public_key by overwriting it with the new one + * TODO(irungentoo): maybe we SHOULDN'T do that if that public_key is in a friend_list + * and the one who is the actual friend's public_key/address set? + * MAYBE: check the other address, if valid, don't nuke? */ + index = index_of_client_ip_port(list, length, &ip_port); + + if (index == UINT32_MAX) { + return 0; + } + + IPPTsPng *assoc; + int ip_version; + + if (ip_port.ip.family == TOX_AF_INET) { + assoc = &list[index].assoc4; + ip_version = 4; + } else { + assoc = &list[index].assoc6; + ip_version = 6; + } + + /* Initialize client timestamp. */ + assoc->timestamp = temp_time; + memcpy(list[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + LOGGER_DEBUG(log, "coipil[%u]: switching public_key (ipv%d)", index, ip_version); + + /* kill the other address, if it was set */ + memset(assoc, 0, sizeof(IPPTsPng)); + return 1; +} + +/* Add node to the node list making sure only the nodes closest to cmp_pk are in the list. + */ +bool add_to_list(Node_format *nodes_list, unsigned int length, const uint8_t *pk, IP_Port ip_port, + const uint8_t *cmp_pk) +{ + uint8_t pk_bak[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ip_port_bak; + + for (size_t i = 0; i < length; ++i) { + if (id_closest(cmp_pk, nodes_list[i].public_key, pk) == 2) { + memcpy(pk_bak, nodes_list[i].public_key, CRYPTO_PUBLIC_KEY_SIZE); + ip_port_bak = nodes_list[i].ip_port; + memcpy(nodes_list[i].public_key, pk, CRYPTO_PUBLIC_KEY_SIZE); + nodes_list[i].ip_port = ip_port; + + if (i != (length - 1)) { + add_to_list(nodes_list, length, pk_bak, ip_port_bak, cmp_pk); + } + + return 1; + } + } + + return 0; +} + +/* TODO(irungentoo): change this to 7 when done*/ +#define HARDENING_ALL_OK 2 +/* return 0 if not. + * return 1 if route request are ok + * return 2 if it responds to send node packets correctly + * return 4 if it can test other nodes correctly + * return HARDENING_ALL_OK if all ok. + */ +static uint8_t hardening_correct(const Hardening *h) +{ + return h->routes_requests_ok + (h->send_nodes_ok << 1) + (h->testing_requests << 2); +} +/* + * helper for get_close_nodes(). argument list is a monster :D + */ +static void get_close_nodes_inner(const uint8_t *public_key, Node_format *nodes_list, + Family sa_family, const Client_data *client_list, uint32_t client_list_length, + uint32_t *num_nodes_ptr, uint8_t is_LAN, uint8_t want_good) +{ + if ((sa_family != TOX_AF_INET) && (sa_family != TOX_AF_INET6) && (sa_family != 0)) { + return; + } + + uint32_t num_nodes = *num_nodes_ptr; + + for (uint32_t i = 0; i < client_list_length; i++) { + const Client_data *client = &client_list[i]; + + /* node already in list? */ + if (index_of_node_pk(nodes_list, MAX_SENT_NODES, client->public_key) != UINT32_MAX) { + continue; + } + + const IPPTsPng *ipptp = NULL; + + if (sa_family == TOX_AF_INET) { + ipptp = &client->assoc4; + } else if (sa_family == TOX_AF_INET6) { + ipptp = &client->assoc6; + } else if (client->assoc4.timestamp >= client->assoc6.timestamp) { + ipptp = &client->assoc4; + } else { + ipptp = &client->assoc6; + } + + /* node not in a good condition? */ + if (is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT)) { + continue; + } + + /* don't send LAN ips to non LAN peers */ + if (LAN_ip(ipptp->ip_port.ip) == 0 && !is_LAN) { + continue; + } + + if (LAN_ip(ipptp->ip_port.ip) != 0 && want_good && hardening_correct(&ipptp->hardening) != HARDENING_ALL_OK + && !id_equal(public_key, client->public_key)) { + continue; + } + + if (num_nodes < MAX_SENT_NODES) { + memcpy(nodes_list[num_nodes].public_key, client->public_key, CRYPTO_PUBLIC_KEY_SIZE); + nodes_list[num_nodes].ip_port = ipptp->ip_port; + num_nodes++; + } else { + add_to_list(nodes_list, MAX_SENT_NODES, client->public_key, ipptp->ip_port, public_key); + } + } + + *num_nodes_ptr = num_nodes; +} + +/* Find MAX_SENT_NODES nodes closest to the public_key for the send nodes request: + * put them in the nodes_list and return how many were found. + * + * TODO(irungentoo): For the love of based make this function cleaner and much more efficient. + * + * want_good : do we want only good nodes as checked with the hardening returned or not? + */ +static int get_somewhat_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, + Family sa_family, uint8_t is_LAN, uint8_t want_good) +{ + uint32_t num_nodes = 0; + get_close_nodes_inner(public_key, nodes_list, sa_family, + dht->close_clientlist, LCLIENT_LIST, &num_nodes, is_LAN, 0); + + /* TODO(irungentoo): uncomment this when hardening is added to close friend clients */ +#if 0 + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + get_close_nodes_inner(dht, public_key, nodes_list, sa_family, + dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, + &num_nodes, is_LAN, want_good); + } + +#endif + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + get_close_nodes_inner(public_key, nodes_list, sa_family, + dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, + &num_nodes, is_LAN, 0); + } + + return num_nodes; +} + +int get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, Family sa_family, + uint8_t is_LAN, uint8_t want_good) +{ + memset(nodes_list, 0, MAX_SENT_NODES * sizeof(Node_format)); + return get_somewhat_close_nodes(dht, public_key, nodes_list, sa_family, is_LAN, want_good); +} + +typedef struct { + const uint8_t *base_public_key; + Client_data entry; +} DHT_Cmp_data; + +static int cmp_dht_entry(const void *a, const void *b) +{ + DHT_Cmp_data cmp1, cmp2; + memcpy(&cmp1, a, sizeof(DHT_Cmp_data)); + memcpy(&cmp2, b, sizeof(DHT_Cmp_data)); + Client_data entry1 = cmp1.entry; + Client_data entry2 = cmp2.entry; + const uint8_t *cmp_public_key = cmp1.base_public_key; + +#define ASSOC_TIMEOUT(assoc) is_timeout((assoc).timestamp, BAD_NODE_TIMEOUT) + + bool t1 = ASSOC_TIMEOUT(entry1.assoc4) && ASSOC_TIMEOUT(entry1.assoc6); + bool t2 = ASSOC_TIMEOUT(entry2.assoc4) && ASSOC_TIMEOUT(entry2.assoc6); + + if (t1 && t2) { + return 0; + } + + if (t1) { + return -1; + } + + if (t2) { + return 1; + } + +#define INCORRECT_HARDENING(assoc) hardening_correct(&(assoc).hardening) != HARDENING_ALL_OK + + t1 = INCORRECT_HARDENING(entry1.assoc4) && INCORRECT_HARDENING(entry1.assoc6); + t2 = INCORRECT_HARDENING(entry2.assoc4) && INCORRECT_HARDENING(entry2.assoc6); + + if (t1 && !t2) { + return -1; + } + + if (!t1 && t2) { + return 1; + } + + int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); + + if (close == 1) { + return 1; + } + + if (close == 2) { + return -1; + } + + return 0; +} + +/* Is it ok to store node with public_key in client. + * + * return 0 if node can't be stored. + * return 1 if it can. + */ +static unsigned int store_node_ok(const Client_data *client, const uint8_t *public_key, const uint8_t *comp_public_key) +{ + return is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && + is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT) || + id_closest(comp_public_key, client->public_key, public_key) == 2; +} + +static void sort_client_list(Client_data *list, unsigned int length, const uint8_t *comp_public_key) +{ + // Pass comp_public_key to qsort with each Client_data entry, so the + // comparison function can use it as the base of comparison. + VLA(DHT_Cmp_data, cmp_list, length); + + for (uint32_t i = 0; i < length; i++) { + cmp_list[i].base_public_key = comp_public_key; + cmp_list[i].entry = list[i]; + } + + qsort(cmp_list, length, sizeof(DHT_Cmp_data), cmp_dht_entry); + + for (uint32_t i = 0; i < length; i++) { + list[i] = cmp_list[i].entry; + } +} + +static void update_client_with_reset(Client_data *client, const IP_Port *ip_port) +{ + IPPTsPng *ipptp_write = NULL; + IPPTsPng *ipptp_clear = NULL; + + if (ip_port->ip.family == TOX_AF_INET) { + ipptp_write = &client->assoc4; + ipptp_clear = &client->assoc6; + } else { + ipptp_write = &client->assoc6; + ipptp_clear = &client->assoc4; + } + + ipptp_write->ip_port = *ip_port; + ipptp_write->timestamp = unix_time(); + + ip_reset(&ipptp_write->ret_ip_port.ip); + ipptp_write->ret_ip_port.port = 0; + ipptp_write->ret_timestamp = 0; + + /* zero out other address */ + memset(ipptp_clear, 0, sizeof(*ipptp_clear)); +} + +/* Replace a first bad (or empty) node with this one + * or replace a possibly bad node (tests failed or not done yet) + * that is further than any other in the list + * from the comp_public_key + * or replace a good node that is further + * than any other in the list from the comp_public_key + * and further than public_key. + * + * Do not replace any node if the list has no bad or possibly bad nodes + * and all nodes in the list are closer to comp_public_key + * than public_key. + * + * returns True(1) when the item was stored, False(0) otherwise */ +static int replace_all(Client_data *list, + uint16_t length, + const uint8_t *public_key, + IP_Port ip_port, + const uint8_t *comp_public_key) +{ + if ((ip_port.ip.family != TOX_AF_INET) && (ip_port.ip.family != TOX_AF_INET6)) { + return 0; + } + + if (!store_node_ok(&list[1], public_key, comp_public_key) && + !store_node_ok(&list[0], public_key, comp_public_key)) { + return 0; + } + + sort_client_list(list, length, comp_public_key); + + Client_data *client = &list[0]; + id_copy(client->public_key, public_key); + + update_client_with_reset(client, &ip_port); + return 1; +} + +/* Add node to close list. + * + * simulate is set to 1 if we want to check if a node can be added to the list without adding it. + * + * return -1 on failure. + * return 0 on success. + */ +static int add_to_close(DHT *dht, const uint8_t *public_key, IP_Port ip_port, bool simulate) +{ + unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key); + + if (index >= LCLIENT_LENGTH) { + index = LCLIENT_LENGTH - 1; + } + + for (uint32_t i = 0; i < LCLIENT_NODES; ++i) { + /* TODO(iphydf): write bounds checking test to catch the case that + * index is left as >= LCLIENT_LENGTH */ + Client_data *client = &dht->close_clientlist[(index * LCLIENT_NODES) + i]; + + if (!is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) || + !is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) { + continue; + } + + if (simulate) { + return 0; + } + + id_copy(client->public_key, public_key); + update_client_with_reset(client, &ip_port); + return 0; + } + + return -1; +} + +/* Return 1 if node can be added to close list, 0 if it can't. + */ +bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port) +{ + return add_to_close(dht, public_key, ip_port, 1) == 0; +} + +static bool is_pk_in_client_list(Client_data *list, unsigned int client_list_length, const uint8_t *public_key, + IP_Port ip_port) +{ + uint32_t index = index_of_client_pk(list, client_list_length, public_key); + + if (index == UINT32_MAX) { + return 0; + } + + const IPPTsPng *assoc = ip_port.ip.family == TOX_AF_INET ? + &list[index].assoc4 : + &list[index].assoc6; + + return !is_timeout(assoc->timestamp, BAD_NODE_TIMEOUT); +} + +static bool is_pk_in_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port) +{ + unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key); + + if (index >= LCLIENT_LENGTH) { + index = LCLIENT_LENGTH - 1; + } + + return is_pk_in_client_list(dht->close_clientlist + index * LCLIENT_NODES, LCLIENT_NODES, public_key, ip_port); +} + +/* Check if the node obtained with a get_nodes with public_key should be pinged. + * NOTE: for best results call it after addto_lists; + * + * return 0 if the node should not be pinged. + * return 1 if it should. + */ +static unsigned int ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_key, IP_Port ip_port) +{ + bool ret = 0; + + if (add_to_close(dht, public_key, ip_port, 1) == 0) { + ret = 1; + } + + unsigned int *num = &dht->num_to_bootstrap; + uint32_t index = index_of_node_pk(dht->to_bootstrap, *num, public_key); + bool in_close_list = is_pk_in_close_list(dht, public_key, ip_port); + + if (ret && index == UINT32_MAX && !in_close_list) { + if (*num < MAX_CLOSE_TO_BOOTSTRAP_NODES) { + memcpy(dht->to_bootstrap[*num].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + dht->to_bootstrap[*num].ip_port = ip_port; + ++*num; + } else { + // TODO(irungentoo): ipv6 vs v4 + add_to_list(dht->to_bootstrap, MAX_CLOSE_TO_BOOTSTRAP_NODES, public_key, ip_port, dht->self_public_key); + } + } + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + bool store_ok = 0; + + DHT_Friend *dht_friend = &dht->friends_list[i]; + + if (store_node_ok(&dht_friend->client_list[1], public_key, dht_friend->public_key)) { + store_ok = 1; + } + + if (store_node_ok(&dht_friend->client_list[0], public_key, dht_friend->public_key)) { + store_ok = 1; + } + + unsigned int *friend_num = &dht_friend->num_to_bootstrap; + const uint32_t index = index_of_node_pk(dht_friend->to_bootstrap, *friend_num, public_key); + const bool pk_in_list = is_pk_in_client_list(dht_friend->client_list, MAX_FRIEND_CLIENTS, public_key, ip_port); + + if (store_ok && index == UINT32_MAX && !pk_in_list) { + if (*friend_num < MAX_SENT_NODES) { + Node_format *format = &dht_friend->to_bootstrap[*friend_num]; + memcpy(format->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + format->ip_port = ip_port; + ++*friend_num; + } else { + add_to_list(dht_friend->to_bootstrap, MAX_SENT_NODES, public_key, ip_port, dht_friend->public_key); + } + + ret = 1; + } + } + + return ret; +} + +/* Attempt to add client with ip_port and public_key to the friends client list + * and close_clientlist. + * + * returns 1+ if the item is used in any list, 0 else + */ +uint32_t addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key) +{ + uint32_t used = 0; + + /* convert IPv4-in-IPv6 to IPv4 */ + if ((ip_port.ip.family == TOX_AF_INET6) && IPV6_IPV4_IN_V6(ip_port.ip.ip6)) { + ip_port.ip.family = TOX_AF_INET; + ip_port.ip.ip4.uint32 = ip_port.ip.ip6.uint32[3]; + } + + /* NOTE: Current behavior if there are two clients with the same id is + * to replace the first ip by the second. + */ + const bool in_close_list = client_or_ip_port_in_list(dht->log, dht->close_clientlist, + LCLIENT_LIST, public_key, ip_port); + + /* add_to_close should be called only if !in_list (don't extract to variable) */ + if (in_close_list || add_to_close(dht, public_key, ip_port, 0)) { + used++; + } + + DHT_Friend *friend_foundip = 0; + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + const bool in_list = client_or_ip_port_in_list(dht->log, dht->friends_list[i].client_list, + MAX_FRIEND_CLIENTS, public_key, ip_port); + + /* replace_all should be called only if !in_list (don't extract to variable) */ + if (in_list || replace_all(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, public_key, + ip_port, dht->friends_list[i].public_key)) { + DHT_Friend *dht_friend = &dht->friends_list[i]; + + if (id_equal(public_key, dht_friend->public_key)) { + friend_foundip = dht_friend; + } + + used++; + } + } + + if (!friend_foundip) { + return used; + } + + for (uint32_t i = 0; i < friend_foundip->lock_count; ++i) { + if (friend_foundip->callbacks[i].ip_callback) { + friend_foundip->callbacks[i].ip_callback(friend_foundip->callbacks[i].data, + friend_foundip->callbacks[i].number, ip_port); + } + } + + return used; +} + +static bool update_client_data(Client_data *array, size_t size, IP_Port ip_port, const uint8_t *pk) +{ + uint64_t temp_time = unix_time(); + uint32_t index = index_of_client_pk(array, size, pk); + + if (index == UINT32_MAX) { + return false; + } + + Client_data *data = &array[index]; + IPPTsPng *assoc; + + if (ip_port.ip.family == TOX_AF_INET) { + assoc = &data->assoc4; + } else if (ip_port.ip.family == TOX_AF_INET6) { + assoc = &data->assoc6; + } else { + return true; + } + + assoc->ret_ip_port = ip_port; + assoc->ret_timestamp = temp_time; + return true; +} + +/* If public_key is a friend or us, update ret_ip_port + * nodepublic_key is the id of the node that sent us this info. + */ +static void returnedip_ports(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *nodepublic_key) +{ + /* convert IPv4-in-IPv6 to IPv4 */ + if ((ip_port.ip.family == TOX_AF_INET6) && IPV6_IPV4_IN_V6(ip_port.ip.ip6)) { + ip_port.ip.family = TOX_AF_INET; + ip_port.ip.ip4.uint32 = ip_port.ip.ip6.uint32[3]; + } + + if (id_equal(public_key, dht->self_public_key)) { + update_client_data(dht->close_clientlist, LCLIENT_LIST, ip_port, nodepublic_key); + return; + } + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + if (id_equal(public_key, dht->friends_list[i].public_key)) { + Client_data *client_list = dht->friends_list[i].client_list; + + if (update_client_data(client_list, MAX_FRIEND_CLIENTS, ip_port, nodepublic_key)) { + return; + } + } + } +} + +/* Send a getnodes request. + sendback_node is the node that it will send back the response to (set to NULL to disable this) */ +static int getnodes(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id, + const Node_format *sendback_node) +{ + /* Check if packet is going to be sent to ourself. */ + if (id_equal(public_key, dht->self_public_key)) { + return -1; + } + + uint8_t plain_message[sizeof(Node_format) * 2] = {0}; + + Node_format receiver; + memcpy(receiver.public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + receiver.ip_port = ip_port; + memcpy(plain_message, &receiver, sizeof(receiver)); + + uint64_t ping_id = 0; + + if (sendback_node != NULL) { + memcpy(plain_message + sizeof(receiver), sendback_node, sizeof(Node_format)); + ping_id = ping_array_add(&dht->dht_harden_ping_array, plain_message, sizeof(plain_message)); + } else { + ping_id = ping_array_add(&dht->dht_ping_array, plain_message, sizeof(receiver)); + } + + if (ping_id == 0) { + return -1; + } + + uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + sizeof(ping_id)]; + uint8_t data[1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE]; + + memcpy(plain, client_id, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, &ping_id, sizeof(ping_id)); + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + DHT_get_shared_key_sent(dht, shared_key, public_key); + + int len = DHT_create_packet(dht->self_public_key, shared_key, NET_PACKET_GET_NODES, + plain, sizeof(plain), data); + + if (len != sizeof(data)) { + return -1; + } + + return sendpacket(dht->net, ip_port, data, len); +} + +/* Send a send nodes response: message for IPv6 nodes */ +static int sendnodes_ipv6(const DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id, + const uint8_t *sendback_data, uint16_t length, const uint8_t *shared_encryption_key) +{ + /* Check if packet is going to be sent to ourself. */ + if (id_equal(public_key, dht->self_public_key)) { + return -1; + } + + if (length != sizeof(uint64_t)) { + return -1; + } + + size_t Node_format_size = sizeof(Node_format); + + Node_format nodes_list[MAX_SENT_NODES]; + uint32_t num_nodes = get_close_nodes(dht, client_id, nodes_list, 0, LAN_ip(ip_port.ip) == 0, 1); + + VLA(uint8_t, plain, 1 + Node_format_size * MAX_SENT_NODES + length); + + int nodes_length = 0; + + if (num_nodes) { + nodes_length = pack_nodes(plain + 1, Node_format_size * MAX_SENT_NODES, nodes_list, num_nodes); + + if (nodes_length <= 0) { + return -1; + } + } + + plain[0] = num_nodes; + memcpy(plain + 1 + nodes_length, sendback_data, length); + + const uint32_t crypto_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE; + VLA(uint8_t, data, 1 + nodes_length + length + crypto_size); + + int len = DHT_create_packet(dht->self_public_key, shared_encryption_key, NET_PACKET_SEND_NODES_IPV6, + plain, 1 + nodes_length + length, data); + + if (len != SIZEOF_VLA(data)) { + return -1; + } + + return sendpacket(dht->net, ip_port, data, len); +} + +#define CRYPTO_NODE_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint64_t)) + +static int handle_getnodes(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + if (length != (CRYPTO_SIZE + CRYPTO_MAC_SIZE + sizeof(uint64_t))) { + return 1; + } + + DHT *dht = (DHT *)object; + + /* Check if packet is from ourself. */ + if (id_equal(packet + 1, dht->self_public_key)) { + return 1; + } + + uint8_t plain[CRYPTO_NODE_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + + DHT_get_shared_key_recv(dht, shared_key, packet + 1); + int len = decrypt_data_symmetric(shared_key, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + CRYPTO_NODE_SIZE + CRYPTO_MAC_SIZE, + plain); + + if (len != CRYPTO_NODE_SIZE) { + return 1; + } + + sendnodes_ipv6(dht, source, packet + 1, plain, plain + CRYPTO_PUBLIC_KEY_SIZE, sizeof(uint64_t), shared_key); + + add_to_ping(dht->ping, packet + 1, source); + + return 0; +} +/* return 0 if no + return 1 if yes */ +static uint8_t sent_getnode_to_node(DHT *dht, const uint8_t *public_key, IP_Port node_ip_port, uint64_t ping_id, + Node_format *sendback_node) +{ + uint8_t data[sizeof(Node_format) * 2]; + + if (ping_array_check(data, sizeof(data), &dht->dht_ping_array, ping_id) == sizeof(Node_format)) { + memset(sendback_node, 0, sizeof(Node_format)); + } else if (ping_array_check(data, sizeof(data), &dht->dht_harden_ping_array, ping_id) == sizeof(data)) { + memcpy(sendback_node, data + sizeof(Node_format), sizeof(Node_format)); + } else { + return 0; + } + + Node_format test; + memcpy(&test, data, sizeof(Node_format)); + + if (!ipport_equal(&test.ip_port, &node_ip_port) || !id_equal(test.public_key, public_key)) { + return 0; + } + + return 1; +} + +/* Function is needed in following functions. */ +static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id, + const uint8_t *nodes_data, uint16_t nodes_data_length); + +static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *packet, uint16_t length, + Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out) +{ + DHT *dht = (DHT *)object; + uint32_t cid_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + 1 + sizeof(uint64_t) + CRYPTO_MAC_SIZE; + + if (length < cid_size) { /* too short */ + return 1; + } + + uint32_t data_size = length - cid_size; + + if (data_size == 0) { + return 1; + } + + if (data_size > sizeof(Node_format) * MAX_SENT_NODES) { /* invalid length */ + return 1; + } + + VLA(uint8_t, plain, 1 + data_size + sizeof(uint64_t)); + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + DHT_get_shared_key_sent(dht, shared_key, packet + 1); + int len = decrypt_data_symmetric( + shared_key, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + 1 + data_size + sizeof(uint64_t) + CRYPTO_MAC_SIZE, + plain); + + if ((unsigned int)len != SIZEOF_VLA(plain)) { + return 1; + } + + if (plain[0] > size_plain_nodes) { + return 1; + } + + Node_format sendback_node; + + uint64_t ping_id; + memcpy(&ping_id, plain + 1 + data_size, sizeof(ping_id)); + + if (!sent_getnode_to_node(dht, packet + 1, source, ping_id, &sendback_node)) { + return 1; + } + + uint16_t length_nodes = 0; + int num_nodes = unpack_nodes(plain_nodes, plain[0], &length_nodes, plain + 1, data_size, 0); + + if (length_nodes != data_size) { + return 1; + } + + if (num_nodes != plain[0]) { + return 1; + } + + if (num_nodes < 0) { + return 1; + } + + /* store the address the *request* was sent to */ + addto_lists(dht, source, packet + 1); + + *num_nodes_out = num_nodes; + + send_hardening_getnode_res(dht, &sendback_node, packet + 1, plain + 1, data_size); + return 0; +} + +static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + Node_format plain_nodes[MAX_SENT_NODES]; + uint32_t num_nodes; + + if (handle_sendnodes_core(object, source, packet, length, plain_nodes, MAX_SENT_NODES, &num_nodes)) { + return 1; + } + + if (num_nodes == 0) { + return 0; + } + + for (uint32_t i = 0; i < num_nodes; i++) { + if (ipport_isset(&plain_nodes[i].ip_port)) { + ping_node_from_getnodes_ok(dht, plain_nodes[i].public_key, plain_nodes[i].ip_port); + returnedip_ports(dht, plain_nodes[i].ip_port, plain_nodes[i].public_key, packet + 1); + } + } + + return 0; +} + +/*----------------------------------------------------------------------------------*/ +/*------------------------END of packet handling functions--------------------------*/ + +int DHT_addfriend(DHT *dht, const uint8_t *public_key, void (*ip_callback)(void *data, int32_t number, IP_Port), + void *data, int32_t number, uint16_t *lock_count) +{ + uint32_t friend_num = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key); + + uint16_t lock_num; + + if (friend_num != UINT32_MAX) { /* Is friend already in DHT? */ + DHT_Friend *dht_friend = &dht->friends_list[friend_num]; + + if (dht_friend->lock_count == DHT_FRIEND_MAX_LOCKS) { + return -1; + } + + lock_num = dht_friend->lock_count; + ++dht_friend->lock_count; + dht_friend->callbacks[lock_num].ip_callback = ip_callback; + dht_friend->callbacks[lock_num].data = data; + dht_friend->callbacks[lock_num].number = number; + + if (lock_count) { + *lock_count = lock_num + 1; + } + + return 0; + } + + DHT_Friend *temp = (DHT_Friend *)realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends + 1)); + + if (temp == NULL) { + return -1; + } + + dht->friends_list = temp; + DHT_Friend *dht_friend = &dht->friends_list[dht->num_friends]; + memset(dht_friend, 0, sizeof(DHT_Friend)); + memcpy(dht_friend->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + dht_friend->nat.NATping_id = random_64b(); + ++dht->num_friends; + + lock_num = dht_friend->lock_count; + ++dht_friend->lock_count; + dht_friend->callbacks[lock_num].ip_callback = ip_callback; + dht_friend->callbacks[lock_num].data = data; + dht_friend->callbacks[lock_num].number = number; + + if (lock_count) { + *lock_count = lock_num + 1; + } + + dht_friend->num_to_bootstrap = get_close_nodes(dht, dht_friend->public_key, dht_friend->to_bootstrap, 0, 1, 0); + + return 0; +} + +int DHT_delfriend(DHT *dht, const uint8_t *public_key, uint16_t lock_count) +{ + uint32_t friend_num = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key); + + if (friend_num == UINT32_MAX) { + return -1; + } + + DHT_Friend *dht_friend = &dht->friends_list[friend_num]; + --dht_friend->lock_count; + + if (dht_friend->lock_count && lock_count) { /* DHT friend is still in use.*/ + --lock_count; + dht_friend->callbacks[lock_count].ip_callback = NULL; + dht_friend->callbacks[lock_count].data = NULL; + dht_friend->callbacks[lock_count].number = 0; + return 0; + } + + --dht->num_friends; + + if (dht->num_friends != friend_num) { + memcpy(&dht->friends_list[friend_num], + &dht->friends_list[dht->num_friends], + sizeof(DHT_Friend)); + } + + if (dht->num_friends == 0) { + free(dht->friends_list); + dht->friends_list = NULL; + return 0; + } + + DHT_Friend *temp = (DHT_Friend *)realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends)); + + if (temp == NULL) { + return -1; + } + + dht->friends_list = temp; + return 0; +} + +/* TODO(irungentoo): Optimize this. */ +int DHT_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port) +{ + ip_reset(&ip_port->ip); + ip_port->port = 0; + + uint32_t friend_index = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key); + + if (friend_index == UINT32_MAX) { + return -1; + } + + DHT_Friend *frnd = &dht->friends_list[friend_index]; + uint32_t client_index = index_of_client_pk(frnd->client_list, MAX_FRIEND_CLIENTS, public_key); + + if (client_index == -1) { + return 0; + } + + Client_data *client = &frnd->client_list[client_index]; + IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc6, &client->assoc4 }; + + for (size_t i = 0; i < ASSOC_COUNT; i++) { + IPPTsPng *assoc = assocs[i]; + + if (!is_timeout(assoc->timestamp, BAD_NODE_TIMEOUT)) { + *ip_port = assoc->ip_port; + return 1; + } + } + + return -1; +} + +/* returns number of nodes not in kill-timeout */ +static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, const uint8_t *public_key, + Client_data *list, uint32_t list_count, uint32_t *bootstrap_times, bool sortable) +{ + uint8_t not_kill = 0; + uint64_t temp_time = unix_time(); + + uint32_t num_nodes = 0; + VLA(Client_data *, client_list, list_count * 2); + VLA(IPPTsPng *, assoc_list, list_count * 2); + unsigned int sort = 0; + bool sort_ok = 0; + + for (uint32_t i = 0; i < list_count; i++) { + /* If node is not dead. */ + Client_data *client = &list[i]; + + IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc6, &client->assoc4 }; + + for (size_t i = 0; i < ASSOC_COUNT; i++) { + IPPTsPng *assoc = assocs[i]; + + if (!is_timeout(assoc->timestamp, KILL_NODE_TIMEOUT)) { + sort = 0; + not_kill++; + + if (is_timeout(assoc->last_pinged, PING_INTERVAL)) { + getnodes(dht, assoc->ip_port, client->public_key, public_key, NULL); + assoc->last_pinged = temp_time; + } + + /* If node is good. */ + if (!is_timeout(assoc->timestamp, BAD_NODE_TIMEOUT)) { + client_list[num_nodes] = client; + assoc_list[num_nodes] = assoc; + ++num_nodes; + } + } else { + ++sort; + + /* Timed out should be at beginning, if they are not, sort the list. */ + if (sort > 1 && sort < (((i + 1) * 2) - 1)) { + sort_ok = 1; + } + } + } + } + + if (sortable && sort_ok) { + sort_client_list(list, list_count, public_key); + } + + if ((num_nodes != 0) && (is_timeout(*lastgetnode, GET_NODE_INTERVAL) || *bootstrap_times < MAX_BOOTSTRAP_TIMES)) { + uint32_t rand_node = rand() % (num_nodes); + + if ((num_nodes - 1) != rand_node) { + rand_node += rand() % (num_nodes - (rand_node + 1)); + } + + getnodes(dht, assoc_list[rand_node]->ip_port, client_list[rand_node]->public_key, public_key, NULL); + + *lastgetnode = temp_time; + ++*bootstrap_times; + } + + return not_kill; +} + +/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request + * every GET_NODE_INTERVAL seconds to a random good node for each "friend" in our "friends" list. + */ +static void do_DHT_friends(DHT *dht) +{ + for (size_t i = 0; i < dht->num_friends; ++i) { + DHT_Friend *dht_friend = &dht->friends_list[i]; + + for (size_t j = 0; j < dht_friend->num_to_bootstrap; ++j) { + getnodes(dht, dht_friend->to_bootstrap[j].ip_port, dht_friend->to_bootstrap[j].public_key, dht_friend->public_key, + NULL); + } + + dht_friend->num_to_bootstrap = 0; + + do_ping_and_sendnode_requests(dht, &dht_friend->lastgetnode, dht_friend->public_key, dht_friend->client_list, + MAX_FRIEND_CLIENTS, + &dht_friend->bootstrap_times, 1); + } +} + +/* Ping each client in the close nodes list every PING_INTERVAL seconds. + * Send a get nodes request every GET_NODE_INTERVAL seconds to a random good node in the list. + */ +static void do_Close(DHT *dht) +{ + for (size_t i = 0; i < dht->num_to_bootstrap; ++i) { + getnodes(dht, dht->to_bootstrap[i].ip_port, dht->to_bootstrap[i].public_key, dht->self_public_key, NULL); + } + + dht->num_to_bootstrap = 0; + + uint8_t not_killed = do_ping_and_sendnode_requests(dht, &dht->close_lastgetnodes, dht->self_public_key, + dht->close_clientlist, LCLIENT_LIST, &dht->close_bootstrap_times, 0); + + if (!not_killed) { + /* all existing nodes are at least KILL_NODE_TIMEOUT, + * which means we are mute, as we only send packets to + * nodes NOT in KILL_NODE_TIMEOUT + * + * so: reset all nodes to be BAD_NODE_TIMEOUT, but not + * KILL_NODE_TIMEOUT, so we at least keep trying pings */ + uint64_t badonly = unix_time() - BAD_NODE_TIMEOUT; + + for (size_t i = 0; i < LCLIENT_LIST; i++) { + Client_data *client = &dht->close_clientlist[i]; + + IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc6, &client->assoc4 }; + + for (size_t j = 0; j < ASSOC_COUNT; j++) { + IPPTsPng *assoc = assocs[j]; + + if (assoc->timestamp) { + assoc->timestamp = badonly; + } + } + } + } +} + +void DHT_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id) +{ + getnodes(dht, *from_ipp, from_id, which_id, NULL); +} + +void DHT_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key) +{ + getnodes(dht, ip_port, public_key, dht->self_public_key, NULL); +} +int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, + uint16_t port, const uint8_t *public_key) +{ + IP_Port ip_port_v64; + IP *ip_extra = NULL; + IP_Port ip_port_v4; + ip_init(&ip_port_v64.ip, ipv6enabled); + + if (ipv6enabled) { + /* setup for getting BOTH: an IPv6 AND an IPv4 address */ + ip_port_v64.ip.family = TOX_AF_UNSPEC; + ip_reset(&ip_port_v4.ip); + ip_extra = &ip_port_v4.ip; + } + + if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) { + ip_port_v64.port = port; + DHT_bootstrap(dht, ip_port_v64, public_key); + + if ((ip_extra != NULL) && ip_isset(ip_extra)) { + ip_port_v4.port = port; + DHT_bootstrap(dht, ip_port_v4, public_key); + } + + return 1; + } + + return 0; +} + +/* Send the given packet to node with public_key + * + * return -1 if failure. + */ +int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length) +{ + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + if (id_equal(public_key, dht->close_clientlist[i].public_key)) { + const Client_data *client = &dht->close_clientlist[i]; + const IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc6, &client->assoc4 }; + + for (size_t j = 0; j < ASSOC_COUNT; j++) { + const IPPTsPng *assoc = assocs[j]; + + if (ip_isset(&assoc->ip_port.ip)) { + return sendpacket(dht->net, assoc->ip_port, packet, length); + } + } + + break; + } + } + + return -1; +} + +/* Puts all the different ips returned by the nodes for a friend_num into array ip_portlist. + * ip_portlist must be at least MAX_FRIEND_CLIENTS big. + * + * return the number of ips returned. + * return 0 if we are connected to friend or if no ips were found. + * return -1 if no such friend. + */ +static int friend_iplist(const DHT *dht, IP_Port *ip_portlist, uint16_t friend_num) +{ + if (friend_num >= dht->num_friends) { + return -1; + } + + DHT_Friend *dht_friend = &dht->friends_list[friend_num]; + Client_data *client; + IP_Port ipv4s[MAX_FRIEND_CLIENTS]; + int num_ipv4s = 0; + IP_Port ipv6s[MAX_FRIEND_CLIENTS]; + int num_ipv6s = 0; + + for (size_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) { + client = &(dht_friend->client_list[i]); + + /* If ip is not zero and node is good. */ + if (ip_isset(&client->assoc4.ret_ip_port.ip) && !is_timeout(client->assoc4.ret_timestamp, BAD_NODE_TIMEOUT)) { + ipv4s[num_ipv4s] = client->assoc4.ret_ip_port; + ++num_ipv4s; + } + + if (ip_isset(&client->assoc6.ret_ip_port.ip) && !is_timeout(client->assoc6.ret_timestamp, BAD_NODE_TIMEOUT)) { + ipv6s[num_ipv6s] = client->assoc6.ret_ip_port; + ++num_ipv6s; + } + + if (id_equal(client->public_key, dht_friend->public_key)) { + if (!is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT) + || !is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT)) { + return 0; /* direct connectivity */ + } + } + } + +#ifdef FRIEND_IPLIST_PAD + memcpy(ip_portlist, ipv6s, num_ipv6s * sizeof(IP_Port)); + + if (num_ipv6s == MAX_FRIEND_CLIENTS) { + return MAX_FRIEND_CLIENTS; + } + + int num_ipv4s_used = MAX_FRIEND_CLIENTS - num_ipv6s; + + if (num_ipv4s_used > num_ipv4s) { + num_ipv4s_used = num_ipv4s; + } + + memcpy(&ip_portlist[num_ipv6s], ipv4s, num_ipv4s_used * sizeof(IP_Port)); + return num_ipv6s + num_ipv4s_used; + +#else /* !FRIEND_IPLIST_PAD */ + + /* there must be some secret reason why we can't pad the longer list + * with the shorter one... + */ + if (num_ipv6s >= num_ipv4s) { + memcpy(ip_portlist, ipv6s, num_ipv6s * sizeof(IP_Port)); + return num_ipv6s; + } + + memcpy(ip_portlist, ipv4s, num_ipv4s * sizeof(IP_Port)); + return num_ipv4s; + +#endif /* !FRIEND_IPLIST_PAD */ +} + + +/* Send the following packet to everyone who tells us they are connected to friend_id. + * + * return ip for friend. + * return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4). + */ +int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length) +{ + uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id); + + if (num == UINT32_MAX) { + return 0; + } + + uint32_t sent = 0; + uint8_t friend_sent[MAX_FRIEND_CLIENTS] = {0}; + + IP_Port ip_list[MAX_FRIEND_CLIENTS]; + int ip_num = friend_iplist(dht, ip_list, num); + + if (ip_num < (MAX_FRIEND_CLIENTS / 4)) { + return 0; /* Reason for that? */ + } + + DHT_Friend *dht_friend = &dht->friends_list[num]; + Client_data *client; + + /* extra legwork, because having the outside allocating the space for us + * is *usually* good(tm) (bites us in the behind in this case though) */ + + for (uint32_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) { + if (friend_sent[i]) {/* Send one packet per client.*/ + continue; + } + + client = &dht_friend->client_list[i]; + + const IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc4, &client->assoc6 }; + + for (size_t j = 0; j < ASSOC_COUNT; j++) { + const IPPTsPng *assoc = assocs[j]; + + /* If ip is not zero and node is good. */ + if (ip_isset(&assoc->ret_ip_port.ip) && !is_timeout(assoc->ret_timestamp, BAD_NODE_TIMEOUT)) { + int retval = sendpacket(dht->net, assoc->ip_port, packet, length); + + if ((unsigned int)retval == length) { + ++sent; + friend_sent[i] = 1; + } + } + } + } + + return sent; +} + +/* Send the following packet to one random person who tells us they are connected to friend_id. + * + * return number of nodes the packet was sent to. + */ +static int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length) +{ + uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id); + + if (num == UINT32_MAX) { + return 0; + } + + DHT_Friend *dht_friend = &dht->friends_list[num]; + Client_data *client; + + IP_Port ip_list[MAX_FRIEND_CLIENTS * 2]; + int n = 0; + + /* extra legwork, because having the outside allocating the space for us + * is *usually* good(tm) (bites us in the behind in this case though) */ + + for (uint32_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) { + client = &dht_friend->client_list[i]; + + const IPPTsPng *assocs[ASSOC_COUNT] = { &client->assoc4, &client->assoc6 }; + + for (size_t j = 0; j < ASSOC_COUNT; j++) { + const IPPTsPng *assoc = assocs[j]; + + /* If ip is not zero and node is good. */ + if (ip_isset(&assoc->ret_ip_port.ip) && !is_timeout(assoc->ret_timestamp, BAD_NODE_TIMEOUT)) { + ip_list[n] = assoc->ip_port; + ++n; + } + } + } + + if (n < 1) { + return 0; + } + + int retval = sendpacket(dht->net, ip_list[rand() % n], packet, length); + + if ((unsigned int)retval == length) { + return 1; + } + + return 0; +} + +/*----------------------------------------------------------------------------------*/ +/*---------------------BEGINNING OF NAT PUNCHING FUNCTIONS--------------------------*/ + +static int send_NATping(DHT *dht, const uint8_t *public_key, uint64_t ping_id, uint8_t type) +{ + uint8_t data[sizeof(uint64_t) + 1]; + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; + + int num = 0; + + data[0] = type; + memcpy(data + 1, &ping_id, sizeof(uint64_t)); + /* 254 is NAT ping request packet id */ + int len = create_request(dht->self_public_key, dht->self_secret_key, packet, public_key, data, + sizeof(uint64_t) + 1, CRYPTO_PACKET_NAT_PING); + + if (len == -1) { + return -1; + } + + if (type == 0) { /* If packet is request use many people to route it. */ + num = route_tofriend(dht, public_key, packet, len); + } else if (type == 1) { /* If packet is response use only one person to route it */ + num = routeone_tofriend(dht, public_key, packet, len); + } + + if (num == 0) { + return -1; + } + + return num; +} + +/* Handle a received ping request for. */ +static int handle_NATping(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, + uint16_t length, void *userdata) +{ + if (length != sizeof(uint64_t) + 1) { + return 1; + } + + DHT *dht = (DHT *)object; + uint64_t ping_id; + memcpy(&ping_id, packet + 1, sizeof(uint64_t)); + + uint32_t friendnumber = index_of_friend_pk(dht->friends_list, dht->num_friends, source_pubkey); + + if (friendnumber == UINT32_MAX) { + return 1; + } + + DHT_Friend *dht_friend = &dht->friends_list[friendnumber]; + + if (packet[0] == NAT_PING_REQUEST) { + /* 1 is reply */ + send_NATping(dht, source_pubkey, ping_id, NAT_PING_RESPONSE); + dht_friend->nat.recvNATping_timestamp = unix_time(); + return 0; + } + + if (packet[0] == NAT_PING_RESPONSE) { + if (dht_friend->nat.NATping_id == ping_id) { + dht_friend->nat.NATping_id = random_64b(); + dht_friend->nat.hole_punching = 1; + return 0; + } + } + + return 1; +} + +/* Get the most common ip in the ip_portlist. + * Only return ip if it appears in list min_num or more. + * len must not be bigger than MAX_FRIEND_CLIENTS. + * + * return ip of 0 if failure. + */ +static IP NAT_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num) +{ + IP zero; + ip_reset(&zero); + + if (len > MAX_FRIEND_CLIENTS) { + return zero; + } + + uint16_t numbers[MAX_FRIEND_CLIENTS] = {0}; + + for (uint32_t i = 0; i < len; ++i) { + for (uint32_t j = 0; j < len; ++j) { + if (ip_equal(&ip_portlist[i].ip, &ip_portlist[j].ip)) { + ++numbers[i]; + } + } + + if (numbers[i] >= min_num) { + return ip_portlist[i].ip; + } + } + + return zero; +} + +/* Return all the ports for one ip in a list. + * portlist must be at least len long, + * where len is the length of ip_portlist. + * + * return number of ports and puts the list of ports in portlist. + */ +static uint16_t NAT_getports(uint16_t *portlist, IP_Port *ip_portlist, uint16_t len, IP ip) +{ + uint16_t num = 0; + + for (uint32_t i = 0; i < len; ++i) { + if (ip_equal(&ip_portlist[i].ip, &ip)) { + portlist[num] = net_ntohs(ip_portlist[i].port); + ++num; + } + } + + return num; +} + +static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports, uint16_t friend_num) +{ + if (!dht->hole_punching_enabled) { + return; + } + + if (numports > MAX_FRIEND_CLIENTS || numports == 0) { + return; + } + + uint16_t first_port = port_list[0]; + uint32_t i; + + for (i = 0; i < numports; ++i) { + if (first_port != port_list[i]) { + break; + } + } + + if (i == numports) { /* If all ports are the same, only try that one port. */ + IP_Port pinging; + ip_copy(&pinging.ip, &ip); + pinging.port = net_htons(first_port); + send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].public_key); + } else { + for (i = 0; i < MAX_PUNCHING_PORTS; ++i) { + /* TODO(irungentoo): Improve port guessing algorithm. */ + uint32_t it = i + dht->friends_list[friend_num].nat.punching_index; + int8_t sign = (it % 2) ? -1 : 1; + uint32_t delta = sign * (it / (2 * numports)); + uint32_t index = (it / 2) % numports; + uint16_t port = port_list[index] + delta; + IP_Port pinging; + ip_copy(&pinging.ip, &ip); + pinging.port = net_htons(port); + send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].public_key); + } + + dht->friends_list[friend_num].nat.punching_index += i; + } + + if (dht->friends_list[friend_num].nat.tries > MAX_NORMAL_PUNCHING_TRIES) { + uint16_t port = 1024; + IP_Port pinging; + ip_copy(&pinging.ip, &ip); + + for (i = 0; i < MAX_PUNCHING_PORTS; ++i) { + uint32_t it = i + dht->friends_list[friend_num].nat.punching_index2; + pinging.port = net_htons(port + it); + send_ping_request(dht->ping, pinging, dht->friends_list[friend_num].public_key); + } + + dht->friends_list[friend_num].nat.punching_index2 += i - (MAX_PUNCHING_PORTS / 2); + } + + ++dht->friends_list[friend_num].nat.tries; +} + +static void do_NAT(DHT *dht) +{ + uint64_t temp_time = unix_time(); + + for (uint32_t i = 0; i < dht->num_friends; ++i) { + IP_Port ip_list[MAX_FRIEND_CLIENTS]; + int num = friend_iplist(dht, ip_list, i); + + /* If already connected or friend is not online don't try to hole punch. */ + if (num < MAX_FRIEND_CLIENTS / 2) { + continue; + } + + if (dht->friends_list[i].nat.NATping_timestamp + PUNCH_INTERVAL < temp_time) { + send_NATping(dht, dht->friends_list[i].public_key, dht->friends_list[i].nat.NATping_id, NAT_PING_REQUEST); + dht->friends_list[i].nat.NATping_timestamp = temp_time; + } + + if (dht->friends_list[i].nat.hole_punching == 1 && + dht->friends_list[i].nat.punching_timestamp + PUNCH_INTERVAL < temp_time && + dht->friends_list[i].nat.recvNATping_timestamp + PUNCH_INTERVAL * 2 >= temp_time) { + + IP ip = NAT_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2); + + if (!ip_isset(&ip)) { + continue; + } + + if (dht->friends_list[i].nat.punching_timestamp + PUNCH_RESET_TIME < temp_time) { + dht->friends_list[i].nat.tries = 0; + dht->friends_list[i].nat.punching_index = 0; + dht->friends_list[i].nat.punching_index2 = 0; + } + + uint16_t port_list[MAX_FRIEND_CLIENTS]; + uint16_t numports = NAT_getports(port_list, ip_list, num, ip); + punch_holes(dht, ip, port_list, numports, i); + + dht->friends_list[i].nat.punching_timestamp = temp_time; + dht->friends_list[i].nat.hole_punching = 0; + } + } +} + +/*----------------------------------------------------------------------------------*/ +/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/ + +#define HARDREQ_DATA_SIZE 384 /* Attempt to prevent amplification/other attacks*/ + +#define CHECK_TYPE_ROUTE_REQ 0 +#define CHECK_TYPE_ROUTE_RES 1 +#define CHECK_TYPE_GETNODE_REQ 2 +#define CHECK_TYPE_GETNODE_RES 3 +#define CHECK_TYPE_TEST_REQ 4 +#define CHECK_TYPE_TEST_RES 5 + +#if DHT_HARDENING +static int send_hardening_req(DHT *dht, Node_format *sendto, uint8_t type, uint8_t *contents, uint16_t length) +{ + if (length > HARDREQ_DATA_SIZE - 1) { + return -1; + } + + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; + uint8_t data[HARDREQ_DATA_SIZE] = {0}; + data[0] = type; + memcpy(data + 1, contents, length); + int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->public_key, data, + sizeof(data), CRYPTO_PACKET_HARDENING); + + if (len == -1) { + return -1; + } + + return sendpacket(dht->net, sendto->ip_port, packet, len); +} + +/* Send a get node hardening request */ +static int send_hardening_getnode_req(DHT *dht, Node_format *dest, Node_format *node_totest, uint8_t *search_id) +{ + uint8_t data[sizeof(Node_format) + CRYPTO_PUBLIC_KEY_SIZE]; + memcpy(data, node_totest, sizeof(Node_format)); + memcpy(data + sizeof(Node_format), search_id, CRYPTO_PUBLIC_KEY_SIZE); + return send_hardening_req(dht, dest, CHECK_TYPE_GETNODE_REQ, data, sizeof(Node_format) + CRYPTO_PUBLIC_KEY_SIZE); +} +#endif + +/* Send a get node hardening response */ +static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id, + const uint8_t *nodes_data, uint16_t nodes_data_length) +{ + if (!ip_isset(&sendto->ip_port.ip)) { + return -1; + } + + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; + VLA(uint8_t, data, 1 + CRYPTO_PUBLIC_KEY_SIZE + nodes_data_length); + data[0] = CHECK_TYPE_GETNODE_RES; + memcpy(data + 1, queried_client_id, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(data + 1 + CRYPTO_PUBLIC_KEY_SIZE, nodes_data, nodes_data_length); + int len = create_request(dht->self_public_key, dht->self_secret_key, packet, sendto->public_key, data, + SIZEOF_VLA(data), CRYPTO_PACKET_HARDENING); + + if (len == -1) { + return -1; + } + + return sendpacket(dht->net, sendto->ip_port, packet, len); +} + +/* TODO(irungentoo): improve */ +static IPPTsPng *get_closelist_IPPTsPng(DHT *dht, const uint8_t *public_key, Family sa_family) +{ + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + if (!id_equal(dht->close_clientlist[i].public_key, public_key)) { + continue; + } + + if (sa_family == TOX_AF_INET) { + return &dht->close_clientlist[i].assoc4; + } + + if (sa_family == TOX_AF_INET6) { + return &dht->close_clientlist[i].assoc6; + } + } + + return NULL; +} + +/* + * check how many nodes in nodes are also present in the closelist. + * TODO(irungentoo): make this function better. + */ +static uint32_t have_nodes_closelist(DHT *dht, Node_format *nodes, uint16_t num) +{ + uint32_t counter = 0; + + for (uint32_t i = 0; i < num; ++i) { + if (id_equal(nodes[i].public_key, dht->self_public_key)) { + ++counter; + continue; + } + + IPPTsPng *temp = get_closelist_IPPTsPng(dht, nodes[i].public_key, nodes[i].ip_port.ip.family); + + if (temp) { + if (!is_timeout(temp->timestamp, BAD_NODE_TIMEOUT)) { + ++counter; + } + } + } + + return counter; +} + +/* Interval in seconds between hardening checks */ +#define HARDENING_INTERVAL 120 +#define HARDEN_TIMEOUT 1200 + +/* Handle a received hardening packet */ +static int handle_hardening(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, + uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + + if (length < 2) { + return 1; + } + + switch (packet[0]) { + case CHECK_TYPE_GETNODE_REQ: { + if (length != HARDREQ_DATA_SIZE) { + return 1; + } + + Node_format node, tocheck_node; + node.ip_port = source; + memcpy(node.public_key, source_pubkey, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(&tocheck_node, packet + 1, sizeof(Node_format)); + + if (getnodes(dht, tocheck_node.ip_port, tocheck_node.public_key, packet + 1 + sizeof(Node_format), &node) == -1) { + return 1; + } + + return 0; + } + + case CHECK_TYPE_GETNODE_RES: { + if (length <= CRYPTO_PUBLIC_KEY_SIZE + 1) { + return 1; + } + + if (length > 1 + CRYPTO_PUBLIC_KEY_SIZE + sizeof(Node_format) * MAX_SENT_NODES) { + return 1; + } + + uint16_t length_nodes = length - 1 - CRYPTO_PUBLIC_KEY_SIZE; + Node_format nodes[MAX_SENT_NODES]; + int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, length_nodes, 0); + + /* TODO(irungentoo): MAX_SENT_NODES nodes should be returned at all times + (right now we have a small network size so it could cause problems for testing and etc..) */ + if (num_nodes <= 0) { + return 1; + } + + /* NOTE: This should work for now but should be changed to something better. */ + if (have_nodes_closelist(dht, nodes, num_nodes) < (uint32_t)((num_nodes + 2) / 2)) { + return 1; + } + + IPPTsPng *temp = get_closelist_IPPTsPng(dht, packet + 1, nodes[0].ip_port.ip.family); + + if (temp == NULL) { + return 1; + } + + if (is_timeout(temp->hardening.send_nodes_timestamp, HARDENING_INTERVAL)) { + return 1; + } + + if (!id_equal(temp->hardening.send_nodes_pingedid, source_pubkey)) { + return 1; + } + + /* If Nodes look good and the request checks out */ + temp->hardening.send_nodes_ok = 1; + return 0;/* success*/ + } + } + + return 1; +} + +#if DHT_HARDENING +/* Return a random node from all the nodes we are connected to. + * TODO(irungentoo): improve this function. + */ +static Node_format random_node(DHT *dht, Family sa_family) +{ + uint8_t id[CRYPTO_PUBLIC_KEY_SIZE]; + + for (uint32_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE / 4; ++i) { /* populate the id with pseudorandom bytes.*/ + uint32_t t = rand(); + memcpy(id + i * sizeof(t), &t, sizeof(t)); + } + + Node_format nodes_list[MAX_SENT_NODES]; + memset(nodes_list, 0, sizeof(nodes_list)); + uint32_t num_nodes = get_close_nodes(dht, id, nodes_list, sa_family, 1, 0); + + if (num_nodes == 0) { + return nodes_list[0]; + } + + return nodes_list[rand() % num_nodes]; +} +#endif + +/* Put up to max_num nodes in nodes from the closelist. + * + * return the number of nodes. + */ +static uint16_t list_nodes(Client_data *list, size_t length, Node_format *nodes, uint16_t max_num) +{ + if (max_num == 0) { + return 0; + } + + uint16_t count = 0; + + for (size_t i = length; i != 0; --i) { + IPPTsPng *assoc = NULL; + + if (!is_timeout(list[i - 1].assoc4.timestamp, BAD_NODE_TIMEOUT)) { + assoc = &list[i - 1].assoc4; + } + + if (!is_timeout(list[i - 1].assoc6.timestamp, BAD_NODE_TIMEOUT)) { + if (assoc == NULL) { + assoc = &list[i - 1].assoc6; + } else if (rand() % 2) { + assoc = &list[i - 1].assoc6; + } + } + + if (assoc != NULL) { + memcpy(nodes[count].public_key, list[i - 1].public_key, CRYPTO_PUBLIC_KEY_SIZE); + nodes[count].ip_port = assoc->ip_port; + ++count; + + if (count >= max_num) { + return count; + } + } + } + + return count; +} + +/* Put up to max_num nodes in nodes from the random friends. + * + * return the number of nodes. + */ +uint16_t randfriends_nodes(DHT *dht, Node_format *nodes, uint16_t max_num) +{ + if (max_num == 0) { + return 0; + } + + uint16_t count = 0; + unsigned int r = rand(); + + for (size_t i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) { + count += list_nodes(dht->friends_list[(i + r) % DHT_FAKE_FRIEND_NUMBER].client_list, MAX_FRIEND_CLIENTS, nodes + count, + max_num - count); + + if (count >= max_num) { + break; + } + } + + return count; +} + +/* Put up to max_num nodes in nodes from the closelist. + * + * return the number of nodes. + */ +uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num) +{ + return list_nodes(dht->close_clientlist, LCLIENT_LIST, nodes, max_num); +} + +#if DHT_HARDENING +static void do_hardening(DHT *dht) +{ + for (uint32_t i = 0; i < LCLIENT_LIST * 2; ++i) { + IPPTsPng *cur_iptspng; + Family sa_family; + uint8_t *public_key = dht->close_clientlist[i / 2].public_key; + + if (i % 2 == 0) { + cur_iptspng = &dht->close_clientlist[i / 2].assoc4; + sa_family = TOX_AF_INET; + } else { + cur_iptspng = &dht->close_clientlist[i / 2].assoc6; + sa_family = TOX_AF_INET6; + } + + if (is_timeout(cur_iptspng->timestamp, BAD_NODE_TIMEOUT)) { + continue; + } + + if (cur_iptspng->hardening.send_nodes_ok == 0) { + if (is_timeout(cur_iptspng->hardening.send_nodes_timestamp, HARDENING_INTERVAL)) { + Node_format rand_node = random_node(dht, sa_family); + + if (!ipport_isset(&rand_node.ip_port)) { + continue; + } + + if (id_equal(public_key, rand_node.public_key)) { + continue; + } + + Node_format to_test; + to_test.ip_port = cur_iptspng->ip_port; + memcpy(to_test.public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + // TODO(irungentoo): The search id should maybe not be ours? + if (send_hardening_getnode_req(dht, &rand_node, &to_test, dht->self_public_key) > 0) { + memcpy(cur_iptspng->hardening.send_nodes_pingedid, rand_node.public_key, CRYPTO_PUBLIC_KEY_SIZE); + cur_iptspng->hardening.send_nodes_timestamp = unix_time(); + } + } + } else { + if (is_timeout(cur_iptspng->hardening.send_nodes_timestamp, HARDEN_TIMEOUT)) { + cur_iptspng->hardening.send_nodes_ok = 0; + } + } + + // TODO(irungentoo): add the 2 other testers. + } +} +#endif + +/*----------------------------------------------------------------------------------*/ + +void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object) +{ + dht->cryptopackethandlers[byte].function = cb; + dht->cryptopackethandlers[byte].object = object; +} + +static int cryptopacket_handle(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + + assert(packet[0] == NET_PACKET_CRYPTO); + + if (length <= CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE + 1 + CRYPTO_MAC_SIZE || + length > MAX_CRYPTO_REQUEST_SIZE + CRYPTO_MAC_SIZE) { + return 1; + } + + // Check if request is for us. + if (id_equal(packet + 1, dht->self_public_key)) { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t data[MAX_CRYPTO_REQUEST_SIZE]; + uint8_t number; + int len = handle_request(dht->self_public_key, dht->self_secret_key, public_key, data, &number, packet, length); + + if (len == -1 || len == 0) { + return 1; + } + + if (!dht->cryptopackethandlers[number].function) { + return 1; + } + + return dht->cryptopackethandlers[number].function(dht->cryptopackethandlers[number].object, source, public_key, + data, len, userdata); + } + + /* If request is not for us, try routing it. */ + int retval = route_packet(dht, packet + 1, packet, length); + + if ((unsigned int)retval == length) { + return 0; + } + + return 1; +} + +/*----------------------------------------------------------------------------------*/ + +DHT *new_DHT(Logger *log, Networking_Core *net, bool holepunching_enabled) +{ + /* init time */ + unix_time_update(); + + if (net == NULL) { + return NULL; + } + + DHT *dht = (DHT *)calloc(1, sizeof(DHT)); + + if (dht == NULL) { + return NULL; + } + + dht->log = log; + dht->net = net; + + dht->hole_punching_enabled = holepunching_enabled; + + dht->ping = new_ping(dht); + + if (dht->ping == NULL) { + kill_DHT(dht); + return NULL; + } + + networking_registerhandler(dht->net, NET_PACKET_GET_NODES, &handle_getnodes, dht); + networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, dht); + networking_registerhandler(dht->net, NET_PACKET_CRYPTO, &cryptopacket_handle, dht); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, &handle_NATping, dht); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, &handle_hardening, dht); + + new_symmetric_key(dht->secret_symmetric_key); + crypto_new_keypair(dht->self_public_key, dht->self_secret_key); + + ping_array_init(&dht->dht_ping_array, DHT_PING_ARRAY_SIZE, PING_TIMEOUT); + ping_array_init(&dht->dht_harden_ping_array, DHT_PING_ARRAY_SIZE, PING_TIMEOUT); + + for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) { + uint8_t random_key_bytes[CRYPTO_PUBLIC_KEY_SIZE]; + random_bytes(random_key_bytes, sizeof(random_key_bytes)); + + if (DHT_addfriend(dht, random_key_bytes, 0, 0, 0, 0) != 0) { + kill_DHT(dht); + return NULL; + } + } + + return dht; +} + +void do_DHT(DHT *dht) +{ + unix_time_update(); + + if (dht->last_run == unix_time()) { + return; + } + + // Load friends/clients if first call to do_DHT + if (dht->loaded_num_nodes) { + DHT_connect_after_load(dht); + } + + do_Close(dht); + do_DHT_friends(dht); + do_NAT(dht); + do_to_ping(dht->ping); +#if DHT_HARDENING + do_hardening(dht); +#endif + dht->last_run = unix_time(); +} +void kill_DHT(DHT *dht) +{ + networking_registerhandler(dht->net, NET_PACKET_GET_NODES, NULL, NULL); + networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, NULL, NULL); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, NULL, NULL); + cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, NULL, NULL); + ping_array_free_all(&dht->dht_ping_array); + ping_array_free_all(&dht->dht_harden_ping_array); + kill_ping(dht->ping); + free(dht->friends_list); + free(dht->loaded_nodes_list); + free(dht); +} + +/* new DHT format for load/save, more robust and forward compatible */ +// TODO(irungentoo): Move this closer to Messenger. +#define DHT_STATE_COOKIE_GLOBAL 0x159000d + +#define DHT_STATE_COOKIE_TYPE 0x11ce +#define DHT_STATE_TYPE_NODES 4 + +#define MAX_SAVED_DHT_NODES (((DHT_FAKE_FRIEND_NUMBER * MAX_FRIEND_CLIENTS) + LCLIENT_LIST) * 2) + +/* Get the size of the DHT (for saving). */ +uint32_t DHT_size(const DHT *dht) +{ + uint32_t numv4 = 0, numv6 = 0; + + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + numv4 += (dht->close_clientlist[i].assoc4.timestamp != 0); + numv6 += (dht->close_clientlist[i].assoc6.timestamp != 0); + } + + for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER && i < dht->num_friends; ++i) { + DHT_Friend *fr = &dht->friends_list[i]; + + for (uint32_t j = 0; j < MAX_FRIEND_CLIENTS; ++j) { + numv4 += (fr->client_list[j].assoc4.timestamp != 0); + numv6 += (fr->client_list[j].assoc6.timestamp != 0); + } + } + + uint32_t size32 = sizeof(uint32_t), sizesubhead = size32 * 2; + + return size32 + sizesubhead + (packed_node_size(TOX_AF_INET) * numv4) + (packed_node_size(TOX_AF_INET6) * numv6); +} + +static uint8_t *DHT_save_subheader(uint8_t *data, uint32_t len, uint16_t type) +{ + host_to_lendian32(data, len); + data += sizeof(uint32_t); + host_to_lendian32(data, (host_tolendian16(DHT_STATE_COOKIE_TYPE) << 16) | host_tolendian16(type)); + data += sizeof(uint32_t); + return data; +} + + +/* Save the DHT in data where data is an array of size DHT_size(). */ +void DHT_save(DHT *dht, uint8_t *data) +{ + host_to_lendian32(data, DHT_STATE_COOKIE_GLOBAL); + data += sizeof(uint32_t); + + uint8_t *old_data = data; + + /* get right offset. we write the actual header later. */ + data = DHT_save_subheader(data, 0, 0); + + Node_format clients[MAX_SAVED_DHT_NODES]; + + uint32_t num = 0; + + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + if (dht->close_clientlist[i].assoc4.timestamp != 0) { + memcpy(clients[num].public_key, dht->close_clientlist[i].public_key, CRYPTO_PUBLIC_KEY_SIZE); + clients[num].ip_port = dht->close_clientlist[i].assoc4.ip_port; + ++num; + } + + if (dht->close_clientlist[i].assoc6.timestamp != 0) { + memcpy(clients[num].public_key, dht->close_clientlist[i].public_key, CRYPTO_PUBLIC_KEY_SIZE); + clients[num].ip_port = dht->close_clientlist[i].assoc6.ip_port; + ++num; + } + } + + for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER && i < dht->num_friends; ++i) { + DHT_Friend *fr = &dht->friends_list[i]; + + for (uint32_t j = 0; j < MAX_FRIEND_CLIENTS; ++j) { + if (fr->client_list[j].assoc4.timestamp != 0) { + memcpy(clients[num].public_key, fr->client_list[j].public_key, CRYPTO_PUBLIC_KEY_SIZE); + clients[num].ip_port = fr->client_list[j].assoc4.ip_port; + ++num; + } + + if (fr->client_list[j].assoc6.timestamp != 0) { + memcpy(clients[num].public_key, fr->client_list[j].public_key, CRYPTO_PUBLIC_KEY_SIZE); + clients[num].ip_port = fr->client_list[j].assoc6.ip_port; + ++num; + } + } + } + + DHT_save_subheader(old_data, pack_nodes(data, sizeof(Node_format) * num, clients, num), DHT_STATE_TYPE_NODES); +} + +/* Bootstrap from this number of nodes every time DHT_connect_after_load() is called */ +#define SAVE_BOOTSTAP_FREQUENCY 8 + +/* Start sending packets after DHT loaded_friends_list and loaded_clients_list are set */ +int DHT_connect_after_load(DHT *dht) +{ + if (dht == NULL) { + return -1; + } + + if (!dht->loaded_nodes_list) { + return -1; + } + + /* DHT is connected, stop. */ + if (DHT_non_lan_connected(dht)) { + free(dht->loaded_nodes_list); + dht->loaded_nodes_list = NULL; + dht->loaded_num_nodes = 0; + return 0; + } + + for (uint32_t i = 0; i < dht->loaded_num_nodes && i < SAVE_BOOTSTAP_FREQUENCY; ++i) { + unsigned int index = dht->loaded_nodes_index % dht->loaded_num_nodes; + DHT_bootstrap(dht, dht->loaded_nodes_list[index].ip_port, dht->loaded_nodes_list[index].public_key); + ++dht->loaded_nodes_index; + } + + return 0; +} + +static int dht_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type) +{ + DHT *dht = (DHT *)outer; + + switch (type) { + case DHT_STATE_TYPE_NODES: + if (length == 0) { + break; + } + + { + free(dht->loaded_nodes_list); + // Copy to loaded_clients_list + dht->loaded_nodes_list = (Node_format *)calloc(MAX_SAVED_DHT_NODES, sizeof(Node_format)); + + int num = unpack_nodes(dht->loaded_nodes_list, MAX_SAVED_DHT_NODES, NULL, data, length, 0); + + if (num > 0) { + dht->loaded_num_nodes = num; + } else { + dht->loaded_num_nodes = 0; + } + } /* localize declarations */ + + break; + + default: + LOGGER_ERROR(dht->log, "Load state (DHT): contains unrecognized part (len %u, type %u)\n", + length, type); + break; + } + + return 0; +} + +/* Load the DHT from data of size size. + * + * return -1 if failure. + * return 0 if success. + */ +int DHT_load(DHT *dht, const uint8_t *data, uint32_t length) +{ + uint32_t cookie_len = sizeof(uint32_t); + + if (length > cookie_len) { + uint32_t data32; + lendian_to_host32(&data32, data); + + if (data32 == DHT_STATE_COOKIE_GLOBAL) { + return load_state(dht_load_state_callback, dht->log, dht, data + cookie_len, + length - cookie_len, DHT_STATE_COOKIE_TYPE); + } + } + + return -1; +} + +/* return 0 if we are not connected to the DHT. + * return 1 if we are. + */ +int DHT_isconnected(const DHT *dht) +{ + unix_time_update(); + + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + const Client_data *client = &dht->close_clientlist[i]; + + if (!is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) || + !is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) { + return 1; + } + } + + return 0; +} + +/* return 0 if we are not connected or only connected to lan peers with the DHT. + * return 1 if we are. + */ +int DHT_non_lan_connected(const DHT *dht) +{ + unix_time_update(); + + for (uint32_t i = 0; i < LCLIENT_LIST; ++i) { + const Client_data *client = &dht->close_clientlist[i]; + + if (!is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && LAN_ip(client->assoc4.ip_port.ip) == -1) { + return 1; + } + + if (!is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT) && LAN_ip(client->assoc6.ip_port.ip) == -1) { + return 1; + } + } + + return 0; +} diff --git a/libs/libtox/src/toxcore/DHT.h b/libs/libtox/src/toxcore/DHT.h new file mode 100644 index 0000000000..510b3c5c92 --- /dev/null +++ b/libs/libtox/src/toxcore/DHT.h @@ -0,0 +1,448 @@ +/* + * An implementation of the DHT as seen in docs/updates/DHT.md + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef DHT_H +#define DHT_H + +#include "crypto_core.h" +#include "logger.h" +#include "network.h" +#include "ping_array.h" + +#include + +/* Maximum number of clients stored per friend. */ +#define MAX_FRIEND_CLIENTS 8 + +#define LCLIENT_NODES (MAX_FRIEND_CLIENTS) +#define LCLIENT_LENGTH 128 + +/* A list of the clients mathematically closest to ours. */ +#define LCLIENT_LIST (LCLIENT_LENGTH * LCLIENT_NODES) + +#define MAX_CLOSE_TO_BOOTSTRAP_NODES 8 + +/* The max number of nodes to send with send nodes. */ +#define MAX_SENT_NODES 4 + +/* Ping timeout in seconds */ +#define PING_TIMEOUT 5 + +/* size of DHT ping arrays. */ +#define DHT_PING_ARRAY_SIZE 512 + +/* Ping interval in seconds for each node in our lists. */ +#define PING_INTERVAL 60 + +/* The number of seconds for a non responsive node to become bad. */ +#define PINGS_MISSED_NODE_GOES_BAD 1 +#define PING_ROUNDTRIP 2 +#define BAD_NODE_TIMEOUT (PING_INTERVAL + PINGS_MISSED_NODE_GOES_BAD * (PING_INTERVAL + PING_ROUNDTRIP)) + +/* The number of "fake" friends to add (for optimization purposes and so our paths for the onion part are more random) */ +#define DHT_FAKE_FRIEND_NUMBER 2 + +#define MAX_CRYPTO_REQUEST_SIZE 1024 + +#define CRYPTO_PACKET_FRIEND_REQ 32 /* Friend request crypto packet ID. */ +#define CRYPTO_PACKET_HARDENING 48 /* Hardening crypto packet ID. */ +#define CRYPTO_PACKET_DHTPK 156 +#define CRYPTO_PACKET_NAT_PING 254 /* NAT ping crypto packet ID. */ + +/* Create a request to peer. + * send_public_key and send_secret_key are the pub/secret keys of the sender. + * recv_public_key is public key of receiver. + * packet must be an array of MAX_CRYPTO_REQUEST_SIZE big. + * Data represents the data we send with the request with length being the length of the data. + * request_id is the id of the request (32 = friend request, 254 = ping request). + * + * return -1 on failure. + * return the length of the created packet on success. + */ +int create_request(const uint8_t *send_public_key, const uint8_t *send_secret_key, uint8_t *packet, + const uint8_t *recv_public_key, const uint8_t *data, uint32_t length, uint8_t request_id); + +/* puts the senders public key in the request in public_key, the data from the request + in data if a friend or ping request was sent to us and returns the length of the data. + packet is the request packet and length is its length + return -1 if not valid request. */ +int handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data, + uint8_t *request_id, const uint8_t *packet, uint16_t length); + +typedef struct { + IP_Port ip_port; + uint64_t timestamp; +} IPPTs; + +typedef struct { + /* Node routes request correctly (true (1) or false/didn't check (0)) */ + uint8_t routes_requests_ok; + /* Time which we last checked this.*/ + uint64_t routes_requests_timestamp; + uint8_t routes_requests_pingedid[CRYPTO_PUBLIC_KEY_SIZE]; + /* Node sends correct send_node (true (1) or false/didn't check (0)) */ + uint8_t send_nodes_ok; + /* Time which we last checked this.*/ + uint64_t send_nodes_timestamp; + uint8_t send_nodes_pingedid[CRYPTO_PUBLIC_KEY_SIZE]; + /* Node can be used to test other nodes (true (1) or false/didn't check (0)) */ + uint8_t testing_requests; + /* Time which we last checked this.*/ + uint64_t testing_timestamp; + uint8_t testing_pingedid[CRYPTO_PUBLIC_KEY_SIZE]; +} Hardening; + +typedef struct { + IP_Port ip_port; + uint64_t timestamp; + uint64_t last_pinged; + + Hardening hardening; + /* Returned by this node. Either our friend or us. */ + IP_Port ret_ip_port; + uint64_t ret_timestamp; +} IPPTsPng; + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IPPTsPng assoc4; + IPPTsPng assoc6; +} Client_data; + +/*----------------------------------------------------------------------------------*/ + +typedef struct { + /* 1 if currently hole punching, otherwise 0 */ + uint8_t hole_punching; + uint32_t punching_index; + uint32_t tries; + uint32_t punching_index2; + + uint64_t punching_timestamp; + uint64_t recvNATping_timestamp; + uint64_t NATping_id; + uint64_t NATping_timestamp; +} NAT; + +#define DHT_FRIEND_MAX_LOCKS 32 + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ip_port; +} +Node_format; + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + Client_data client_list[MAX_FRIEND_CLIENTS]; + + /* Time at which the last get_nodes request was sent. */ + uint64_t lastgetnode; + /* number of times get_node packets were sent. */ + uint32_t bootstrap_times; + + /* Symetric NAT hole punching stuff. */ + NAT nat; + + uint16_t lock_count; + struct { + void (*ip_callback)(void *, int32_t, IP_Port); + void *data; + int32_t number; + } callbacks[DHT_FRIEND_MAX_LOCKS]; + + Node_format to_bootstrap[MAX_SENT_NODES]; + unsigned int num_to_bootstrap; +} DHT_Friend; + +/* Return packet size of packed node with ip_family on success. + * Return -1 on failure. + */ +int packed_node_size(uint8_t ip_family); + +/* Pack number of nodes into data of maxlength length. + * + * return length of packed nodes on success. + * return -1 on failure. + */ +int pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number); + +/* Unpack data of length into nodes of size max_num_nodes. + * Put the length of the data processed in processed_data_len. + * tcp_enabled sets if TCP nodes are expected (true) or not (false). + * + * return number of unpacked nodes on success. + * return -1 on failure. + */ +int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data, + uint16_t length, uint8_t tcp_enabled); + + +/*----------------------------------------------------------------------------------*/ +/* struct to store some shared keys so we don't have to regenerate them for each request. */ +#define MAX_KEYS_PER_SLOT 4 +#define KEYS_TIMEOUT 600 + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint32_t times_requested; + uint8_t stored; /* 0 if not, 1 if is */ + uint64_t time_last_requested; +} Shared_Key; + +typedef struct { + Shared_Key keys[256 * MAX_KEYS_PER_SLOT]; +} Shared_Keys; + +/*----------------------------------------------------------------------------------*/ + +typedef int (*cryptopacket_handler_callback)(void *object, IP_Port ip_port, const uint8_t *source_pubkey, + const uint8_t *data, uint16_t len, void *userdata); + +typedef struct { + cryptopacket_handler_callback function; + void *object; +} Cryptopacket_Handles; + +typedef struct { + Logger *log; + Networking_Core *net; + + bool hole_punching_enabled; + + Client_data close_clientlist[LCLIENT_LIST]; + uint64_t close_lastgetnodes; + uint32_t close_bootstrap_times; + + /* Note: this key should not be/is not used to transmit any sensitive materials */ + uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + /* DHT keypair */ + uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + DHT_Friend *friends_list; + uint16_t num_friends; + + Node_format *loaded_nodes_list; + uint32_t loaded_num_nodes; + unsigned int loaded_nodes_index; + + Shared_Keys shared_keys_recv; + Shared_Keys shared_keys_sent; + + struct PING *ping; + Ping_Array dht_ping_array; + Ping_Array dht_harden_ping_array; + uint64_t last_run; + + Cryptopacket_Handles cryptopackethandlers[256]; + + Node_format to_bootstrap[MAX_CLOSE_TO_BOOTSTRAP_NODES]; + unsigned int num_to_bootstrap; +} DHT; +/*----------------------------------------------------------------------------------*/ + +/* Shared key generations are costly, it is therefor smart to store commonly used + * ones so that they can re used later without being computed again. + * + * If shared key is already in shared_keys, copy it to shared_key. + * else generate it into shared_key and copy it to shared_keys + */ +void get_shared_key(Shared_Keys *shared_keys, uint8_t *shared_key, const uint8_t *secret_key, + const uint8_t *public_key); + +/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key + * for packets that we receive. + */ +void DHT_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key); + +/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key + * for packets that we send. + */ +void DHT_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key); + +void DHT_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id); + +/* Add a new friend to the friends list. + * public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long. + * + * ip_callback is the callback of a function that will be called when the ip address + * is found along with arguments data and number. + * + * lock_count will be set to a non zero number that must be passed to DHT_delfriend() + * to properly remove the callback. + * + * return 0 if success. + * return -1 if failure (friends list is full). + */ +int DHT_addfriend(DHT *dht, const uint8_t *public_key, void (*ip_callback)(void *data, int32_t number, IP_Port), + void *data, int32_t number, uint16_t *lock_count); + +/* Delete a friend from the friends list. + * public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long. + * + * return 0 if success. + * return -1 if failure (public_key not in friends list). + */ +int DHT_delfriend(DHT *dht, const uint8_t *public_key, uint16_t lock_count); + +/* Get ip of friend. + * public_key must be CRYPTO_PUBLIC_KEY_SIZE bytes long. + * ip must be 4 bytes long. + * port must be 2 bytes long. + * + * int DHT_getfriendip(DHT *dht, uint8_t *public_key, IP_Port *ip_port); + * + * return -1, -- if public_key does NOT refer to a friend + * return 0, -- if public_key refers to a friend and we failed to find the friend (yet) + * return 1, ip if public_key refers to a friend and we found him + */ +int DHT_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port); + +/* Compares pk1 and pk2 with pk. + * + * return 0 if both are same distance. + * return 1 if pk1 is closer. + * return 2 if pk2 is closer. + */ +int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2); + +/* Add node to the node list making sure only the nodes closest to cmp_pk are in the list. + */ +bool add_to_list(Node_format *nodes_list, unsigned int length, const uint8_t *pk, IP_Port ip_port, + const uint8_t *cmp_pk); + +/* Return 1 if node can be added to close list, 0 if it can't. + */ +bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port); + +/* Get the (maximum MAX_SENT_NODES) closest nodes to public_key we know + * and put them in nodes_list (must be MAX_SENT_NODES big). + * + * sa_family = family (IPv4 or IPv6) (0 if we don't care)? + * is_LAN = return some LAN ips (true or false) + * want_good = do we want tested nodes or not? (TODO(irungentoo)) + * + * return the number of nodes returned. + * + */ +int get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, Family sa_family, + uint8_t is_LAN, uint8_t want_good); + + +/* Put up to max_num nodes in nodes from the random friends. + * + * return the number of nodes. + */ +uint16_t randfriends_nodes(DHT *dht, Node_format *nodes, uint16_t max_num); + +/* Put up to max_num nodes in nodes from the closelist. + * + * return the number of nodes. + */ +uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num); + +/* Run this function at least a couple times per second (It's the main loop). */ +void do_DHT(DHT *dht); + +/* + * Use these two functions to bootstrap the client. + */ +/* Sends a "get nodes" request to the given node with ip, port and public_key + * to setup connections + */ +void DHT_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key); +/* Resolves address into an IP address. If successful, sends a "get nodes" + * request to the given node with ip, port and public_key to setup connections + * + * address can be a hostname or an IP address (IPv4 or IPv6). + * if ipv6enabled is 0 (zero), the resolving sticks STRICTLY to IPv4 addresses + * if ipv6enabled is not 0 (zero), the resolving looks for IPv6 addresses first, + * then IPv4 addresses. + * + * returns 1 if the address could be converted into an IP address + * returns 0 otherwise + */ +int DHT_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled, + uint16_t port, const uint8_t *public_key); + +/* Start sending packets after DHT loaded_friends_list and loaded_clients_list are set. + * + * returns 0 if successful + * returns -1 otherwise + */ +int DHT_connect_after_load(DHT *dht); + +/* ROUTING FUNCTIONS */ + +/* Send the given packet to node with public_key. + * + * return -1 if failure. + */ +int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length); + +/* Send the following packet to everyone who tells us they are connected to friend_id. + * + * return number of nodes it sent the packet to. + */ +int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length); + +/* Function to handle crypto packets. + */ +void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_callback cb, void *object); + +/* SAVE/LOAD functions */ + +/* Get the size of the DHT (for saving). */ +uint32_t DHT_size(const DHT *dht); + +/* Save the DHT in data where data is an array of size DHT_size(). */ +void DHT_save(DHT *dht, uint8_t *data); + +/* Load the DHT from data of size size. + * + * return -1 if failure. + * return 0 if success. + */ +int DHT_load(DHT *dht, const uint8_t *data, uint32_t length); + +/* Initialize DHT. */ +DHT *new_DHT(Logger *log, Networking_Core *net, bool holepunching_enabled); + +void kill_DHT(DHT *dht); + +/* return 0 if we are not connected to the DHT. + * return 1 if we are. + */ +int DHT_isconnected(const DHT *dht); + +/* return 0 if we are not connected or only connected to lan peers with the DHT. + * return 1 if we are. + */ +int DHT_non_lan_connected(const DHT *dht); + + +uint32_t addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key); + +#endif diff --git a/libs/libtox/src/toxcore/LAN_discovery.c b/libs/libtox/src/toxcore/LAN_discovery.c new file mode 100644 index 0000000000..b95e401d05 --- /dev/null +++ b/libs/libtox/src/toxcore/LAN_discovery.c @@ -0,0 +1,410 @@ +/* + * LAN discovery implementation. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "LAN_discovery.h" + +#include "util.h" + +/* Used for get_broadcast(). */ +#ifdef __linux +#include +#include +#endif + +#define MAX_INTERFACES 16 + + +/* TODO: multiple threads might concurrently try to set these, and it isn't clear that this couldn't lead to undesirable + * behaviour. Consider storing the data in per-instance variables instead. */ +static int broadcast_count = -1; +static IP_Port broadcast_ip_ports[MAX_INTERFACES]; + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + +#include + +static void fetch_broadcast_info(uint16_t port) +{ + IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO)); + unsigned long ulOutBufLen = sizeof(IP_ADAPTER_INFO); + + if (pAdapterInfo == NULL) { + return; + } + + if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) { + free(pAdapterInfo); + pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen); + + if (pAdapterInfo == NULL) { + return; + } + } + + /* We copy these to the static variables broadcast_* only at the end of fetch_broadcast_info(). + * The intention is to ensure that even if multiple threads enter fetch_broadcast_info() concurrently, only valid + * interfaces will be set to be broadcast to. + * */ + int count = 0; + IP_Port ip_ports[MAX_INTERFACES]; + + int ret; + + if ((ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) { + IP_ADAPTER_INFO *pAdapter = pAdapterInfo; + + while (pAdapter) { + IP gateway = {0}, subnet_mask = {0}; + + if (addr_parse_ip(pAdapter->IpAddressList.IpMask.String, &subnet_mask) + && addr_parse_ip(pAdapter->GatewayList.IpAddress.String, &gateway)) { + if (gateway.family == TOX_AF_INET && subnet_mask.family == TOX_AF_INET) { + IP_Port *ip_port = &ip_ports[count]; + ip_port->ip.family = TOX_AF_INET; + uint32_t gateway_ip = net_ntohl(gateway.ip4.uint32), subnet_ip = net_ntohl(subnet_mask.ip4.uint32); + uint32_t broadcast_ip = gateway_ip + ~subnet_ip - 1; + ip_port->ip.ip4.uint32 = net_htonl(broadcast_ip); + ip_port->port = port; + count++; + + if (count >= MAX_INTERFACES) { + break; + } + } + } + + pAdapter = pAdapter->Next; + } + } + + if (pAdapterInfo) { + free(pAdapterInfo); + } + + broadcast_count = count; + + for (uint32_t i = 0; i < count; i++) { + broadcast_ip_ports[i] = ip_ports[i]; + } +} + +#elif defined(__linux__) + +static void fetch_broadcast_info(uint16_t port) +{ + /* Not sure how many platforms this will run on, + * so it's wrapped in __linux for now. + * Definitely won't work like this on Windows... + */ + broadcast_count = 0; + Socket sock = 0; + + if ((sock = net_socket(TOX_AF_INET, TOX_SOCK_STREAM, 0)) < 0) { + return; + } + + /* Configure ifconf for the ioctl call. */ + struct ifreq i_faces[MAX_INTERFACES]; + memset(i_faces, 0, sizeof(struct ifreq) * MAX_INTERFACES); + + struct ifconf ifconf; + ifconf.ifc_buf = (char *)i_faces; + ifconf.ifc_len = sizeof(i_faces); + + if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0) { + close(sock); + return; + } + + /* We copy these to the static variables broadcast_* only at the end of fetch_broadcast_info(). + * The intention is to ensure that even if multiple threads enter fetch_broadcast_info() concurrently, only valid + * interfaces will be set to be broadcast to. + * */ + int count = 0; + IP_Port ip_ports[MAX_INTERFACES]; + + /* ifconf.ifc_len is set by the ioctl() to the actual length used; + * on usage of the complete array the call should be repeated with + * a larger array, not done (640kB and 16 interfaces shall be + * enough, for everybody!) + */ + int i, n = ifconf.ifc_len / sizeof(struct ifreq); + + for (i = 0; i < n; i++) { + /* there are interfaces with are incapable of broadcast */ + if (ioctl(sock, SIOCGIFBRDADDR, &i_faces[i]) < 0) { + continue; + } + + /* moot check: only TOX_AF_INET returned (backwards compat.) */ + if (i_faces[i].ifr_broadaddr.sa_family != TOX_AF_INET) { + continue; + } + + struct sockaddr_in *sock4 = (struct sockaddr_in *)&i_faces[i].ifr_broadaddr; + + if (count >= MAX_INTERFACES) { + break; + } + + IP_Port *ip_port = &ip_ports[count]; + ip_port->ip.family = TOX_AF_INET; + ip_port->ip.ip4.uint32 = sock4->sin_addr.s_addr; + + if (ip_port->ip.ip4.uint32 == 0) { + continue; + } + + ip_port->port = port; + count++; + } + + close(sock); + + broadcast_count = count; + + for (uint32_t i = 0; i < count; i++) { + broadcast_ip_ports[i] = ip_ports[i]; + } +} + +#else // TODO(irungentoo): Other platforms? + +static void fetch_broadcast_info(uint16_t port) +{ + broadcast_count = 0; +} + +#endif +/* Send packet to all IPv4 broadcast addresses + * + * return 1 if sent to at least one broadcast target. + * return 0 on failure to find any valid broadcast target. + */ +static uint32_t send_broadcasts(Networking_Core *net, uint16_t port, const uint8_t *data, uint16_t length) +{ + /* fetch only once? on every packet? every X seconds? + * old: every packet, new: once */ + if (broadcast_count < 0) { + fetch_broadcast_info(port); + } + + if (!broadcast_count) { + return 0; + } + + int i; + + for (i = 0; i < broadcast_count; i++) { + sendpacket(net, broadcast_ip_ports[i], data, length); + } + + return 1; +} + +/* Return the broadcast ip. */ +static IP broadcast_ip(Family family_socket, Family family_broadcast) +{ + IP ip; + ip_reset(&ip); + + if (family_socket == TOX_AF_INET6) { + if (family_broadcast == TOX_AF_INET6) { + ip.family = TOX_AF_INET6; + /* FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */ + /* FE80::*: MUST be exact, for that we would need to look over all + * interfaces and check in which status they are */ + ip.ip6.uint8[ 0] = 0xFF; + ip.ip6.uint8[ 1] = 0x02; + ip.ip6.uint8[15] = 0x01; + } else if (family_broadcast == TOX_AF_INET) { + ip.family = TOX_AF_INET6; + ip.ip6 = IP6_BROADCAST; + } + } else if (family_socket == TOX_AF_INET) { + if (family_broadcast == TOX_AF_INET) { + ip.family = TOX_AF_INET; + ip.ip4 = IP4_BROADCAST; + } + } + + return ip; +} + +/* Is IP a local ip or not. */ +bool Local_ip(IP ip) +{ + if (ip.family == TOX_AF_INET) { + IP4 ip4 = ip.ip4; + + /* Loopback. */ + if (ip4.uint8[0] == 127) { + return 1; + } + } else { + /* embedded IPv4-in-IPv6 */ + if (IPV6_IPV4_IN_V6(ip.ip6)) { + IP ip4; + ip4.family = TOX_AF_INET; + ip4.ip4.uint32 = ip.ip6.uint32[3]; + return Local_ip(ip4); + } + + /* localhost in IPv6 (::1) */ + if (ip.ip6.uint64[0] == 0 && ip.ip6.uint32[2] == 0 && ip.ip6.uint32[3] == net_htonl(1)) { + return 1; + } + } + + return 0; +} + +/* return 0 if ip is a LAN ip. + * return -1 if it is not. + */ +int LAN_ip(IP ip) +{ + if (Local_ip(ip)) { + return 0; + } + + if (ip.family == TOX_AF_INET) { + IP4 ip4 = ip.ip4; + + /* 10.0.0.0 to 10.255.255.255 range. */ + if (ip4.uint8[0] == 10) { + return 0; + } + + /* 172.16.0.0 to 172.31.255.255 range. */ + if (ip4.uint8[0] == 172 && ip4.uint8[1] >= 16 && ip4.uint8[1] <= 31) { + return 0; + } + + /* 192.168.0.0 to 192.168.255.255 range. */ + if (ip4.uint8[0] == 192 && ip4.uint8[1] == 168) { + return 0; + } + + /* 169.254.1.0 to 169.254.254.255 range. */ + if (ip4.uint8[0] == 169 && ip4.uint8[1] == 254 && ip4.uint8[2] != 0 + && ip4.uint8[2] != 255) { + return 0; + } + + /* RFC 6598: 100.64.0.0 to 100.127.255.255 (100.64.0.0/10) + * (shared address space to stack another layer of NAT) */ + if ((ip4.uint8[0] == 100) && ((ip4.uint8[1] & 0xC0) == 0x40)) { + return 0; + } + } else if (ip.family == TOX_AF_INET6) { + + /* autogenerated for each interface: FE80::* (up to FEBF::*) + FF02::1 is - according to RFC 4291 - multicast all-nodes link-local */ + if (((ip.ip6.uint8[0] == 0xFF) && (ip.ip6.uint8[1] < 3) && (ip.ip6.uint8[15] == 1)) || + ((ip.ip6.uint8[0] == 0xFE) && ((ip.ip6.uint8[1] & 0xC0) == 0x80))) { + return 0; + } + + /* embedded IPv4-in-IPv6 */ + if (IPV6_IPV4_IN_V6(ip.ip6)) { + IP ip4; + ip4.family = TOX_AF_INET; + ip4.ip4.uint32 = ip.ip6.uint32[3]; + return LAN_ip(ip4); + } + } + + return -1; +} + +static int handle_LANdiscovery(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + + if (LAN_ip(source.ip) == -1) { + return 1; + } + + if (length != CRYPTO_PUBLIC_KEY_SIZE + 1) { + return 1; + } + + char ip_str[IP_NTOA_LEN] = { 0 }; + ip_ntoa(&source.ip, ip_str, sizeof(ip_str)); + LOGGER_INFO(dht->log, "Found node in LAN: %s", ip_str); + + DHT_bootstrap(dht, source, packet + 1); + return 0; +} + + +int send_LANdiscovery(uint16_t port, DHT *dht) +{ + uint8_t data[CRYPTO_PUBLIC_KEY_SIZE + 1]; + data[0] = NET_PACKET_LAN_DISCOVERY; + id_copy(data + 1, dht->self_public_key); + + send_broadcasts(dht->net, port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE); + + int res = -1; + IP_Port ip_port; + ip_port.port = port; + + /* IPv6 multicast */ + if (dht->net->family == TOX_AF_INET6) { + ip_port.ip = broadcast_ip(TOX_AF_INET6, TOX_AF_INET6); + + if (ip_isset(&ip_port.ip)) { + if (sendpacket(dht->net, ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE) > 0) { + res = 1; + } + } + } + + /* IPv4 broadcast (has to be IPv4-in-IPv6 mapping if socket is TOX_AF_INET6 */ + ip_port.ip = broadcast_ip(dht->net->family, TOX_AF_INET); + + if (ip_isset(&ip_port.ip)) { + if (sendpacket(dht->net, ip_port, data, 1 + CRYPTO_PUBLIC_KEY_SIZE)) { + res = 1; + } + } + + return res; +} + + +void LANdiscovery_init(DHT *dht) +{ + networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, &handle_LANdiscovery, dht); +} + +void LANdiscovery_kill(DHT *dht) +{ + networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, NULL, NULL); +} diff --git a/libs/libtox/src/toxcore/LAN_discovery.h b/libs/libtox/src/toxcore/LAN_discovery.h new file mode 100644 index 0000000000..753de5249f --- /dev/null +++ b/libs/libtox/src/toxcore/LAN_discovery.h @@ -0,0 +1,52 @@ +/* + * LAN discovery implementation. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef LAN_DISCOVERY_H +#define LAN_DISCOVERY_H + +#include "DHT.h" + +/* Interval in seconds between LAN discovery packet sending. */ +#define LAN_DISCOVERY_INTERVAL 10 + +/* Send a LAN discovery pcaket to the broadcast address with port port. */ +int send_LANdiscovery(uint16_t port, DHT *dht); + +/* Sets up packet handlers. */ +void LANdiscovery_init(DHT *dht); + +/* Clear packet handlers. */ +void LANdiscovery_kill(DHT *dht); + +/* Is IP a local ip or not. */ +bool Local_ip(IP ip); + +/* checks if a given IP isn't routable + * + * return 0 if ip is a LAN ip. + * return -1 if it is not. + */ +int LAN_ip(IP ip); + + +#endif diff --git a/libs/libtox/src/toxcore/Messenger.c b/libs/libtox/src/toxcore/Messenger.c new file mode 100644 index 0000000000..4dd7d0c4a4 --- /dev/null +++ b/libs/libtox/src/toxcore/Messenger.c @@ -0,0 +1,3155 @@ +/* + * An implementation of a simple text chat only messenger on the tox network core. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Messenger.h" + +#include "logger.h" +#include "network.h" +#include "util.h" + +#include + +static void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status, void *userdata); +static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, + uint32_t length, uint8_t congestion_control); + +// friend_not_valid determines if the friendnumber passed is valid in the Messenger object +static uint8_t friend_not_valid(const Messenger *m, int32_t friendnumber) +{ + if ((unsigned int)friendnumber < m->numfriends) { + if (m->friendlist[friendnumber].status != 0) { + return 0; + } + } + + return 1; +} + +/* Set the size of the friend list to numfriends. + * + * return -1 if realloc fails. + */ +static int realloc_friendlist(Messenger *m, uint32_t num) +{ + if (num == 0) { + free(m->friendlist); + m->friendlist = NULL; + return 0; + } + + Friend *newfriendlist = (Friend *)realloc(m->friendlist, num * sizeof(Friend)); + + if (newfriendlist == NULL) { + return -1; + } + + m->friendlist = newfriendlist; + return 0; +} + +/* return the friend id associated to that public key. + * return -1 if no such friend. + */ +int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < m->numfriends; ++i) { + if (m->friendlist[i].status > 0) { + if (id_equal(real_pk, m->friendlist[i].real_pk)) { + return i; + } + } + } + + return -1; +} + +/* Copies the public key associated to that friend id into real_pk buffer. + * Make sure that real_pk is of size CRYPTO_PUBLIC_KEY_SIZE. + * + * return 0 if success. + * return -1 if failure. + */ +int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + memcpy(real_pk, m->friendlist[friendnumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + return 0; +} + +/* return friend connection id on success. + * return -1 if failure. + */ +int getfriendcon_id(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return m->friendlist[friendnumber].friendcon_id; +} + +/* + * return a uint16_t that represents the checksum of address of length len. + */ +static uint16_t address_checksum(const uint8_t *address, uint32_t len) +{ + uint8_t checksum[2] = {0}; + uint16_t check; + uint32_t i; + + for (i = 0; i < len; ++i) { + checksum[i % 2] ^= address[i]; + } + + memcpy(&check, checksum, sizeof(check)); + return check; +} + +/* Format: [real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] + * + * return FRIEND_ADDRESS_SIZE byte address to give to others. + */ +void getaddress(const Messenger *m, uint8_t *address) +{ + id_copy(address, m->net_crypto->self_public_key); + uint32_t nospam = get_nospam(&(m->fr)); + memcpy(address + CRYPTO_PUBLIC_KEY_SIZE, &nospam, sizeof(nospam)); + uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); + memcpy(address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(nospam), &checksum, sizeof(checksum)); +} + +static int send_online_packet(Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + uint8_t packet = PACKET_ID_ONLINE; + return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), &packet, sizeof(packet), 0) != -1; +} + +static int send_offline_packet(Messenger *m, int friendcon_id) +{ + uint8_t packet = PACKET_ID_OFFLINE; + return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, friendcon_id), &packet, + sizeof(packet), 0) != -1; +} + +static int m_handle_status(void *object, int i, uint8_t status, void *userdata); +static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t len, void *userdata); +static int m_handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length, + void *userdata); + +static int32_t init_new_friend(Messenger *m, const uint8_t *real_pk, uint8_t status) +{ + /* Resize the friend list if necessary. */ + if (realloc_friendlist(m, m->numfriends + 1) != 0) { + return FAERR_NOMEM; + } + + memset(&(m->friendlist[m->numfriends]), 0, sizeof(Friend)); + + int friendcon_id = new_friend_connection(m->fr_c, real_pk); + + if (friendcon_id == -1) { + return FAERR_NOMEM; + } + + uint32_t i; + + for (i = 0; i <= m->numfriends; ++i) { + if (m->friendlist[i].status == NOFRIEND) { + m->friendlist[i].status = status; + m->friendlist[i].friendcon_id = friendcon_id; + m->friendlist[i].friendrequest_lastsent = 0; + id_copy(m->friendlist[i].real_pk, real_pk); + m->friendlist[i].statusmessage_length = 0; + m->friendlist[i].userstatus = USERSTATUS_NONE; + m->friendlist[i].is_typing = 0; + m->friendlist[i].message_id = 0; + friend_connection_callbacks(m->fr_c, friendcon_id, MESSENGER_CALLBACK_INDEX, &m_handle_status, &m_handle_packet, + &m_handle_custom_lossy_packet, m, i); + + if (m->numfriends == i) { + ++m->numfriends; + } + + if (friend_con_connected(m->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { + send_online_packet(m, i); + } + + return i; + } + } + + return FAERR_NOMEM; +} + +/* + * Add a friend. + * Set the data that will be sent along with friend request. + * Address is the address of the friend (returned by getaddress of the friend you wish to add) it must be FRIEND_ADDRESS_SIZE bytes. + * data is the data and length is the length. + * + * return the friend number if success. + * return FA_TOOLONG if message length is too long. + * return FAERR_NOMESSAGE if no message (message length must be >= 1 byte). + * return FAERR_OWNKEY if user's own key. + * return FAERR_ALREADYSENT if friend request already sent or already a friend. + * return FAERR_BADCHECKSUM if bad checksum in address. + * return FAERR_SETNEWNOSPAM if the friend was already there but the nospam was different. + * (the nospam for that friend was set to the new one). + * return FAERR_NOMEM if increasing the friend list size fails. + */ +int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length) +{ + if (length > MAX_FRIEND_REQUEST_DATA_SIZE) { + return FAERR_TOOLONG; + } + + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + id_copy(real_pk, address); + + if (!public_key_valid(real_pk)) { + return FAERR_BADCHECKSUM; + } + + uint16_t check, checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); + memcpy(&check, address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t), sizeof(check)); + + if (check != checksum) { + return FAERR_BADCHECKSUM; + } + + if (length < 1) { + return FAERR_NOMESSAGE; + } + + if (id_equal(real_pk, m->net_crypto->self_public_key)) { + return FAERR_OWNKEY; + } + + int32_t friend_id = getfriend_id(m, real_pk); + + if (friend_id != -1) { + if (m->friendlist[friend_id].status >= FRIEND_CONFIRMED) { + return FAERR_ALREADYSENT; + } + + uint32_t nospam; + memcpy(&nospam, address + CRYPTO_PUBLIC_KEY_SIZE, sizeof(nospam)); + + if (m->friendlist[friend_id].friendrequest_nospam == nospam) { + return FAERR_ALREADYSENT; + } + + m->friendlist[friend_id].friendrequest_nospam = nospam; + return FAERR_SETNEWNOSPAM; + } + + int32_t ret = init_new_friend(m, real_pk, FRIEND_ADDED); + + if (ret < 0) { + return ret; + } + + m->friendlist[ret].friendrequest_timeout = FRIENDREQUEST_TIMEOUT; + memcpy(m->friendlist[ret].info, data, length); + m->friendlist[ret].info_size = length; + memcpy(&(m->friendlist[ret].friendrequest_nospam), address + CRYPTO_PUBLIC_KEY_SIZE, sizeof(uint32_t)); + + return ret; +} + +int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk) +{ + if (getfriend_id(m, real_pk) != -1) { + return FAERR_ALREADYSENT; + } + + if (!public_key_valid(real_pk)) { + return FAERR_BADCHECKSUM; + } + + if (id_equal(real_pk, m->net_crypto->self_public_key)) { + return FAERR_OWNKEY; + } + + return init_new_friend(m, real_pk, FRIEND_CONFIRMED); +} + +static int clear_receipts(Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + struct Receipts *receipts = m->friendlist[friendnumber].receipts_start; + + while (receipts) { + struct Receipts *temp_r = receipts->next; + free(receipts); + receipts = temp_r; + } + + m->friendlist[friendnumber].receipts_start = NULL; + m->friendlist[friendnumber].receipts_end = NULL; + return 0; +} + +static int add_receipt(Messenger *m, int32_t friendnumber, uint32_t packet_num, uint32_t msg_id) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + struct Receipts *new_receipts = (struct Receipts *)calloc(1, sizeof(struct Receipts)); + + if (!new_receipts) { + return -1; + } + + new_receipts->packet_num = packet_num; + new_receipts->msg_id = msg_id; + + if (!m->friendlist[friendnumber].receipts_start) { + m->friendlist[friendnumber].receipts_start = new_receipts; + } else { + m->friendlist[friendnumber].receipts_end->next = new_receipts; + } + + m->friendlist[friendnumber].receipts_end = new_receipts; + new_receipts->next = NULL; + return 0; +} +/* + * return -1 on failure. + * return 0 if packet was received. + */ +static int friend_received_packet(const Messenger *m, int32_t friendnumber, uint32_t number) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return cryptpacket_received(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), number); +} + +static int do_receipts(Messenger *m, int32_t friendnumber, void *userdata) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + struct Receipts *receipts = m->friendlist[friendnumber].receipts_start; + + while (receipts) { + struct Receipts *temp_r = receipts->next; + + if (friend_received_packet(m, friendnumber, receipts->packet_num) == -1) { + break; + } + + if (m->read_receipt) { + (*m->read_receipt)(m, friendnumber, receipts->msg_id, userdata); + } + + free(receipts); + m->friendlist[friendnumber].receipts_start = temp_r; + receipts = temp_r; + } + + if (!m->friendlist[friendnumber].receipts_start) { + m->friendlist[friendnumber].receipts_end = NULL; + } + + return 0; +} + +/* Remove a friend. + * + * return 0 if success. + * return -1 if failure. + */ +int m_delfriend(Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friend_connectionstatuschange_internal) { + m->friend_connectionstatuschange_internal(m, friendnumber, 0, m->friend_connectionstatuschange_internal_userdata); + } + + clear_receipts(m, friendnumber); + remove_request_received(&(m->fr), m->friendlist[friendnumber].real_pk); + friend_connection_callbacks(m->fr_c, m->friendlist[friendnumber].friendcon_id, MESSENGER_CALLBACK_INDEX, 0, 0, 0, 0, 0); + + if (friend_con_connected(m->fr_c, m->friendlist[friendnumber].friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { + send_offline_packet(m, m->friendlist[friendnumber].friendcon_id); + } + + kill_friend_connection(m->fr_c, m->friendlist[friendnumber].friendcon_id); + memset(&(m->friendlist[friendnumber]), 0, sizeof(Friend)); + uint32_t i; + + for (i = m->numfriends; i != 0; --i) { + if (m->friendlist[i - 1].status != NOFRIEND) { + break; + } + } + + m->numfriends = i; + + if (realloc_friendlist(m, m->numfriends) != 0) { + return FAERR_NOMEM; + } + + return 0; +} + +int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status == FRIEND_ONLINE) { + bool direct_connected = 0; + unsigned int num_online_relays = 0; + int crypt_conn_id = friend_connection_crypt_connection_id(m->fr_c, m->friendlist[friendnumber].friendcon_id); + crypto_connection_status(m->net_crypto, crypt_conn_id, &direct_connected, &num_online_relays); + + if (direct_connected) { + return CONNECTION_UDP; + } + + if (num_online_relays) { + return CONNECTION_TCP; + } + + return CONNECTION_UNKNOWN; + } + + return CONNECTION_NONE; +} + +int m_friend_exists(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + return 1; +} + +/* Send a message of type. + * + * return -1 if friend not valid. + * return -2 if too large. + * return -3 if friend not online. + * return -4 if send failed (because queue is full). + * return -5 if bad type. + * return 0 if success. + */ +int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length, + uint32_t *message_id) +{ + if (type > MESSAGE_ACTION) { + return -5; + } + + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length >= MAX_CRYPTO_DATA_SIZE) { + return -2; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -3; + } + + VLA(uint8_t, packet, length + 1); + packet[0] = type + PACKET_ID_MESSAGE; + + if (length != 0) { + memcpy(packet + 1, message, length); + } + + int64_t packet_num = write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), packet, length + 1, 0); + + if (packet_num == -1) { + return -4; + } + + uint32_t msg_id = ++m->friendlist[friendnumber].message_id; + + add_receipt(m, friendnumber, packet_num, msg_id); + + if (message_id) { + *message_id = msg_id; + } + + return 0; +} + +/* Send a name packet to friendnumber. + * length is the length with the NULL terminator. + */ +static int m_sendname(const Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length) +{ + if (length > MAX_NAME_LENGTH) { + return 0; + } + + return write_cryptpacket_id(m, friendnumber, PACKET_ID_NICKNAME, name, length, 0); +} + +/* Set the name and name_length of a friend. + * + * return 0 if success. + * return -1 if failure. + */ +int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length > MAX_NAME_LENGTH || length == 0) { + return -1; + } + + m->friendlist[friendnumber].name_length = length; + memcpy(m->friendlist[friendnumber].name, name, length); + return 0; +} + +/* Set our nickname + * name must be a string of maximum MAX_NAME_LENGTH length. + * length must be at least 1 byte. + * length is the length of name with the NULL terminator. + * + * return 0 if success. + * return -1 if failure. + */ +int setname(Messenger *m, const uint8_t *name, uint16_t length) +{ + if (length > MAX_NAME_LENGTH) { + return -1; + } + + if (m->name_length == length && (length == 0 || memcmp(name, m->name, length) == 0)) { + return 0; + } + + if (length) { + memcpy(m->name, name, length); + } + + m->name_length = length; + uint32_t i; + + for (i = 0; i < m->numfriends; ++i) { + m->friendlist[i].name_sent = 0; + } + + return 0; +} + +/* Get our nickname and put it in name. + * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. + * + * return the length of the name. + */ +uint16_t getself_name(const Messenger *m, uint8_t *name) +{ + if (name == NULL) { + return 0; + } + + memcpy(name, m->name, m->name_length); + + return m->name_length; +} + +/* Get name of friendnumber and put it in name. + * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. + * + * return length of name if success. + * return -1 if failure. + */ +int getname(const Messenger *m, int32_t friendnumber, uint8_t *name) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + memcpy(name, m->friendlist[friendnumber].name, m->friendlist[friendnumber].name_length); + return m->friendlist[friendnumber].name_length; +} + +int m_get_name_size(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return m->friendlist[friendnumber].name_length; +} + +int m_get_self_name_size(const Messenger *m) +{ + return m->name_length; +} + +int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length) +{ + if (length > MAX_STATUSMESSAGE_LENGTH) { + return -1; + } + + if (m->statusmessage_length == length && (length == 0 || memcmp(m->statusmessage, status, length) == 0)) { + return 0; + } + + if (length) { + memcpy(m->statusmessage, status, length); + } + + m->statusmessage_length = length; + + uint32_t i; + + for (i = 0; i < m->numfriends; ++i) { + m->friendlist[i].statusmessage_sent = 0; + } + + return 0; +} + +int m_set_userstatus(Messenger *m, uint8_t status) +{ + if (status >= USERSTATUS_INVALID) { + return -1; + } + + if (m->userstatus == status) { + return 0; + } + + m->userstatus = (USERSTATUS)status; + uint32_t i; + + for (i = 0; i < m->numfriends; ++i) { + m->friendlist[i].userstatus_sent = 0; + } + + return 0; +} + +/* return the size of friendnumber's user status. + * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. + */ +int m_get_statusmessage_size(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return m->friendlist[friendnumber].statusmessage_length; +} + +/* Copy the user status of friendnumber into buf, truncating if needed to maxlen + * bytes, use m_get_statusmessage_size to find out how much you need to allocate. + */ +int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + int msglen = MIN(maxlen, m->friendlist[friendnumber].statusmessage_length); + + memcpy(buf, m->friendlist[friendnumber].statusmessage, msglen); + memset(buf + msglen, 0, maxlen - msglen); + return msglen; +} + +/* return the size of friendnumber's user status. + * Guaranteed to be at most MAX_STATUSMESSAGE_LENGTH. + */ +int m_get_self_statusmessage_size(const Messenger *m) +{ + return m->statusmessage_length; +} + +int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf) +{ + memcpy(buf, m->statusmessage, m->statusmessage_length); + return m->statusmessage_length; +} + +uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return USERSTATUS_INVALID; + } + + uint8_t status = m->friendlist[friendnumber].userstatus; + + if (status >= USERSTATUS_INVALID) { + status = USERSTATUS_NONE; + } + + return status; +} + +uint8_t m_get_self_userstatus(const Messenger *m) +{ + return m->userstatus; +} + +uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return UINT64_MAX; + } + + return m->friendlist[friendnumber].last_seen_time; +} + +int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing) +{ + if (is_typing != 0 && is_typing != 1) { + return -1; + } + + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].user_istyping == is_typing) { + return 0; + } + + m->friendlist[friendnumber].user_istyping = is_typing; + m->friendlist[friendnumber].user_istyping_sent = 0; + + return 0; +} + +int m_get_istyping(const Messenger *m, int32_t friendnumber) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + return m->friendlist[friendnumber].is_typing; +} + +static int send_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_STATUSMESSAGE, status, length, 0); +} + +static int send_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_USERSTATUS, &status, sizeof(status), 0); +} + +static int send_user_istyping(const Messenger *m, int32_t friendnumber, uint8_t is_typing) +{ + uint8_t typing = is_typing; + return write_cryptpacket_id(m, friendnumber, PACKET_ID_TYPING, &typing, sizeof(typing), 0); +} + +static int set_friend_statusmessage(const Messenger *m, int32_t friendnumber, const uint8_t *status, uint16_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length > MAX_STATUSMESSAGE_LENGTH) { + return -1; + } + + if (length) { + memcpy(m->friendlist[friendnumber].statusmessage, status, length); + } + + m->friendlist[friendnumber].statusmessage_length = length; + return 0; +} + +static void set_friend_userstatus(const Messenger *m, int32_t friendnumber, uint8_t status) +{ + m->friendlist[friendnumber].userstatus = (USERSTATUS)status; +} + +static void set_friend_typing(const Messenger *m, int32_t friendnumber, uint8_t is_typing) +{ + m->friendlist[friendnumber].is_typing = is_typing; +} + +void m_callback_log(Messenger *m, logger_cb *function, void *context, void *userdata) +{ + logger_callback_log(m->log, function, context, userdata); +} + +/* Set the function that will be executed when a friend request is received. */ +void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, size_t, + void *)) +{ + callback_friendrequest(&(m->fr), (void (*)(void *, const uint8_t *, const uint8_t *, size_t, void *))function, m); +} + +/* Set the function that will be executed when a message from a friend is received. */ +void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, const uint8_t *, + size_t, void *)) +{ + m->friend_message = function; +} + +void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *)) +{ + m->friend_namechange = function; +} + +void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *)) +{ + m->friend_statusmessagechange = function; +} + +void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *)) +{ + m->friend_userstatuschange = function; +} + +void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, uint32_t, bool, void *)) +{ + m->friend_typingchange = function; +} + +void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, void *)) +{ + m->read_receipt = function; +} + +void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *)) +{ + m->friend_connectionstatuschange = function; +} + +void m_callback_core_connection(Messenger *m, void (*function)(Messenger *m, unsigned int, void *)) +{ + m->core_connection_change = function; +} + +void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), + void *userdata) +{ + m->friend_connectionstatuschange_internal = function; + m->friend_connectionstatuschange_internal_userdata = userdata; +} + +static void check_friend_tcp_udp(Messenger *m, int32_t friendnumber, void *userdata) +{ + int last_connection_udp_tcp = m->friendlist[friendnumber].last_connection_udp_tcp; + + int ret = m_get_friend_connectionstatus(m, friendnumber); + + if (ret == -1) { + return; + } + + if (ret == CONNECTION_UNKNOWN) { + if (last_connection_udp_tcp == CONNECTION_UDP) { + return; + } + + ret = CONNECTION_TCP; + } + + if (last_connection_udp_tcp != ret) { + if (m->friend_connectionstatuschange) { + m->friend_connectionstatuschange(m, friendnumber, ret, userdata); + } + } + + m->friendlist[friendnumber].last_connection_udp_tcp = ret; +} + +static void break_files(const Messenger *m, int32_t friendnumber); +static void check_friend_connectionstatus(Messenger *m, int32_t friendnumber, uint8_t status, void *userdata) +{ + if (status == NOFRIEND) { + return; + } + + const uint8_t was_online = m->friendlist[friendnumber].status == FRIEND_ONLINE; + const uint8_t is_online = status == FRIEND_ONLINE; + + if (is_online != was_online) { + if (was_online) { + break_files(m, friendnumber); + clear_receipts(m, friendnumber); + } else { + m->friendlist[friendnumber].name_sent = 0; + m->friendlist[friendnumber].userstatus_sent = 0; + m->friendlist[friendnumber].statusmessage_sent = 0; + m->friendlist[friendnumber].user_istyping_sent = 0; + } + + m->friendlist[friendnumber].status = status; + + check_friend_tcp_udp(m, friendnumber, userdata); + + if (m->friend_connectionstatuschange_internal) { + m->friend_connectionstatuschange_internal(m, friendnumber, is_online, + m->friend_connectionstatuschange_internal_userdata); + } + } +} + +void set_friend_status(Messenger *m, int32_t friendnumber, uint8_t status, void *userdata) +{ + check_friend_connectionstatus(m, friendnumber, status, userdata); + m->friendlist[friendnumber].status = status; +} + +static int write_cryptpacket_id(const Messenger *m, int32_t friendnumber, uint8_t packet_id, const uint8_t *data, + uint32_t length, uint8_t congestion_control) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + if (length >= MAX_CRYPTO_DATA_SIZE || m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return 0; + } + + VLA(uint8_t, packet, length + 1); + packet[0] = packet_id; + + if (length != 0) { + memcpy(packet + 1, data, length); + } + + return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), packet, length + 1, congestion_control) != -1; +} + +/**********CONFERENCES************/ + + +/* Set the callback for conference invites. + * + * Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) + */ +void m_callback_conference_invite(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, + void *)) +{ + m->conference_invite = function; +} + + +/* Send a conference invite packet. + * + * return 1 on success + * return 0 on failure + */ +int send_conference_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_INVITE_CONFERENCE, data, length, 0); +} + +/****************FILE SENDING*****************/ + + +/* Set the callback for file send requests. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint32_t filetype, uint64_t filesize, uint8_t *filename, size_t filename_length, void *userdata) + */ +void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint32_t, uint64_t, + const uint8_t *, size_t, void *)) +{ + m->file_sendrequest = function; +} + +/* Set the callback for file control requests. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata) + * + */ +void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *)) +{ + m->file_filecontrol = function; +} + +/* Set the callback for file data. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata) + * + */ +void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *, + size_t, void *)) +{ + m->file_filedata = function; +} + +/* Set the callback for file request chunk. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata) + * + */ +void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *)) +{ + m->file_reqchunk = function; +} + +#define MAX_FILENAME_LENGTH 255 + +/* Copy the file transfer file id to file_id + * + * return 0 on success. + * return -1 if friend not valid. + * return -2 if filenumber not valid + */ +int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -2; + } + + uint32_t temp_filenum; + uint8_t send_receive, file_number; + + if (filenumber >= (1 << 16)) { + send_receive = 1; + temp_filenum = (filenumber >> 16) - 1; + } else { + send_receive = 0; + temp_filenum = filenumber; + } + + if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) { + return -2; + } + + file_number = temp_filenum; + + struct File_Transfers *ft; + + if (send_receive) { + ft = &m->friendlist[friendnumber].file_receiving[file_number]; + } else { + ft = &m->friendlist[friendnumber].file_sending[file_number]; + } + + if (ft->status == FILESTATUS_NONE) { + return -2; + } + + memcpy(file_id, ft->id, FILE_ID_LENGTH); + return 0; +} + +/* Send a file send request. + * Maximum filename length is 255 bytes. + * return 1 on success + * return 0 on failure + */ +static int file_sendrequest(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint32_t file_type, + uint64_t filesize, const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + if (filename_length > MAX_FILENAME_LENGTH) { + return 0; + } + + VLA(uint8_t, packet, 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH + filename_length); + packet[0] = filenumber; + file_type = net_htonl(file_type); + memcpy(packet + 1, &file_type, sizeof(file_type)); + host_to_net((uint8_t *)&filesize, sizeof(filesize)); + memcpy(packet + 1 + sizeof(file_type), &filesize, sizeof(filesize)); + memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize), file_id, FILE_ID_LENGTH); + + if (filename_length) { + memcpy(packet + 1 + sizeof(file_type) + sizeof(filesize) + FILE_ID_LENGTH, filename, filename_length); + } + + return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_SENDREQUEST, packet, SIZEOF_VLA(packet), 0); +} + +/* Send a file send request. + * Maximum filename length is 255 bytes. + * return file number on success + * return -1 if friend not found. + * return -2 if filename length invalid. + * return -3 if no more file sending slots left. + * return -4 if could not send packet (friend offline). + * + */ +long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize, + const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (filename_length > MAX_FILENAME_LENGTH) { + return -2; + } + + uint32_t i; + + for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { + if (m->friendlist[friendnumber].file_sending[i].status == FILESTATUS_NONE) { + break; + } + } + + if (i == MAX_CONCURRENT_FILE_PIPES) { + return -3; + } + + if (file_sendrequest(m, friendnumber, i, file_type, filesize, file_id, filename, filename_length) == 0) { + return -4; + } + + struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i]; + + ft->status = FILESTATUS_NOT_ACCEPTED; + + ft->size = filesize; + + ft->transferred = 0; + + ft->requested = 0; + + ft->slots_allocated = 0; + + ft->paused = FILE_PAUSE_NOT; + + memcpy(ft->id, file_id, FILE_ID_LENGTH); + + ++m->friendlist[friendnumber].num_sending_files; + + return i; +} + +static int send_file_control_packet(const Messenger *m, int32_t friendnumber, uint8_t send_receive, uint8_t filenumber, + uint8_t control_type, uint8_t *data, uint16_t data_length) +{ + if ((unsigned int)(1 + 3 + data_length) > MAX_CRYPTO_DATA_SIZE) { + return -1; + } + + VLA(uint8_t, packet, 3 + data_length); + + packet[0] = send_receive; + packet[1] = filenumber; + packet[2] = control_type; + + if (data_length) { + memcpy(packet + 3, data, data_length); + } + + return write_cryptpacket_id(m, friendnumber, PACKET_ID_FILE_CONTROL, packet, SIZEOF_VLA(packet), 0); +} + +/* Send a file control request. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if file number invalid. + * return -4 if file control is bad. + * return -5 if file already paused. + * return -6 if resume file failed because it was only paused by the other. + * return -7 if resume file failed because it wasn't paused. + * return -8 if packet failed to send. + */ +int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -2; + } + + uint32_t temp_filenum; + uint8_t send_receive, file_number; + + if (filenumber >= (1 << 16)) { + send_receive = 1; + temp_filenum = (filenumber >> 16) - 1; + } else { + send_receive = 0; + temp_filenum = filenumber; + } + + if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) { + return -3; + } + + file_number = temp_filenum; + + struct File_Transfers *ft; + + if (send_receive) { + ft = &m->friendlist[friendnumber].file_receiving[file_number]; + } else { + ft = &m->friendlist[friendnumber].file_sending[file_number]; + } + + if (ft->status == FILESTATUS_NONE) { + return -3; + } + + if (control > FILECONTROL_KILL) { + return -4; + } + + if (control == FILECONTROL_PAUSE && ((ft->paused & FILE_PAUSE_US) || ft->status != FILESTATUS_TRANSFERRING)) { + return -5; + } + + if (control == FILECONTROL_ACCEPT) { + if (ft->status == FILESTATUS_TRANSFERRING) { + if (!(ft->paused & FILE_PAUSE_US)) { + if (ft->paused & FILE_PAUSE_OTHER) { + return -6; + } + + return -7; + } + } else { + if (ft->status != FILESTATUS_NOT_ACCEPTED) { + return -7; + } + + if (!send_receive) { + return -6; + } + } + } + + if (send_file_control_packet(m, friendnumber, send_receive, file_number, control, 0, 0)) { + if (control == FILECONTROL_KILL) { + ft->status = FILESTATUS_NONE; + + if (send_receive == 0) { + --m->friendlist[friendnumber].num_sending_files; + } + } else if (control == FILECONTROL_PAUSE) { + ft->paused |= FILE_PAUSE_US; + } else if (control == FILECONTROL_ACCEPT) { + ft->status = FILESTATUS_TRANSFERRING; + + if (ft->paused & FILE_PAUSE_US) { + ft->paused ^= FILE_PAUSE_US; + } + } + } else { + return -8; + } + + return 0; +} + +/* Send a seek file control request. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if file number invalid. + * return -4 if not receiving file. + * return -5 if file status wrong. + * return -6 if position bad. + * return -8 if packet failed to send. + */ +int file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -2; + } + + if (filenumber < (1 << 16)) { + // Not receiving. + return -4; + } + + uint32_t temp_filenum = (filenumber >> 16) - 1; + + if (temp_filenum >= MAX_CONCURRENT_FILE_PIPES) { + return -3; + } + + assert(temp_filenum <= UINT8_MAX); + uint8_t file_number = temp_filenum; + + // We're always receiving at this point. + struct File_Transfers *ft = &m->friendlist[friendnumber].file_receiving[file_number]; + + if (ft->status == FILESTATUS_NONE) { + return -3; + } + + if (ft->status != FILESTATUS_NOT_ACCEPTED) { + return -5; + } + + if (position >= ft->size) { + return -6; + } + + uint64_t sending_pos = position; + host_to_net((uint8_t *)&sending_pos, sizeof(sending_pos)); + + if (send_file_control_packet(m, friendnumber, 1, file_number, FILECONTROL_SEEK, (uint8_t *)&sending_pos, + sizeof(sending_pos))) { + ft->transferred = position; + } else { + return -8; + } + + return 0; +} + +/* return packet number on success. + * return -1 on failure. + */ +static int64_t send_file_data_packet(const Messenger *m, int32_t friendnumber, uint8_t filenumber, const uint8_t *data, + uint16_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + VLA(uint8_t, packet, 2 + length); + packet[0] = PACKET_ID_FILE_DATA; + packet[1] = filenumber; + + if (length) { + memcpy(packet + 2, data, length); + } + + return write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), packet, SIZEOF_VLA(packet), 1); +} + +#define MAX_FILE_DATA_SIZE (MAX_CRYPTO_DATA_SIZE - 2) +#define MIN_SLOTS_FREE (CRYPTO_MIN_QUEUE_LENGTH / 4) +/* Send file data. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if filenumber invalid. + * return -4 if file transfer not transferring. + * return -5 if bad data size. + * return -6 if packet queue full. + * return -7 if wrong position. + */ +int file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, + uint16_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -2; + } + + if (filenumber >= MAX_CONCURRENT_FILE_PIPES) { + return -3; + } + + struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[filenumber]; + + if (ft->status != FILESTATUS_TRANSFERRING) { + return -4; + } + + if (length > MAX_FILE_DATA_SIZE) { + return -5; + } + + if (ft->size - ft->transferred < length) { + return -5; + } + + if (ft->size != UINT64_MAX && length != MAX_FILE_DATA_SIZE && (ft->transferred + length) != ft->size) { + return -5; + } + + if (position != ft->transferred || (ft->requested <= position && ft->size != 0)) { + return -7; + } + + /* Prevent file sending from filling up the entire buffer preventing messages from being sent. + * TODO(irungentoo): remove */ + if (crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id)) < MIN_SLOTS_FREE) { + return -6; + } + + int64_t ret = send_file_data_packet(m, friendnumber, filenumber, data, length); + + if (ret != -1) { + // TODO(irungentoo): record packet ids to check if other received complete file. + ft->transferred += length; + + if (ft->slots_allocated) { + --ft->slots_allocated; + } + + if (length != MAX_FILE_DATA_SIZE || ft->size == ft->transferred) { + ft->status = FILESTATUS_FINISHED; + ft->last_packet_number = ret; + } + + return 0; + } + + return -6; +} + +/* Give the number of bytes left to be sent/received. + * + * send_receive is 0 if we want the sending files, 1 if we want the receiving. + * + * return number of bytes remaining to be sent/received on success + * return 0 on failure + */ +uint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive) +{ + if (friend_not_valid(m, friendnumber)) { + return 0; + } + + if (send_receive == 0) { + if (m->friendlist[friendnumber].file_sending[filenumber].status == FILESTATUS_NONE) { + return 0; + } + + return m->friendlist[friendnumber].file_sending[filenumber].size - + m->friendlist[friendnumber].file_sending[filenumber].transferred; + } + + if (m->friendlist[friendnumber].file_receiving[filenumber].status == FILESTATUS_NONE) { + return 0; + } + + return m->friendlist[friendnumber].file_receiving[filenumber].size - + m->friendlist[friendnumber].file_receiving[filenumber].transferred; +} + +static void do_reqchunk_filecb(Messenger *m, int32_t friendnumber, void *userdata) +{ + if (!m->friendlist[friendnumber].num_sending_files) { + return; + } + + int free_slots = crypto_num_free_sendqueue_slots(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id)); + + if (free_slots < MIN_SLOTS_FREE) { + free_slots = 0; + } else { + free_slots -= MIN_SLOTS_FREE; + } + + unsigned int i, num = m->friendlist[friendnumber].num_sending_files; + + for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { + struct File_Transfers *ft = &m->friendlist[friendnumber].file_sending[i]; + + if (ft->status != FILESTATUS_NONE) { + --num; + + if (ft->status == FILESTATUS_FINISHED) { + /* Check if file was entirely sent. */ + if (friend_received_packet(m, friendnumber, ft->last_packet_number) == 0) { + if (m->file_reqchunk) { + (*m->file_reqchunk)(m, friendnumber, i, ft->transferred, 0, userdata); + } + + ft->status = FILESTATUS_NONE; + --m->friendlist[friendnumber].num_sending_files; + } + } + + /* TODO(irungentoo): if file is too slow, switch to the next. */ + if (ft->slots_allocated > (unsigned int)free_slots) { + free_slots = 0; + } else { + free_slots -= ft->slots_allocated; + } + } + + while (ft->status == FILESTATUS_TRANSFERRING && (ft->paused == FILE_PAUSE_NOT)) { + if (max_speed_reached(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id))) { + free_slots = 0; + } + + if (free_slots == 0) { + break; + } + + uint16_t length = MAX_FILE_DATA_SIZE; + + if (ft->size == 0) { + /* Send 0 data to friend if file is 0 length. */ + file_data(m, friendnumber, i, 0, 0, 0); + break; + } + + if (ft->size == ft->requested) { + break; + } + + if (ft->size - ft->requested < length) { + length = ft->size - ft->requested; + } + + ++ft->slots_allocated; + + uint64_t position = ft->requested; + ft->requested += length; + + if (m->file_reqchunk) { + (*m->file_reqchunk)(m, friendnumber, i, position, length, userdata); + } + + --free_slots; + } + + if (num == 0) { + break; + } + } +} + +/* Run this when the friend disconnects. + * Kill all current file transfers. + */ +static void break_files(const Messenger *m, int32_t friendnumber) +{ + uint32_t i; + + // TODO(irungentoo): Inform the client which file transfers get killed with a callback? + for (i = 0; i < MAX_CONCURRENT_FILE_PIPES; ++i) { + if (m->friendlist[friendnumber].file_sending[i].status != FILESTATUS_NONE) { + m->friendlist[friendnumber].file_sending[i].status = FILESTATUS_NONE; + } + + if (m->friendlist[friendnumber].file_receiving[i].status != FILESTATUS_NONE) { + m->friendlist[friendnumber].file_receiving[i].status = FILESTATUS_NONE; + } + } +} + +static struct File_Transfers *get_file_transfer(uint8_t receive_send, uint8_t filenumber, + uint32_t *real_filenumber, Friend *sender) +{ + struct File_Transfers *ft; + + if (receive_send == 0) { + *real_filenumber = (filenumber + 1) << 16; + ft = &sender->file_receiving[filenumber]; + } else { + *real_filenumber = filenumber; + ft = &sender->file_sending[filenumber]; + } + + if (ft->status == FILESTATUS_NONE) { + return NULL; + } + + return ft; +} + +/* return -1 on failure, 0 on success. + */ +static int handle_filecontrol(Messenger *m, int32_t friendnumber, uint8_t receive_send, uint8_t filenumber, + uint8_t control_type, const uint8_t *data, uint16_t length, void *userdata) +{ + if (receive_send > 1) { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): receive_send value is invalid (should be 0 or 1): %d", + friendnumber, filenumber, receive_send); + return -1; + } + + uint32_t real_filenumber; + struct File_Transfers *ft = get_file_transfer(receive_send, filenumber, &real_filenumber, &m->friendlist[friendnumber]); + + if (ft == NULL) { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): file transfer does not exist; telling the other to kill it", + friendnumber, filenumber); + send_file_control_packet(m, friendnumber, !receive_send, filenumber, FILECONTROL_KILL, 0, 0); + return -1; + } + + switch (control_type) { + case FILECONTROL_ACCEPT: { + if (receive_send && ft->status == FILESTATUS_NOT_ACCEPTED) { + ft->status = FILESTATUS_TRANSFERRING; + } else { + if (ft->paused & FILE_PAUSE_OTHER) { + ft->paused ^= FILE_PAUSE_OTHER; + } else { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): friend told us to resume file transfer that wasn't paused", + friendnumber, filenumber); + return -1; + } + } + + if (m->file_filecontrol) { + m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata); + } + + return 0; + } + + case FILECONTROL_PAUSE: { + if ((ft->paused & FILE_PAUSE_OTHER) || ft->status != FILESTATUS_TRANSFERRING) { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): friend told us to pause file transfer that is already paused", + friendnumber, filenumber); + return -1; + } + + ft->paused |= FILE_PAUSE_OTHER; + + if (m->file_filecontrol) { + m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata); + } + + return 0; + } + + case FILECONTROL_KILL: { + if (m->file_filecontrol) { + m->file_filecontrol(m, friendnumber, real_filenumber, control_type, userdata); + } + + ft->status = FILESTATUS_NONE; + + if (receive_send) { + --m->friendlist[friendnumber].num_sending_files; + } + + return 0; + } + + case FILECONTROL_SEEK: { + uint64_t position; + + if (length != sizeof(position)) { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): expected payload of length %d, but got %d", + friendnumber, filenumber, (uint32_t)sizeof(position), length); + return -1; + } + + /* seek can only be sent by the receiver to seek before resuming broken transfers. */ + if (ft->status != FILESTATUS_NOT_ACCEPTED || !receive_send) { + LOGGER_DEBUG(m->log, + "file control (friend %d, file %d): seek was either sent by a sender or by the receiver after accepting", + friendnumber, filenumber); + return -1; + } + + memcpy(&position, data, sizeof(position)); + net_to_host((uint8_t *) &position, sizeof(position)); + + if (position >= ft->size) { + LOGGER_DEBUG(m->log, + "file control (friend %d, file %d): seek position %lld exceeds file size %lld", + friendnumber, filenumber, (unsigned long long)position, (unsigned long long)ft->size); + return -1; + } + + ft->transferred = ft->requested = position; + return 0; + } + + default: { + LOGGER_DEBUG(m->log, "file control (friend %d, file %d): invalid file control: %d", + friendnumber, filenumber, control_type); + return -1; + } + } +} + +/**************************************/ + +/* Set the callback for msi packets. + * + * Function(Messenger *m, int friendnumber, uint8_t *data, uint16_t length, void *userdata) + */ +void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, void *), + void *userdata) +{ + m->msi_packet = function; + m->msi_packet_userdata = userdata; +} + +/* Send an msi packet. + * + * return 1 on success + * return 0 on failure + */ +int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length) +{ + return write_cryptpacket_id(m, friendnumber, PACKET_ID_MSI, data, length, 0); +} + +static int m_handle_custom_lossy_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Messenger *m = (Messenger *)object; + + if (friend_not_valid(m, friend_num)) { + return 1; + } + + if (packet[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED)) { + if (m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] % PACKET_LOSSY_AV_RESERVED].function) { + return m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] % PACKET_LOSSY_AV_RESERVED].function( + m, friend_num, packet, length, m->friendlist[friend_num].lossy_rtp_packethandlers[packet[0] % + PACKET_LOSSY_AV_RESERVED].object); + } + + return 1; + } + + if (m->lossy_packethandler) { + m->lossy_packethandler(m, friend_num, packet, length, userdata); + } + + return 1; +} + +void custom_lossy_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, size_t len, void *object)) +{ + m->lossy_packethandler = packet_handler_callback; +} + +int m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte, int (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object), void *object) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (byte < PACKET_ID_LOSSY_RANGE_START) { + return -1; + } + + if (byte >= (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED)) { + return -1; + } + + m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_LOSSY_AV_RESERVED].function = + packet_handler_callback; + m->friendlist[friendnumber].lossy_rtp_packethandlers[byte % PACKET_LOSSY_AV_RESERVED].object = object; + return 0; +} + + +int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -2; + } + + if (data[0] < PACKET_ID_LOSSY_RANGE_START) { + return -3; + } + + if (data[0] >= (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE)) { + return -3; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -4; + } + + if (send_lossy_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), data, length) == -1) { + return -5; + } + + return 0; +} + +static int handle_custom_lossless_packet(void *object, int friend_num, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Messenger *m = (Messenger *)object; + + if (friend_not_valid(m, friend_num)) { + return -1; + } + + if (packet[0] < PACKET_ID_LOSSLESS_RANGE_START) { + return -1; + } + + if (packet[0] >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE)) { + return -1; + } + + if (m->lossless_packethandler) { + m->lossless_packethandler(m, friend_num, packet, length, userdata); + } + + return 1; +} + +void custom_lossless_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, size_t len, void *object)) +{ + m->lossless_packethandler = packet_handler_callback; +} + +int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length) +{ + if (friend_not_valid(m, friendnumber)) { + return -1; + } + + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -2; + } + + if (data[0] < PACKET_ID_LOSSLESS_RANGE_START) { + return -3; + } + + if (data[0] >= (PACKET_ID_LOSSLESS_RANGE_START + PACKET_ID_LOSSLESS_RANGE_SIZE)) { + return -3; + } + + if (m->friendlist[friendnumber].status != FRIEND_ONLINE) { + return -4; + } + + if (write_cryptpacket(m->net_crypto, friend_connection_crypt_connection_id(m->fr_c, + m->friendlist[friendnumber].friendcon_id), data, length, 1) == -1) { + return -5; + } + + return 0; +} + +/* Function to filter out some friend requests*/ +static int friend_already_added(const uint8_t *real_pk, void *data) +{ + const Messenger *m = (const Messenger *)data; + + if (getfriend_id(m, real_pk) == -1) { + return 0; + } + + return -1; +} + +/* Run this at startup. */ +Messenger *new_messenger(Messenger_Options *options, unsigned int *error) +{ + if (!options) { + return NULL; + } + + Messenger *m = (Messenger *)calloc(1, sizeof(Messenger)); + + if (error) { + *error = MESSENGER_ERROR_OTHER; + } + + if (!m) { + return NULL; + } + + Logger *log = NULL; + + if (options->log_callback) { + log = logger_new(); + + if (log != NULL) { + logger_callback_log(log, options->log_callback, m, options->log_user_data); + } + } + + m->log = log; + + unsigned int net_err = 0; + + if (options->udp_disabled) { + /* this is the easiest way to completely disable UDP without changing too much code. */ + m->net = (Networking_Core *)calloc(1, sizeof(Networking_Core)); + } else { + IP ip; + ip_init(&ip, options->ipv6enabled); + m->net = new_networking_ex(log, ip, options->port_range[0], options->port_range[1], &net_err); + } + + if (m->net == NULL) { + free(m); + + if (error && net_err == 1) { + *error = MESSENGER_ERROR_PORT; + } + + return NULL; + } + + m->dht = new_DHT(m->log, m->net, options->hole_punching_enabled); + + if (m->dht == NULL) { + kill_networking(m->net); + free(m); + return NULL; + } + + m->net_crypto = new_net_crypto(m->log, m->dht, &options->proxy_info); + + if (m->net_crypto == NULL) { + kill_networking(m->net); + kill_DHT(m->dht); + free(m); + return NULL; + } + + m->onion = new_onion(m->dht); + m->onion_a = new_onion_announce(m->dht); + m->onion_c = new_onion_client(m->net_crypto); + m->fr_c = new_friend_connections(m->onion_c, options->local_discovery_enabled); + + if (!(m->onion && m->onion_a && m->onion_c)) { + kill_friend_connections(m->fr_c); + kill_onion(m->onion); + kill_onion_announce(m->onion_a); + kill_onion_client(m->onion_c); + kill_net_crypto(m->net_crypto); + kill_DHT(m->dht); + kill_networking(m->net); + free(m); + return NULL; + } + + if (options->tcp_server_port) { + m->tcp_server = new_TCP_server(options->ipv6enabled, 1, &options->tcp_server_port, m->dht->self_secret_key, m->onion); + + if (m->tcp_server == NULL) { + kill_friend_connections(m->fr_c); + kill_onion(m->onion); + kill_onion_announce(m->onion_a); + kill_onion_client(m->onion_c); + kill_net_crypto(m->net_crypto); + kill_DHT(m->dht); + kill_networking(m->net); + free(m); + + if (error) { + *error = MESSENGER_ERROR_TCP_SERVER; + } + + return NULL; + } + } + + m->options = *options; + friendreq_init(&(m->fr), m->fr_c); + set_nospam(&(m->fr), random_int()); + set_filter_function(&(m->fr), &friend_already_added, m); + + m->lastdump = 0; + + if (error) { + *error = MESSENGER_ERROR_NONE; + } + + return m; +} + +/* Run this before closing shop. */ +void kill_messenger(Messenger *m) +{ + if (!m) { + return; + } + + uint32_t i; + + if (m->tcp_server) { + kill_TCP_server(m->tcp_server); + } + + kill_friend_connections(m->fr_c); + kill_onion(m->onion); + kill_onion_announce(m->onion_a); + kill_onion_client(m->onion_c); + kill_net_crypto(m->net_crypto); + kill_DHT(m->dht); + kill_networking(m->net); + + for (i = 0; i < m->numfriends; ++i) { + clear_receipts(m, i); + } + + logger_kill(m->log); + free(m->friendlist); + free(m); +} + +/* Check for and handle a timed-out friend request. If the request has + * timed-out then the friend status is set back to FRIEND_ADDED. + * i: friendlist index of the timed-out friend + * t: time + */ +static void check_friend_request_timed_out(Messenger *m, uint32_t i, uint64_t t, void *userdata) +{ + Friend *f = &m->friendlist[i]; + + if (f->friendrequest_lastsent + f->friendrequest_timeout < t) { + set_friend_status(m, i, FRIEND_ADDED, userdata); + /* Double the default timeout every time if friendrequest is assumed + * to have been sent unsuccessfully. + */ + f->friendrequest_timeout *= 2; + } +} + +static int m_handle_status(void *object, int i, uint8_t status, void *userdata) +{ + Messenger *m = (Messenger *)object; + + if (status) { /* Went online. */ + send_online_packet(m, i); + } else { /* Went offline. */ + if (m->friendlist[i].status == FRIEND_ONLINE) { + set_friend_status(m, i, FRIEND_CONFIRMED, userdata); + } + } + + return 0; +} + +static int m_handle_packet(void *object, int i, const uint8_t *temp, uint16_t len, void *userdata) +{ + if (len == 0) { + return -1; + } + + Messenger *m = (Messenger *)object; + uint8_t packet_id = temp[0]; + const uint8_t *data = temp + 1; + uint32_t data_length = len - 1; + + if (m->friendlist[i].status != FRIEND_ONLINE) { + if (packet_id == PACKET_ID_ONLINE && len == 1) { + set_friend_status(m, i, FRIEND_ONLINE, userdata); + send_online_packet(m, i); + } else { + return -1; + } + } + + switch (packet_id) { + case PACKET_ID_OFFLINE: { + if (data_length != 0) { + break; + } + + set_friend_status(m, i, FRIEND_CONFIRMED, userdata); + break; + } + + case PACKET_ID_NICKNAME: { + if (data_length > MAX_NAME_LENGTH) { + break; + } + + /* Make sure the NULL terminator is present. */ + VLA(uint8_t, data_terminated, data_length + 1); + memcpy(data_terminated, data, data_length); + data_terminated[data_length] = 0; + + /* inform of namechange before we overwrite the old name */ + if (m->friend_namechange) { + m->friend_namechange(m, i, data_terminated, data_length, userdata); + } + + memcpy(m->friendlist[i].name, data_terminated, data_length); + m->friendlist[i].name_length = data_length; + + break; + } + + case PACKET_ID_STATUSMESSAGE: { + if (data_length > MAX_STATUSMESSAGE_LENGTH) { + break; + } + + /* Make sure the NULL terminator is present. */ + VLA(uint8_t, data_terminated, data_length + 1); + memcpy(data_terminated, data, data_length); + data_terminated[data_length] = 0; + + if (m->friend_statusmessagechange) { + m->friend_statusmessagechange(m, i, data_terminated, data_length, userdata); + } + + set_friend_statusmessage(m, i, data_terminated, data_length); + break; + } + + case PACKET_ID_USERSTATUS: { + if (data_length != 1) { + break; + } + + USERSTATUS status = (USERSTATUS)data[0]; + + if (status >= USERSTATUS_INVALID) { + break; + } + + if (m->friend_userstatuschange) { + m->friend_userstatuschange(m, i, status, userdata); + } + + set_friend_userstatus(m, i, status); + break; + } + + case PACKET_ID_TYPING: { + if (data_length != 1) { + break; + } + + bool typing = !!data[0]; + + set_friend_typing(m, i, typing); + + if (m->friend_typingchange) { + m->friend_typingchange(m, i, typing, userdata); + } + + break; + } + + case PACKET_ID_MESSAGE: // fall-through + case PACKET_ID_ACTION: { + if (data_length == 0) { + break; + } + + const uint8_t *message = data; + uint16_t message_length = data_length; + + /* Make sure the NULL terminator is present. */ + VLA(uint8_t, message_terminated, message_length + 1); + memcpy(message_terminated, message, message_length); + message_terminated[message_length] = 0; + uint8_t type = packet_id - PACKET_ID_MESSAGE; + + if (m->friend_message) { + (*m->friend_message)(m, i, type, message_terminated, message_length, userdata); + } + + break; + } + + case PACKET_ID_INVITE_CONFERENCE: { + if (data_length == 0) { + break; + } + + if (m->conference_invite) { + (*m->conference_invite)(m, i, data, data_length, userdata); + } + + break; + } + + case PACKET_ID_FILE_SENDREQUEST: { + const unsigned int head_length = 1 + sizeof(uint32_t) + sizeof(uint64_t) + FILE_ID_LENGTH; + + if (data_length < head_length) { + break; + } + + uint8_t filenumber = data[0]; + + if (filenumber >= MAX_CONCURRENT_FILE_PIPES) { + break; + } + + uint64_t filesize; + uint32_t file_type; + uint16_t filename_length = data_length - head_length; + + if (filename_length > MAX_FILENAME_LENGTH) { + break; + } + + memcpy(&file_type, data + 1, sizeof(file_type)); + file_type = net_ntohl(file_type); + + memcpy(&filesize, data + 1 + sizeof(uint32_t), sizeof(filesize)); + net_to_host((uint8_t *) &filesize, sizeof(filesize)); + struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber]; + + if (ft->status != FILESTATUS_NONE) { + break; + } + + ft->status = FILESTATUS_NOT_ACCEPTED; + ft->size = filesize; + ft->transferred = 0; + ft->paused = FILE_PAUSE_NOT; + memcpy(ft->id, data + 1 + sizeof(uint32_t) + sizeof(uint64_t), FILE_ID_LENGTH); + + VLA(uint8_t, filename_terminated, filename_length + 1); + uint8_t *filename = NULL; + + if (filename_length) { + /* Force NULL terminate file name. */ + memcpy(filename_terminated, data + head_length, filename_length); + filename_terminated[filename_length] = 0; + filename = filename_terminated; + } + + uint32_t real_filenumber = filenumber; + real_filenumber += 1; + real_filenumber <<= 16; + + if (m->file_sendrequest) { + (*m->file_sendrequest)(m, i, real_filenumber, file_type, filesize, filename, filename_length, + userdata); + } + + break; + } + + case PACKET_ID_FILE_CONTROL: { + if (data_length < 3) { + break; + } + + uint8_t send_receive = data[0]; + uint8_t filenumber = data[1]; + uint8_t control_type = data[2]; + + if (filenumber >= MAX_CONCURRENT_FILE_PIPES) { + break; + } + + if (handle_filecontrol(m, i, send_receive, filenumber, control_type, data + 3, data_length - 3, userdata) == -1) { + // TODO(iphydf): Do something different here? Right now, this + // check is pointless. + break; + } + + break; + } + + case PACKET_ID_FILE_DATA: { + if (data_length < 1) { + break; + } + + uint8_t filenumber = data[0]; + + if (filenumber >= MAX_CONCURRENT_FILE_PIPES) { + break; + } + + struct File_Transfers *ft = &m->friendlist[i].file_receiving[filenumber]; + + if (ft->status != FILESTATUS_TRANSFERRING) { + break; + } + + uint64_t position = ft->transferred; + uint32_t real_filenumber = filenumber; + real_filenumber += 1; + real_filenumber <<= 16; + uint16_t file_data_length = (data_length - 1); + const uint8_t *file_data; + + if (file_data_length == 0) { + file_data = NULL; + } else { + file_data = data + 1; + } + + /* Prevent more data than the filesize from being passed to clients. */ + if ((ft->transferred + file_data_length) > ft->size) { + file_data_length = ft->size - ft->transferred; + } + + if (m->file_filedata) { + (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, userdata); + } + + ft->transferred += file_data_length; + + if (file_data_length && (ft->transferred >= ft->size || file_data_length != MAX_FILE_DATA_SIZE)) { + file_data_length = 0; + file_data = NULL; + position = ft->transferred; + + /* Full file received. */ + if (m->file_filedata) { + (*m->file_filedata)(m, i, real_filenumber, position, file_data, file_data_length, userdata); + } + } + + /* Data is zero, filetransfer is over. */ + if (file_data_length == 0) { + ft->status = FILESTATUS_NONE; + } + + break; + } + + case PACKET_ID_MSI: { + if (data_length == 0) { + break; + } + + if (m->msi_packet) { + (*m->msi_packet)(m, i, data, data_length, m->msi_packet_userdata); + } + + break; + } + + default: { + handle_custom_lossless_packet(object, i, temp, len, userdata); + break; + } + } + + return 0; +} + +static void do_friends(Messenger *m, void *userdata) +{ + uint32_t i; + uint64_t temp_time = unix_time(); + + for (i = 0; i < m->numfriends; ++i) { + if (m->friendlist[i].status == FRIEND_ADDED) { + int fr = send_friend_request_packet(m->fr_c, m->friendlist[i].friendcon_id, m->friendlist[i].friendrequest_nospam, + m->friendlist[i].info, + m->friendlist[i].info_size); + + if (fr >= 0) { + set_friend_status(m, i, FRIEND_REQUESTED, userdata); + m->friendlist[i].friendrequest_lastsent = temp_time; + } + } + + if (m->friendlist[i].status == FRIEND_REQUESTED + || m->friendlist[i].status == FRIEND_CONFIRMED) { /* friend is not online. */ + if (m->friendlist[i].status == FRIEND_REQUESTED) { + /* If we didn't connect to friend after successfully sending him a friend request the request is deemed + * unsuccessful so we set the status back to FRIEND_ADDED and try again. + */ + check_friend_request_timed_out(m, i, temp_time, userdata); + } + } + + if (m->friendlist[i].status == FRIEND_ONLINE) { /* friend is online. */ + if (m->friendlist[i].name_sent == 0) { + if (m_sendname(m, i, m->name, m->name_length)) { + m->friendlist[i].name_sent = 1; + } + } + + if (m->friendlist[i].statusmessage_sent == 0) { + if (send_statusmessage(m, i, m->statusmessage, m->statusmessage_length)) { + m->friendlist[i].statusmessage_sent = 1; + } + } + + if (m->friendlist[i].userstatus_sent == 0) { + if (send_userstatus(m, i, m->userstatus)) { + m->friendlist[i].userstatus_sent = 1; + } + } + + if (m->friendlist[i].user_istyping_sent == 0) { + if (send_user_istyping(m, i, m->friendlist[i].user_istyping)) { + m->friendlist[i].user_istyping_sent = 1; + } + } + + check_friend_tcp_udp(m, i, userdata); + do_receipts(m, i, userdata); + do_reqchunk_filecb(m, i, userdata); + + m->friendlist[i].last_seen_time = (uint64_t) time(NULL); + } + } +} + +static void connection_status_cb(Messenger *m, void *userdata) +{ + unsigned int conn_status = onion_connection_status(m->onion_c); + + if (conn_status != m->last_connection_status) { + if (m->core_connection_change) { + (*m->core_connection_change)(m, conn_status, userdata); + } + + m->last_connection_status = conn_status; + } +} + + +#define DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS 60UL + +#define IDSTRING_LEN (CRYPTO_PUBLIC_KEY_SIZE * 2 + 1) +/* id_str should be of length at least IDSTRING_LEN */ +static char *id_to_string(const uint8_t *pk, char *id_str, size_t length) +{ + if (length < IDSTRING_LEN) { + snprintf(id_str, length, "Bad buf length"); + return id_str; + } + + for (uint32_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; i++) { + sprintf(&id_str[i * 2], "%02X", pk[i]); + } + + id_str[CRYPTO_PUBLIC_KEY_SIZE * 2] = 0; + return id_str; +} + +/* Minimum messenger run interval in ms + TODO(mannol): A/V */ +#define MIN_RUN_INTERVAL 50 + +/* Return the time in milliseconds before do_messenger() should be called again + * for optimal performance. + * + * returns time (in ms) before the next do_messenger() needs to be run on success. + */ +uint32_t messenger_run_interval(const Messenger *m) +{ + uint32_t crypto_interval = crypto_run_interval(m->net_crypto); + + if (crypto_interval > MIN_RUN_INTERVAL) { + return MIN_RUN_INTERVAL; + } + + return crypto_interval; +} + +/* The main loop that needs to be run at least 20 times per second. */ +void do_messenger(Messenger *m, void *userdata) +{ + // Add the TCP relays, but only if this is the first time calling do_messenger + if (m->has_added_relays == 0) { + m->has_added_relays = 1; + + int i; + + for (i = 0; i < NUM_SAVED_TCP_RELAYS; ++i) { + add_tcp_relay(m->net_crypto, m->loaded_relays[i].ip_port, m->loaded_relays[i].public_key); + } + + if (m->tcp_server) { + /* Add self tcp server. */ + IP_Port local_ip_port; + local_ip_port.port = m->options.tcp_server_port; + local_ip_port.ip.family = TOX_AF_INET; + local_ip_port.ip.ip4 = get_ip4_loopback(); + add_tcp_relay(m->net_crypto, local_ip_port, + tcp_server_public_key(m->tcp_server)); + } + } + + unix_time_update(); + + if (!m->options.udp_disabled) { + networking_poll(m->net, userdata); + do_DHT(m->dht); + } + + if (m->tcp_server) { + do_TCP_server(m->tcp_server); + } + + do_net_crypto(m->net_crypto, userdata); + do_onion_client(m->onion_c); + do_friend_connections(m->fr_c, userdata); + do_friends(m, userdata); + connection_status_cb(m, userdata); + + if (unix_time() > m->lastdump + DUMPING_CLIENTS_FRIENDS_EVERY_N_SECONDS) { + m->lastdump = unix_time(); + uint32_t client, last_pinged; + + for (client = 0; client < LCLIENT_LIST; client++) { + Client_data *cptr = &m->dht->close_clientlist[client]; + IPPTsPng *assoc = NULL; + uint32_t a; + + for (a = 0, assoc = &cptr->assoc4; a < 2; a++, assoc = &cptr->assoc6) { + if (ip_isset(&assoc->ip_port.ip)) { + last_pinged = m->lastdump - assoc->last_pinged; + + if (last_pinged > 999) { + last_pinged = 999; + } + + char ip_str[IP_NTOA_LEN]; + char id_str[IDSTRING_LEN]; + LOGGER_TRACE(m->log, "C[%2u] %s:%u [%3u] %s", + client, ip_ntoa(&assoc->ip_port.ip, ip_str, sizeof(ip_str)), + net_ntohs(assoc->ip_port.port), last_pinged, + id_to_string(cptr->public_key, id_str, sizeof(id_str))); + } + } + } + + + uint32_t friend_idx, dhtfriend; + + /* dht contains additional "friends" (requests) */ + uint32_t num_dhtfriends = m->dht->num_friends; + VLA(int32_t, m2dht, num_dhtfriends); + VLA(int32_t, dht2m, num_dhtfriends); + + for (friend_idx = 0; friend_idx < num_dhtfriends; friend_idx++) { + m2dht[friend_idx] = -1; + dht2m[friend_idx] = -1; + + if (friend_idx >= m->numfriends) { + continue; + } + + for (dhtfriend = 0; dhtfriend < m->dht->num_friends; dhtfriend++) { + if (id_equal(m->friendlist[friend_idx].real_pk, m->dht->friends_list[dhtfriend].public_key)) { + m2dht[friend_idx] = dhtfriend; + break; + } + } + } + + for (friend_idx = 0; friend_idx < num_dhtfriends; friend_idx++) { + if (m2dht[friend_idx] >= 0) { + dht2m[m2dht[friend_idx]] = friend_idx; + } + } + + if (m->numfriends != m->dht->num_friends) { + LOGGER_TRACE(m->log, "Friend num in DHT %u != friend num in msger %u\n", m->dht->num_friends, m->numfriends); + } + + Friend *msgfptr; + DHT_Friend *dhtfptr; + + for (friend_idx = 0; friend_idx < num_dhtfriends; friend_idx++) { + if (dht2m[friend_idx] >= 0) { + msgfptr = &m->friendlist[dht2m[friend_idx]]; + } else { + msgfptr = NULL; + } + + dhtfptr = &m->dht->friends_list[friend_idx]; + + if (msgfptr) { + char id_str[IDSTRING_LEN]; + LOGGER_TRACE(m->log, "F[%2u:%2u] <%s> %s", + dht2m[friend_idx], friend_idx, msgfptr->name, + id_to_string(msgfptr->real_pk, id_str, sizeof(id_str))); + } else { + char id_str[IDSTRING_LEN]; + LOGGER_TRACE(m->log, "F[--:%2u] %s", friend_idx, + id_to_string(dhtfptr->public_key, id_str, sizeof(id_str))); + } + + for (client = 0; client < MAX_FRIEND_CLIENTS; client++) { + Client_data *cptr = &dhtfptr->client_list[client]; + IPPTsPng *assoc = NULL; + uint32_t a; + + for (a = 0, assoc = &cptr->assoc4; a < 2; a++, assoc = &cptr->assoc6) { + if (ip_isset(&assoc->ip_port.ip)) { + last_pinged = m->lastdump - assoc->last_pinged; + + if (last_pinged > 999) { + last_pinged = 999; + } + + char ip_str[IP_NTOA_LEN]; + char id_str[IDSTRING_LEN]; + LOGGER_TRACE(m->log, "F[%2u] => C[%2u] %s:%u [%3u] %s", + friend_idx, client, ip_ntoa(&assoc->ip_port.ip, ip_str, sizeof(ip_str)), + net_ntohs(assoc->ip_port.port), last_pinged, + id_to_string(cptr->public_key, id_str, sizeof(id_str))); + } + } + } + } + } +} + +/* new messenger format for load/save, more robust and forward compatible */ + +#define MESSENGER_STATE_COOKIE_GLOBAL 0x15ed1b1f + +#define MESSENGER_STATE_COOKIE_TYPE 0x01ce +#define MESSENGER_STATE_TYPE_NOSPAMKEYS 1 +#define MESSENGER_STATE_TYPE_DHT 2 +#define MESSENGER_STATE_TYPE_FRIENDS 3 +#define MESSENGER_STATE_TYPE_NAME 4 +#define MESSENGER_STATE_TYPE_STATUSMESSAGE 5 +#define MESSENGER_STATE_TYPE_STATUS 6 +#define MESSENGER_STATE_TYPE_TCP_RELAY 10 +#define MESSENGER_STATE_TYPE_PATH_NODE 11 +#define MESSENGER_STATE_TYPE_END 255 + +#define SAVED_FRIEND_REQUEST_SIZE 1024 +#define NUM_SAVED_PATH_NODES 8 + +struct SAVED_FRIEND { + uint8_t status; + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t info[SAVED_FRIEND_REQUEST_SIZE]; // the data that is sent during the friend requests we do. + uint16_t info_size; // Length of the info. + uint8_t name[MAX_NAME_LENGTH]; + uint16_t name_length; + uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; + uint16_t statusmessage_length; + uint8_t userstatus; + uint32_t friendrequest_nospam; + uint64_t last_seen_time; +}; + +static uint32_t friend_size() +{ + uint32_t data = 0; + const struct SAVED_FRIEND temp = { 0 }; + +#define VALUE_MEMBER(NAME) data += sizeof(temp.NAME) +#define ARRAY_MEMBER(NAME) data += sizeof(temp.NAME) + + // Exactly the same in friend_load, friend_save, and friend_size + VALUE_MEMBER(status); + ARRAY_MEMBER(real_pk); + ARRAY_MEMBER(info); + data++; // padding + VALUE_MEMBER(info_size); + ARRAY_MEMBER(name); + VALUE_MEMBER(name_length); + ARRAY_MEMBER(statusmessage); + data++; // padding + VALUE_MEMBER(statusmessage_length); + VALUE_MEMBER(userstatus); + data += 3; // padding + VALUE_MEMBER(friendrequest_nospam); + VALUE_MEMBER(last_seen_time); + +#undef VALUE_MEMBER +#undef ARRAY_MEMBER + + return data; +} + +static uint32_t saved_friendslist_size(const Messenger *m) +{ + return count_friendlist(m) * friend_size(); +} + +static uint8_t *friend_save(const struct SAVED_FRIEND *temp, uint8_t *data) +{ +#define VALUE_MEMBER(NAME) \ + memcpy(data, &temp->NAME, sizeof(temp->NAME)); \ + data += sizeof(temp->NAME) + +#define ARRAY_MEMBER(NAME) \ + memcpy(data, temp->NAME, sizeof(temp->NAME)); \ + data += sizeof(temp->NAME) + + // Exactly the same in friend_load, friend_save, and friend_size + VALUE_MEMBER(status); + ARRAY_MEMBER(real_pk); + ARRAY_MEMBER(info); + data++; // padding + VALUE_MEMBER(info_size); + ARRAY_MEMBER(name); + VALUE_MEMBER(name_length); + ARRAY_MEMBER(statusmessage); + data++; // padding + VALUE_MEMBER(statusmessage_length); + VALUE_MEMBER(userstatus); + data += 3; // padding + VALUE_MEMBER(friendrequest_nospam); + VALUE_MEMBER(last_seen_time); + +#undef VALUE_MEMBER +#undef ARRAY_MEMBER + + return data; +} + +static uint32_t friends_list_save(const Messenger *m, uint8_t *data) +{ + uint32_t i; + uint32_t num = 0; + uint8_t *cur_data = data; + + for (i = 0; i < m->numfriends; i++) { + if (m->friendlist[i].status > 0) { + struct SAVED_FRIEND temp = { 0 }; + temp.status = m->friendlist[i].status; + memcpy(temp.real_pk, m->friendlist[i].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + + if (temp.status < 3) { + const size_t friendrequest_length = + MIN(m->friendlist[i].info_size, + MIN(SAVED_FRIEND_REQUEST_SIZE, MAX_FRIEND_REQUEST_DATA_SIZE)); + memcpy(temp.info, m->friendlist[i].info, friendrequest_length); + + temp.info_size = net_htons(m->friendlist[i].info_size); + temp.friendrequest_nospam = m->friendlist[i].friendrequest_nospam; + } else { + memcpy(temp.name, m->friendlist[i].name, m->friendlist[i].name_length); + temp.name_length = net_htons(m->friendlist[i].name_length); + memcpy(temp.statusmessage, m->friendlist[i].statusmessage, m->friendlist[i].statusmessage_length); + temp.statusmessage_length = net_htons(m->friendlist[i].statusmessage_length); + temp.userstatus = m->friendlist[i].userstatus; + + uint8_t last_seen_time[sizeof(uint64_t)]; + memcpy(last_seen_time, &m->friendlist[i].last_seen_time, sizeof(uint64_t)); + host_to_net(last_seen_time, sizeof(uint64_t)); + memcpy(&temp.last_seen_time, last_seen_time, sizeof(uint64_t)); + } + + uint8_t *next_data = friend_save(&temp, cur_data); + assert(next_data - cur_data == friend_size()); +#ifdef __LP64__ + assert(memcmp(cur_data, &temp, friend_size()) == 0); +#endif + cur_data = next_data; + num++; + } + } + + assert(cur_data - data == num * friend_size()); + return cur_data - data; +} + +static const uint8_t *friend_load(struct SAVED_FRIEND *temp, const uint8_t *data) +{ +#define VALUE_MEMBER(NAME) \ + memcpy(&temp->NAME, data, sizeof(temp->NAME)); \ + data += sizeof(temp->NAME) + +#define ARRAY_MEMBER(NAME) \ + memcpy(temp->NAME, data, sizeof(temp->NAME)); \ + data += sizeof(temp->NAME) + + // Exactly the same in friend_load, friend_save, and friend_size + VALUE_MEMBER(status); + ARRAY_MEMBER(real_pk); + ARRAY_MEMBER(info); + data++; // padding + VALUE_MEMBER(info_size); + ARRAY_MEMBER(name); + VALUE_MEMBER(name_length); + ARRAY_MEMBER(statusmessage); + data++; // padding + VALUE_MEMBER(statusmessage_length); + VALUE_MEMBER(userstatus); + data += 3; // padding + VALUE_MEMBER(friendrequest_nospam); + VALUE_MEMBER(last_seen_time); + +#undef VALUE_MEMBER +#undef ARRAY_MEMBER + + return data; +} + +static int friends_list_load(Messenger *m, const uint8_t *data, uint32_t length) +{ + if (length % friend_size() != 0) { + return -1; + } + + uint32_t num = length / friend_size(); + uint32_t i; + const uint8_t *cur_data = data; + + for (i = 0; i < num; ++i) { + struct SAVED_FRIEND temp = { 0 }; + const uint8_t *next_data = friend_load(&temp, cur_data); + assert(next_data - cur_data == friend_size()); +#ifdef __LP64__ + assert(memcmp(&temp, cur_data, friend_size()) == 0); +#endif + cur_data = next_data; + + if (temp.status >= 3) { + int fnum = m_addfriend_norequest(m, temp.real_pk); + + if (fnum < 0) { + continue; + } + + setfriendname(m, fnum, temp.name, net_ntohs(temp.name_length)); + set_friend_statusmessage(m, fnum, temp.statusmessage, net_ntohs(temp.statusmessage_length)); + set_friend_userstatus(m, fnum, temp.userstatus); + uint8_t last_seen_time[sizeof(uint64_t)]; + memcpy(last_seen_time, &temp.last_seen_time, sizeof(uint64_t)); + net_to_host(last_seen_time, sizeof(uint64_t)); + memcpy(&m->friendlist[fnum].last_seen_time, last_seen_time, sizeof(uint64_t)); + } else if (temp.status != 0) { + /* TODO(irungentoo): This is not a good way to do this. */ + uint8_t address[FRIEND_ADDRESS_SIZE]; + id_copy(address, temp.real_pk); + memcpy(address + CRYPTO_PUBLIC_KEY_SIZE, &(temp.friendrequest_nospam), sizeof(uint32_t)); + uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); + memcpy(address + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t), &checksum, sizeof(checksum)); + m_addfriend(m, address, temp.info, net_ntohs(temp.info_size)); + } + } + + return num; +} + +/* return size of the messenger data (for saving) */ +uint32_t messenger_size(const Messenger *m) +{ + uint32_t size32 = sizeof(uint32_t), sizesubhead = size32 * 2; + return size32 * 2 // global cookie + + sizesubhead + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE + + sizesubhead + DHT_size(m->dht) // DHT + + sizesubhead + saved_friendslist_size(m) // Friendlist itself. + + sizesubhead + m->name_length // Own nickname. + + sizesubhead + m->statusmessage_length // status message + + sizesubhead + 1 // status + + sizesubhead + NUM_SAVED_TCP_RELAYS * packed_node_size(TCP_INET6) //TCP relays + + sizesubhead + NUM_SAVED_PATH_NODES * packed_node_size(TCP_INET6) //saved path nodes + + sizesubhead; +} + +static uint8_t *messenger_save_subheader(uint8_t *data, uint32_t len, uint16_t type) +{ + host_to_lendian32(data, len); + data += sizeof(uint32_t); + host_to_lendian32(data, (host_tolendian16(MESSENGER_STATE_COOKIE_TYPE) << 16) | host_tolendian16(type)); + data += sizeof(uint32_t); + return data; +} + +/* Save the messenger in data of size Messenger_size(). */ +void messenger_save(const Messenger *m, uint8_t *data) +{ + memset(data, 0, messenger_size(m)); + + uint32_t len; + uint16_t type; + uint32_t size32 = sizeof(uint32_t); + + memset(data, 0, size32); + data += size32; + host_to_lendian32(data, MESSENGER_STATE_COOKIE_GLOBAL); + data += size32; + + assert(sizeof(get_nospam(&m->fr)) == sizeof(uint32_t)); + len = size32 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE; + type = MESSENGER_STATE_TYPE_NOSPAMKEYS; + data = messenger_save_subheader(data, len, type); + *(uint32_t *)data = get_nospam(&(m->fr)); + save_keys(m->net_crypto, data + size32); + data += len; + + len = saved_friendslist_size(m); + type = MESSENGER_STATE_TYPE_FRIENDS; + data = messenger_save_subheader(data, len, type); + friends_list_save(m, data); + data += len; + + len = m->name_length; + type = MESSENGER_STATE_TYPE_NAME; + data = messenger_save_subheader(data, len, type); + memcpy(data, m->name, len); + data += len; + + len = m->statusmessage_length; + type = MESSENGER_STATE_TYPE_STATUSMESSAGE; + data = messenger_save_subheader(data, len, type); + memcpy(data, m->statusmessage, len); + data += len; + + len = 1; + type = MESSENGER_STATE_TYPE_STATUS; + data = messenger_save_subheader(data, len, type); + *data = m->userstatus; + data += len; + + len = DHT_size(m->dht); + type = MESSENGER_STATE_TYPE_DHT; + data = messenger_save_subheader(data, len, type); + DHT_save(m->dht, data); + data += len; + + Node_format relays[NUM_SAVED_TCP_RELAYS]; + type = MESSENGER_STATE_TYPE_TCP_RELAY; + uint8_t *temp_data = data; + data = messenger_save_subheader(temp_data, 0, type); + unsigned int num = copy_connected_tcp_relays(m->net_crypto, relays, NUM_SAVED_TCP_RELAYS); + int l = pack_nodes(data, NUM_SAVED_TCP_RELAYS * packed_node_size(TCP_INET6), relays, num); + + if (l > 0) { + len = l; + data = messenger_save_subheader(temp_data, len, type); + data += len; + } + + Node_format nodes[NUM_SAVED_PATH_NODES]; + type = MESSENGER_STATE_TYPE_PATH_NODE; + temp_data = data; + data = messenger_save_subheader(data, 0, type); + memset(nodes, 0, sizeof(nodes)); + num = onion_backup_nodes(m->onion_c, nodes, NUM_SAVED_PATH_NODES); + l = pack_nodes(data, NUM_SAVED_PATH_NODES * packed_node_size(TCP_INET6), nodes, num); + + if (l > 0) { + len = l; + data = messenger_save_subheader(temp_data, len, type); + data += len; + } + + messenger_save_subheader(data, 0, MESSENGER_STATE_TYPE_END); +} + +static int messenger_load_state_callback(void *outer, const uint8_t *data, uint32_t length, uint16_t type) +{ + Messenger *m = (Messenger *)outer; + + switch (type) { + case MESSENGER_STATE_TYPE_NOSPAMKEYS: + if (length == CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE + sizeof(uint32_t)) { + set_nospam(&(m->fr), *(const uint32_t *)data); + load_secret_key(m->net_crypto, (&data[sizeof(uint32_t)]) + CRYPTO_PUBLIC_KEY_SIZE); + + if (public_key_cmp((&data[sizeof(uint32_t)]), m->net_crypto->self_public_key) != 0) { + return -1; + } + } else { + return -1; /* critical */ + } + + break; + + case MESSENGER_STATE_TYPE_DHT: + DHT_load(m->dht, data, length); + break; + + case MESSENGER_STATE_TYPE_FRIENDS: + friends_list_load(m, data, length); + break; + + case MESSENGER_STATE_TYPE_NAME: + if ((length > 0) && (length <= MAX_NAME_LENGTH)) { + setname(m, data, length); + } + + break; + + case MESSENGER_STATE_TYPE_STATUSMESSAGE: + if ((length > 0) && (length <= MAX_STATUSMESSAGE_LENGTH)) { + m_set_statusmessage(m, data, length); + } + + break; + + case MESSENGER_STATE_TYPE_STATUS: + if (length == 1) { + m_set_userstatus(m, *data); + } + + break; + + case MESSENGER_STATE_TYPE_TCP_RELAY: { + if (length == 0) { + break; + } + + unpack_nodes(m->loaded_relays, NUM_SAVED_TCP_RELAYS, 0, data, length, 1); + m->has_added_relays = 0; + + break; + } + + case MESSENGER_STATE_TYPE_PATH_NODE: { + Node_format nodes[NUM_SAVED_PATH_NODES]; + + if (length == 0) { + break; + } + + int i, num = unpack_nodes(nodes, NUM_SAVED_PATH_NODES, 0, data, length, 0); + + for (i = 0; i < num; ++i) { + onion_add_bs_path_node(m->onion_c, nodes[i].ip_port, nodes[i].public_key); + } + + break; + } + + case MESSENGER_STATE_TYPE_END: { + if (length != 0) { + return -1; + } + + return -2; + } + + default: + LOGGER_ERROR(m->log, "Load state: contains unrecognized part (len %u, type %u)\n", + length, type); + break; + } + + return 0; +} + +/* Load the messenger from data of size length. */ +int messenger_load(Messenger *m, const uint8_t *data, uint32_t length) +{ + uint32_t data32[2]; + uint32_t cookie_len = sizeof(data32); + + if (length < cookie_len) { + return -1; + } + + memcpy(data32, data, sizeof(uint32_t)); + lendian_to_host32(data32 + 1, data + sizeof(uint32_t)); + + if (!data32[0] && (data32[1] == MESSENGER_STATE_COOKIE_GLOBAL)) { + return load_state(messenger_load_state_callback, m->log, m, data + cookie_len, + length - cookie_len, MESSENGER_STATE_COOKIE_TYPE); + } + + return -1; +} + +/* Return the number of friends in the instance m. + * You should use this to determine how much memory to allocate + * for copy_friendlist. */ +uint32_t count_friendlist(const Messenger *m) +{ + uint32_t ret = 0; + uint32_t i; + + for (i = 0; i < m->numfriends; i++) { + if (m->friendlist[i].status > 0) { + ret++; + } + } + + return ret; +} + +/* Copy a list of valid friend IDs into the array out_list. + * If out_list is NULL, returns 0. + * Otherwise, returns the number of elements copied. + * If the array was too small, the contents + * of out_list will be truncated to list_size. */ +uint32_t copy_friendlist(Messenger const *m, uint32_t *out_list, uint32_t list_size) +{ + if (!out_list) { + return 0; + } + + if (m->numfriends == 0) { + return 0; + } + + uint32_t i; + uint32_t ret = 0; + + for (i = 0; i < m->numfriends; i++) { + if (ret >= list_size) { + break; /* Abandon ship */ + } + + if (m->friendlist[i].status > 0) { + out_list[ret] = i; + ret++; + } + } + + return ret; +} diff --git a/libs/libtox/src/toxcore/Messenger.h b/libs/libtox/src/toxcore/Messenger.h new file mode 100644 index 0000000000..e1dba69886 --- /dev/null +++ b/libs/libtox/src/toxcore/Messenger.h @@ -0,0 +1,777 @@ +/* + * An implementation of a simple text chat only messenger on the tox network + * core. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef MESSENGER_H +#define MESSENGER_H + +#include "friend_connection.h" +#include "friend_requests.h" +#include "logger.h" + +#define MAX_NAME_LENGTH 128 +/* TODO(irungentoo): this must depend on other variable. */ +#define MAX_STATUSMESSAGE_LENGTH 1007 +/* Used for TCP relays in Messenger struct (may need to be % 2 == 0)*/ +#define NUM_SAVED_TCP_RELAYS 8 +/* This cannot be bigger than 256 */ +#define MAX_CONCURRENT_FILE_PIPES 256 + + +#define FRIEND_ADDRESS_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint16_t)) + +enum { + MESSAGE_NORMAL, + MESSAGE_ACTION +}; + +/* NOTE: Packet ids below 24 must never be used. */ +#define PACKET_ID_ONLINE 24 +#define PACKET_ID_OFFLINE 25 +#define PACKET_ID_NICKNAME 48 +#define PACKET_ID_STATUSMESSAGE 49 +#define PACKET_ID_USERSTATUS 50 +#define PACKET_ID_TYPING 51 +#define PACKET_ID_MESSAGE 64 +#define PACKET_ID_ACTION (PACKET_ID_MESSAGE + MESSAGE_ACTION) /* 65 */ +#define PACKET_ID_MSI 69 +#define PACKET_ID_FILE_SENDREQUEST 80 +#define PACKET_ID_FILE_CONTROL 81 +#define PACKET_ID_FILE_DATA 82 +#define PACKET_ID_INVITE_CONFERENCE 96 +#define PACKET_ID_ONLINE_PACKET 97 +#define PACKET_ID_DIRECT_CONFERENCE 98 +#define PACKET_ID_MESSAGE_CONFERENCE 99 +#define PACKET_ID_LOSSY_CONFERENCE 199 + +/* All packets starting with a byte in this range can be used for anything. */ +#define PACKET_ID_LOSSLESS_RANGE_START 160 +#define PACKET_ID_LOSSLESS_RANGE_SIZE 32 +#define PACKET_LOSSY_AV_RESERVED 8 /* Number of lossy packet types at start of range reserved for A/V. */ + +typedef struct { + uint8_t ipv6enabled; + uint8_t udp_disabled; + TCP_Proxy_Info proxy_info; + uint16_t port_range[2]; + uint16_t tcp_server_port; + + uint8_t hole_punching_enabled; + bool local_discovery_enabled; + + logger_cb *log_callback; + void *log_user_data; +} Messenger_Options; + + +struct Receipts { + uint32_t packet_num; + uint32_t msg_id; + struct Receipts *next; +}; + +/* Status definitions. */ +enum { + NOFRIEND, + FRIEND_ADDED, + FRIEND_REQUESTED, + FRIEND_CONFIRMED, + FRIEND_ONLINE, +}; + +/* Errors for m_addfriend + * FAERR - Friend Add Error + */ +enum { + FAERR_TOOLONG = -1, + FAERR_NOMESSAGE = -2, + FAERR_OWNKEY = -3, + FAERR_ALREADYSENT = -4, + FAERR_BADCHECKSUM = -6, + FAERR_SETNEWNOSPAM = -7, + FAERR_NOMEM = -8 +}; + + +/* Default start timeout in seconds between friend requests. */ +#define FRIENDREQUEST_TIMEOUT 5; + +enum { + CONNECTION_NONE, + CONNECTION_TCP, + CONNECTION_UDP, + CONNECTION_UNKNOWN +}; + +/* USERSTATUS - + * Represents userstatuses someone can have. + */ + +typedef enum { + USERSTATUS_NONE, + USERSTATUS_AWAY, + USERSTATUS_BUSY, + USERSTATUS_INVALID +} +USERSTATUS; + +#define FILE_ID_LENGTH 32 + +struct File_Transfers { + uint64_t size; + uint64_t transferred; + uint8_t status; /* 0 == no transfer, 1 = not accepted, 3 = transferring, 4 = broken, 5 = finished */ + uint8_t paused; /* 0: not paused, 1 = paused by us, 2 = paused by other, 3 = paused by both. */ + uint32_t last_packet_number; /* number of the last packet sent. */ + uint64_t requested; /* total data requested by the request chunk callback */ + unsigned int slots_allocated; /* number of slots allocated to this transfer. */ + uint8_t id[FILE_ID_LENGTH]; +}; +enum { + FILESTATUS_NONE, + FILESTATUS_NOT_ACCEPTED, + FILESTATUS_TRANSFERRING, + //FILESTATUS_BROKEN, + FILESTATUS_FINISHED +}; + +enum { + FILE_PAUSE_NOT, + FILE_PAUSE_US, + FILE_PAUSE_OTHER, + FILE_PAUSE_BOTH +}; + +enum { + FILECONTROL_ACCEPT, + FILECONTROL_PAUSE, + FILECONTROL_KILL, + FILECONTROL_SEEK +}; + +enum { + FILEKIND_DATA, + FILEKIND_AVATAR +}; + + +typedef struct Messenger Messenger; + +typedef struct { + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + int friendcon_id; + + uint64_t friendrequest_lastsent; // Time at which the last friend request was sent. + uint32_t friendrequest_timeout; // The timeout between successful friendrequest sending attempts. + uint8_t status; // 0 if no friend, 1 if added, 2 if friend request sent, 3 if confirmed friend, 4 if online. + uint8_t info[MAX_FRIEND_REQUEST_DATA_SIZE]; // the data that is sent during the friend requests we do. + uint8_t name[MAX_NAME_LENGTH]; + uint16_t name_length; + uint8_t name_sent; // 0 if we didn't send our name to this friend 1 if we have. + uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; + uint16_t statusmessage_length; + uint8_t statusmessage_sent; + USERSTATUS userstatus; + uint8_t userstatus_sent; + uint8_t user_istyping; + uint8_t user_istyping_sent; + uint8_t is_typing; + uint16_t info_size; // Length of the info. + uint32_t message_id; // a semi-unique id used in read receipts. + uint32_t friendrequest_nospam; // The nospam number used in the friend request. + uint64_t last_seen_time; + uint8_t last_connection_udp_tcp; + struct File_Transfers file_sending[MAX_CONCURRENT_FILE_PIPES]; + unsigned int num_sending_files; + struct File_Transfers file_receiving[MAX_CONCURRENT_FILE_PIPES]; + + struct { + int (*function)(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object); + void *object; + } lossy_rtp_packethandlers[PACKET_LOSSY_AV_RESERVED]; + + struct Receipts *receipts_start; + struct Receipts *receipts_end; +} Friend; + +struct Messenger { + Logger *log; + + Networking_Core *net; + Net_Crypto *net_crypto; + DHT *dht; + + Onion *onion; + Onion_Announce *onion_a; + Onion_Client *onion_c; + + Friend_Connections *fr_c; + + TCP_Server *tcp_server; + Friend_Requests fr; + uint8_t name[MAX_NAME_LENGTH]; + uint16_t name_length; + + uint8_t statusmessage[MAX_STATUSMESSAGE_LENGTH]; + uint16_t statusmessage_length; + + USERSTATUS userstatus; + + Friend *friendlist; + uint32_t numfriends; + + time_t lastdump; + + uint8_t has_added_relays; // If the first connection has occurred in do_messenger + Node_format loaded_relays[NUM_SAVED_TCP_RELAYS]; // Relays loaded from config + + void (*friend_message)(struct Messenger *m, uint32_t, unsigned int, const uint8_t *, size_t, void *); + void (*friend_namechange)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); + void (*friend_statusmessagechange)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); + void (*friend_userstatuschange)(struct Messenger *m, uint32_t, unsigned int, void *); + void (*friend_typingchange)(struct Messenger *m, uint32_t, bool, void *); + void (*read_receipt)(struct Messenger *m, uint32_t, uint32_t, void *); + void (*friend_connectionstatuschange)(struct Messenger *m, uint32_t, unsigned int, void *); + void (*friend_connectionstatuschange_internal)(struct Messenger *m, uint32_t, uint8_t, void *); + void *friend_connectionstatuschange_internal_userdata; + + void *conferences_object; /* Set by new_groupchats()*/ + void (*conference_invite)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t, void *); + + void (*file_sendrequest)(struct Messenger *m, uint32_t, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, + void *); + void (*file_filecontrol)(struct Messenger *m, uint32_t, uint32_t, unsigned int, void *); + void (*file_filedata)(struct Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *, size_t, void *); + void (*file_reqchunk)(struct Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *); + + void (*msi_packet)(struct Messenger *m, uint32_t, const uint8_t *, uint16_t, void *); + void *msi_packet_userdata; + + void (*lossy_packethandler)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); + void (*lossless_packethandler)(struct Messenger *m, uint32_t, const uint8_t *, size_t, void *); + + void (*core_connection_change)(struct Messenger *m, unsigned int, void *); + unsigned int last_connection_status; + + Messenger_Options options; +}; + +/* Format: [real_pk (32 bytes)][nospam number (4 bytes)][checksum (2 bytes)] + * + * return FRIEND_ADDRESS_SIZE byte address to give to others. + */ +void getaddress(const Messenger *m, uint8_t *address); + +/* Add a friend. + * Set the data that will be sent along with friend request. + * address is the address of the friend (returned by getaddress of the friend + * you wish to add) it must be FRIEND_ADDRESS_SIZE bytes. + * TODO(irungentoo): add checksum. + * data is the data and length is the length. + * + * return the friend number if success. + * return -1 if message length is too long. + * return -2 if no message (message length must be >= 1 byte). + * return -3 if user's own key. + * return -4 if friend request already sent or already a friend. + * return -6 if bad checksum in address. + * return -7 if the friend was already there but the nospam was different. + * (the nospam for that friend was set to the new one). + * return -8 if increasing the friend list size fails. + */ +int32_t m_addfriend(Messenger *m, const uint8_t *address, const uint8_t *data, uint16_t length); + + +/* Add a friend without sending a friendrequest. + * return the friend number if success. + * return -3 if user's own key. + * return -4 if friend request already sent or already a friend. + * return -6 if bad checksum in address. + * return -8 if increasing the friend list size fails. + */ +int32_t m_addfriend_norequest(Messenger *m, const uint8_t *real_pk); + +/* return the friend number associated to that client id. + * return -1 if no such friend. + */ +int32_t getfriend_id(const Messenger *m, const uint8_t *real_pk); + +/* Copies the public key associated to that friend id into real_pk buffer. + * Make sure that real_pk is of size CRYPTO_PUBLIC_KEY_SIZE. + * + * return 0 if success + * return -1 if failure + */ +int get_real_pk(const Messenger *m, int32_t friendnumber, uint8_t *real_pk); + +/* return friend connection id on success. + * return -1 if failure. + */ +int getfriendcon_id(const Messenger *m, int32_t friendnumber); + +/* Remove a friend. + * + * return 0 if success + * return -1 if failure + */ +int m_delfriend(Messenger *m, int32_t friendnumber); + +/* Checks friend's connecting status. + * + * return CONNECTION_UDP (2) if friend is directly connected to us (Online UDP). + * return CONNECTION_TCP (1) if friend is connected to us (Online TCP). + * return CONNECTION_NONE (0) if friend is not connected to us (Offline). + * return -1 on failure. + */ +int m_get_friend_connectionstatus(const Messenger *m, int32_t friendnumber); + +/* Checks if there exists a friend with given friendnumber. + * + * return 1 if friend exists. + * return 0 if friend doesn't exist. + */ +int m_friend_exists(const Messenger *m, int32_t friendnumber); + +/* Send a message of type to an online friend. + * + * return -1 if friend not valid. + * return -2 if too large. + * return -3 if friend not online. + * return -4 if send failed (because queue is full). + * return -5 if bad type. + * return 0 if success. + * + * the value in message_id will be passed to your read_receipt callback when the other receives the message. + */ +int m_send_message_generic(Messenger *m, int32_t friendnumber, uint8_t type, const uint8_t *message, uint32_t length, + uint32_t *message_id); + + +/* Set the name and name_length of a friend. + * name must be a string of maximum MAX_NAME_LENGTH length. + * length must be at least 1 byte. + * length is the length of name with the NULL terminator. + * + * return 0 if success. + * return -1 if failure. + */ +int setfriendname(Messenger *m, int32_t friendnumber, const uint8_t *name, uint16_t length); + +/* Set our nickname. + * name must be a string of maximum MAX_NAME_LENGTH length. + * length must be at least 1 byte. + * length is the length of name with the NULL terminator. + * + * return 0 if success. + * return -1 if failure. + */ +int setname(Messenger *m, const uint8_t *name, uint16_t length); + +/* + * Get your nickname. + * m - The messenger context to use. + * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH bytes. + * + * return length of the name. + * return 0 on error. + */ +uint16_t getself_name(const Messenger *m, uint8_t *name); + +/* Get name of friendnumber and put it in name. + * name needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. + * + * return length of name if success. + * return -1 if failure. + */ +int getname(const Messenger *m, int32_t friendnumber, uint8_t *name); + +/* return the length of name, including null on success. + * return -1 on failure. + */ +int m_get_name_size(const Messenger *m, int32_t friendnumber); +int m_get_self_name_size(const Messenger *m); + +/* Set our user status. + * You are responsible for freeing status after. + * + * returns 0 on success. + * returns -1 on failure. + */ +int m_set_statusmessage(Messenger *m, const uint8_t *status, uint16_t length); +int m_set_userstatus(Messenger *m, uint8_t status); + +/* return the length of friendnumber's status message, including null on success. + * return -1 on failure. + */ +int m_get_statusmessage_size(const Messenger *m, int32_t friendnumber); +int m_get_self_statusmessage_size(const Messenger *m); + +/* Copy friendnumber's status message into buf, truncating if size is over maxlen. + * Get the size you need to allocate from m_get_statusmessage_size. + * The self variant will copy our own status message. + * + * returns the length of the copied data on success + * retruns -1 on failure. + */ +int m_copy_statusmessage(const Messenger *m, int32_t friendnumber, uint8_t *buf, uint32_t maxlen); +int m_copy_self_statusmessage(const Messenger *m, uint8_t *buf); + +/* return one of USERSTATUS values. + * Values unknown to your application should be represented as USERSTATUS_NONE. + * As above, the self variant will return our own USERSTATUS. + * If friendnumber is invalid, this shall return USERSTATUS_INVALID. + */ +uint8_t m_get_userstatus(const Messenger *m, int32_t friendnumber); +uint8_t m_get_self_userstatus(const Messenger *m); + + +/* returns timestamp of last time friendnumber was seen online or 0 if never seen. + * if friendnumber is invalid this function will return UINT64_MAX. + */ +uint64_t m_get_last_online(const Messenger *m, int32_t friendnumber); + +/* Set our typing status for a friend. + * You are responsible for turning it on or off. + * + * returns 0 on success. + * returns -1 on failure. + */ +int m_set_usertyping(Messenger *m, int32_t friendnumber, uint8_t is_typing); + +/* Get the typing status of a friend. + * + * returns 0 if friend is not typing. + * returns 1 if friend is typing. + */ +int m_get_istyping(const Messenger *m, int32_t friendnumber); + +/* Set the logger callback. + */ +void m_callback_log(Messenger *m, logger_cb *function, void *context, void *userdata); + +/* Set the function that will be executed when a friend request is received. + * Function format is function(uint8_t * public_key, uint8_t * data, size_t length) + */ +void m_callback_friendrequest(Messenger *m, void (*function)(Messenger *m, const uint8_t *, const uint8_t *, size_t, + void *)); + +/* Set the function that will be executed when a message from a friend is received. + * Function format is: function(uint32_t friendnumber, unsigned int type, uint8_t * message, uint32_t length) + */ +void m_callback_friendmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, const uint8_t *, + size_t, void *)); + +/* Set the callback for name changes. + * Function(uint32_t friendnumber, uint8_t *newname, size_t length) + * You are not responsible for freeing newname. + */ +void m_callback_namechange(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *)); + +/* Set the callback for status message changes. + * Function(uint32_t friendnumber, uint8_t *newstatus, size_t length) + * + * You are not responsible for freeing newstatus + */ +void m_callback_statusmessage(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, size_t, void *)); + +/* Set the callback for status type changes. + * Function(uint32_t friendnumber, USERSTATUS kind) + */ +void m_callback_userstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *)); + +/* Set the callback for typing changes. + * Function(uint32_t friendnumber, uint8_t is_typing) + */ +void m_callback_typingchange(Messenger *m, void(*function)(Messenger *m, uint32_t, bool, void *)); + +/* Set the callback for read receipts. + * Function(uint32_t friendnumber, uint32_t receipt) + * + * If you are keeping a record of returns from m_sendmessage, + * receipt might be one of those values, meaning the message + * has been received on the other side. + * Since core doesn't track ids for you, receipt may not correspond to any message. + * In that case, you should discard it. + */ +void m_callback_read_receipt(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, void *)); + +/* Set the callback for connection status changes. + * function(uint32_t friendnumber, uint8_t status) + * + * Status: + * 0 -- friend went offline after being previously online. + * 1 -- friend went online. + * + * Note that this callback is not called when adding friends, thus the "after + * being previously online" part. + * It's assumed that when adding friends, their connection status is offline. + */ +void m_callback_connectionstatus(Messenger *m, void (*function)(Messenger *m, uint32_t, unsigned int, void *)); + +/* Same as previous but for internal A/V core usage only */ +void m_callback_connectionstatus_internal_av(Messenger *m, void (*function)(Messenger *m, uint32_t, uint8_t, void *), + void *userdata); + + +/* Set the callback for typing changes. + * Function(unsigned int connection_status (0 = not connected, 1 = TCP only, 2 = UDP + TCP)) + */ +void m_callback_core_connection(Messenger *m, void (*function)(Messenger *m, unsigned int, void *)); + +/**********CONFERENCES************/ + +/* Set the callback for conference invites. + * + * Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) + */ +void m_callback_conference_invite(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, + void *)); + +/* Send a conference invite packet. + * + * return 1 on success + * return 0 on failure + */ +int send_conference_invite_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length); + +/****************FILE SENDING*****************/ + + +/* Set the callback for file send requests. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint32_t filetype, uint64_t filesize, uint8_t *filename, size_t filename_length, void *userdata) + */ +void callback_file_sendrequest(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint32_t, uint64_t, + const uint8_t *, size_t, void *)); + + +/* Set the callback for file control requests. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, unsigned int control_type, void *userdata) + * + */ +void callback_file_control(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, unsigned int, void *)); + +/* Set the callback for file data. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, uint8_t *data, size_t length, void *userdata) + * + */ +void callback_file_data(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, const uint8_t *, + size_t, void *)); + +/* Set the callback for file request chunk. + * + * Function(Tox *tox, uint32_t friendnumber, uint32_t filenumber, uint64_t position, size_t length, void *userdata) + * + */ +void callback_file_reqchunk(Messenger *m, void (*function)(Messenger *m, uint32_t, uint32_t, uint64_t, size_t, void *)); + + +/* Copy the file transfer file id to file_id + * + * return 0 on success. + * return -1 if friend not valid. + * return -2 if filenumber not valid + */ +int file_get_id(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint8_t *file_id); + +/* Send a file send request. + * Maximum filename length is 255 bytes. + * return file number on success + * return -1 if friend not found. + * return -2 if filename length invalid. + * return -3 if no more file sending slots left. + * return -4 if could not send packet (friend offline). + * + */ +long int new_filesender(const Messenger *m, int32_t friendnumber, uint32_t file_type, uint64_t filesize, + const uint8_t *file_id, const uint8_t *filename, uint16_t filename_length); + +/* Send a file control request. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if file number invalid. + * return -4 if file control is bad. + * return -5 if file already paused. + * return -6 if resume file failed because it was only paused by the other. + * return -7 if resume file failed because it wasn't paused. + * return -8 if packet failed to send. + */ +int file_control(const Messenger *m, int32_t friendnumber, uint32_t filenumber, unsigned int control); + +/* Send a seek file control request. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if file number invalid. + * return -4 if not receiving file. + * return -5 if file status wrong. + * return -6 if position bad. + * return -8 if packet failed to send. + */ +int file_seek(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position); + +/* Send file data. + * + * return 0 on success + * return -1 if friend not valid. + * return -2 if friend not online. + * return -3 if filenumber invalid. + * return -4 if file transfer not transferring. + * return -5 if bad data size. + * return -6 if packet queue full. + * return -7 if wrong position. + */ +int file_data(const Messenger *m, int32_t friendnumber, uint32_t filenumber, uint64_t position, const uint8_t *data, + uint16_t length); + +/* Give the number of bytes left to be sent/received. + * + * send_receive is 0 if we want the sending files, 1 if we want the receiving. + * + * return number of bytes remaining to be sent/received on success + * return 0 on failure + */ +uint64_t file_dataremaining(const Messenger *m, int32_t friendnumber, uint8_t filenumber, uint8_t send_receive); + +/*************** A/V related ******************/ + +/* Set the callback for msi packets. + * + * Function(Messenger *m, uint32_t friendnumber, uint8_t *data, uint16_t length, void *userdata) + */ +void m_callback_msi_packet(Messenger *m, void (*function)(Messenger *m, uint32_t, const uint8_t *, uint16_t, void *), + void *userdata); + +/* Send an msi packet. + * + * return 1 on success + * return 0 on failure + */ +int m_msi_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint16_t length); + +/* Set handlers for lossy rtp packets. + * + * return -1 on failure. + * return 0 on success. + */ +int m_callback_rtp_packet(Messenger *m, int32_t friendnumber, uint8_t byte, int (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, uint16_t len, void *object), void *object); + +/**********************************************/ + +/* Set handlers for custom lossy packets. + * + */ +void custom_lossy_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, size_t len, void *object)); + +/* High level function to send custom lossy packets. + * + * return -1 if friend invalid. + * return -2 if length wrong. + * return -3 if first byte invalid. + * return -4 if friend offline. + * return -5 if packet failed to send because of other error. + * return 0 on success. + */ +int m_send_custom_lossy_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length); + + +/* Set handlers for custom lossless packets. + * + */ +void custom_lossless_packet_registerhandler(Messenger *m, void (*packet_handler_callback)(Messenger *m, + uint32_t friendnumber, const uint8_t *data, size_t len, void *object)); + +/* High level function to send custom lossless packets. + * + * return -1 if friend invalid. + * return -2 if length wrong. + * return -3 if first byte invalid. + * return -4 if friend offline. + * return -5 if packet failed to send because of other error. + * return 0 on success. + */ +int send_custom_lossless_packet(const Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length); + +/**********************************************/ + +enum { + MESSENGER_ERROR_NONE, + MESSENGER_ERROR_PORT, + MESSENGER_ERROR_TCP_SERVER, + MESSENGER_ERROR_OTHER +}; + +/* Run this at startup. + * return allocated instance of Messenger on success. + * return 0 if there are problems. + * + * if error is not NULL it will be set to one of the values in the enum above. + */ +Messenger *new_messenger(Messenger_Options *options, unsigned int *error); + +/* Run this before closing shop + * Free all datastructures. + */ +void kill_messenger(Messenger *m); + +/* The main loop that needs to be run at least 20 times per second. */ +void do_messenger(Messenger *m, void *userdata); + +/* Return the time in milliseconds before do_messenger() should be called again + * for optimal performance. + * + * returns time (in ms) before the next do_messenger() needs to be run on success. + */ +uint32_t messenger_run_interval(const Messenger *m); + +/* SAVING AND LOADING FUNCTIONS: */ + +/* return size of the messenger data (for saving). */ +uint32_t messenger_size(const Messenger *m); + +/* Save the messenger in data (must be allocated memory of size Messenger_size()) */ +void messenger_save(const Messenger *m, uint8_t *data); + +/* Load the messenger from data of size length. */ +int messenger_load(Messenger *m, const uint8_t *data, uint32_t length); + +/* Return the number of friends in the instance m. + * You should use this to determine how much memory to allocate + * for copy_friendlist. */ +uint32_t count_friendlist(const Messenger *m); + +/* Copy a list of valid friend IDs into the array out_list. + * If out_list is NULL, returns 0. + * Otherwise, returns the number of elements copied. + * If the array was too small, the contents + * of out_list will be truncated to list_size. */ +uint32_t copy_friendlist(const Messenger *m, uint32_t *out_list, uint32_t list_size); + +#endif diff --git a/libs/libtox/src/toxcore/TCP_client.c b/libs/libtox/src/toxcore/TCP_client.c new file mode 100644 index 0000000000..8a14c7cd70 --- /dev/null +++ b/libs/libtox/src/toxcore/TCP_client.c @@ -0,0 +1,991 @@ +/* + * Implementation of the TCP relay client part of Tox. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "TCP_client.h" + +#include "util.h" + +#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) +#include +#endif + +/* return 1 on success + * return 0 on failure + */ +static int connect_sock_to(Socket sock, IP_Port ip_port, TCP_Proxy_Info *proxy_info) +{ + if (proxy_info->proxy_type != TCP_PROXY_NONE) { + ip_port = proxy_info->ip_port; + } + + /* nonblocking socket, connect will never return success */ + net_connect(sock, ip_port); + return 1; +} + +/* return 1 on success. + * return 0 on failure. + */ +static int proxy_http_generate_connection_request(TCP_Client_Connection *TCP_conn) +{ + char one[] = "CONNECT "; + char two[] = " HTTP/1.1\nHost: "; + char three[] = "\r\n\r\n"; + + char ip[TOX_INET6_ADDRSTRLEN]; + + if (!ip_parse_addr(&TCP_conn->ip_port.ip, ip, sizeof(ip))) { + return 0; + } + + const uint16_t port = net_ntohs(TCP_conn->ip_port.port); + const int written = snprintf((char *)TCP_conn->last_packet, MAX_PACKET_SIZE, "%s%s:%hu%s%s:%hu%s", one, ip, port, two, + ip, port, three); + + if (written < 0 || MAX_PACKET_SIZE < written) { + return 0; + } + + TCP_conn->last_packet_length = written; + TCP_conn->last_packet_sent = 0; + + return 1; +} + +/* return 1 on success. + * return 0 if no data received. + * return -1 on failure (connection refused). + */ +static int proxy_http_read_connection_response(TCP_Client_Connection *TCP_conn) +{ + char success[] = "200"; + uint8_t data[16]; // draining works the best if the length is a power of 2 + + int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data) - 1); + + if (ret == -1) { + return 0; + } + + data[sizeof(data) - 1] = 0; + + if (strstr((char *)data, success)) { + // drain all data + unsigned int data_left = TCP_socket_data_recv_buffer(TCP_conn->sock); + + if (data_left) { + VLA(uint8_t, temp_data, data_left); + read_TCP_packet(TCP_conn->sock, temp_data, data_left); + } + + return 1; + } + + return -1; +} + +static void proxy_socks5_generate_handshake(TCP_Client_Connection *TCP_conn) +{ + TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ + TCP_conn->last_packet[1] = 1; /* number of authentication methods supported */ + TCP_conn->last_packet[2] = 0; /* No authentication */ + + TCP_conn->last_packet_length = 3; + TCP_conn->last_packet_sent = 0; +} + +/* return 1 on success. + * return 0 if no data received. + * return -1 on failure (connection refused). + */ +static int socks5_read_handshake_response(TCP_Client_Connection *TCP_conn) +{ + uint8_t data[2]; + int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data)); + + if (ret == -1) { + return 0; + } + + if (data[0] == 5 && data[1] == 0) { // TODO(irungentoo): magic numbers + return 1; + } + + return -1; +} + +static void proxy_socks5_generate_connection_request(TCP_Client_Connection *TCP_conn) +{ + TCP_conn->last_packet[0] = 5; /* SOCKSv5 */ + TCP_conn->last_packet[1] = 1; /* command code: establish a TCP/IP stream connection */ + TCP_conn->last_packet[2] = 0; /* reserved, must be 0 */ + uint16_t length = 3; + + if (TCP_conn->ip_port.ip.family == TOX_AF_INET) { + TCP_conn->last_packet[3] = 1; /* IPv4 address */ + ++length; + memcpy(TCP_conn->last_packet + length, TCP_conn->ip_port.ip.ip4.uint8, sizeof(IP4)); + length += sizeof(IP4); + } else { + TCP_conn->last_packet[3] = 4; /* IPv6 address */ + ++length; + memcpy(TCP_conn->last_packet + length, TCP_conn->ip_port.ip.ip6.uint8, sizeof(IP6)); + length += sizeof(IP6); + } + + memcpy(TCP_conn->last_packet + length, &TCP_conn->ip_port.port, sizeof(uint16_t)); + length += sizeof(uint16_t); + + TCP_conn->last_packet_length = length; + TCP_conn->last_packet_sent = 0; +} + +/* return 1 on success. + * return 0 if no data received. + * return -1 on failure (connection refused). + */ +static int proxy_socks5_read_connection_response(TCP_Client_Connection *TCP_conn) +{ + if (TCP_conn->ip_port.ip.family == TOX_AF_INET) { + uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)]; + int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data)); + + if (ret == -1) { + return 0; + } + + if (data[0] == 5 && data[1] == 0) { + return 1; + } + } else { + uint8_t data[4 + sizeof(IP6) + sizeof(uint16_t)]; + int ret = read_TCP_packet(TCP_conn->sock, data, sizeof(data)); + + if (ret == -1) { + return 0; + } + + if (data[0] == 5 && data[1] == 0) { + return 1; + } + } + + return -1; +} + +/* return 0 on success. + * return -1 on failure. + */ +static int generate_handshake(TCP_Client_Connection *TCP_conn) +{ + uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; + crypto_new_keypair(plain, TCP_conn->temp_secret_key); + random_nonce(TCP_conn->sent_nonce); + memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, TCP_conn->sent_nonce, CRYPTO_NONCE_SIZE); + memcpy(TCP_conn->last_packet, TCP_conn->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + random_nonce(TCP_conn->last_packet + CRYPTO_PUBLIC_KEY_SIZE); + int len = encrypt_data_symmetric(TCP_conn->shared_key, TCP_conn->last_packet + CRYPTO_PUBLIC_KEY_SIZE, plain, + sizeof(plain), TCP_conn->last_packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if (len != sizeof(plain) + CRYPTO_MAC_SIZE) { + return -1; + } + + TCP_conn->last_packet_length = CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE; + TCP_conn->last_packet_sent = 0; + return 0; +} + +/* data must be of length TCP_SERVER_HANDSHAKE_SIZE + * + * return 0 on success. + * return -1 on failure. + */ +static int handle_handshake(TCP_Client_Connection *TCP_conn, const uint8_t *data) +{ + uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; + int len = decrypt_data_symmetric(TCP_conn->shared_key, data, data + CRYPTO_NONCE_SIZE, + TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, plain); + + if (len != sizeof(plain)) { + return -1; + } + + memcpy(TCP_conn->recv_nonce, plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE); + encrypt_precompute(plain, TCP_conn->temp_secret_key, TCP_conn->shared_key); + crypto_memzero(TCP_conn->temp_secret_key, CRYPTO_SECRET_KEY_SIZE); + return 0; +} + +/* return 0 if pending data was sent completely + * return -1 if it wasn't + */ +static int client_send_pending_data_nonpriority(TCP_Client_Connection *con) +{ + if (con->last_packet_length == 0) { + return 0; + } + + uint16_t left = con->last_packet_length - con->last_packet_sent; + const char *data = (const char *)(con->last_packet + con->last_packet_sent); + int len = send(con->sock, data, left, MSG_NOSIGNAL); + + if (len <= 0) { + return -1; + } + + if (len == left) { + con->last_packet_length = 0; + con->last_packet_sent = 0; + return 0; + } + + con->last_packet_sent += len; + return -1; +} + +/* return 0 if pending data was sent completely + * return -1 if it wasn't + */ +static int client_send_pending_data(TCP_Client_Connection *con) +{ + /* finish sending current non-priority packet */ + if (client_send_pending_data_nonpriority(con) == -1) { + return -1; + } + + TCP_Priority_List *p = con->priority_queue_start; + + while (p) { + uint16_t left = p->size - p->sent; + int len = send(con->sock, (const char *)(p->data + p->sent), left, MSG_NOSIGNAL); + + if (len != left) { + if (len > 0) { + p->sent += len; + } + + break; + } + + TCP_Priority_List *pp = p; + p = p->next; + free(pp); + } + + con->priority_queue_start = p; + + if (!p) { + con->priority_queue_end = NULL; + return 0; + } + + return -1; +} + +/* return 0 on failure (only if malloc fails) + * return 1 on success + */ +static bool client_add_priority(TCP_Client_Connection *con, const uint8_t *packet, uint16_t size, uint16_t sent) +{ + TCP_Priority_List *p = con->priority_queue_end; + TCP_Priority_List *new_list = (TCP_Priority_List *)malloc(sizeof(TCP_Priority_List) + size); + + if (!new_list) { + return 0; + } + + new_list->next = NULL; + new_list->size = size; + new_list->sent = sent; + memcpy(new_list->data, packet, size); + + if (p) { + p->next = new_list; + } else { + con->priority_queue_start = new_list; + } + + con->priority_queue_end = new_list; + return 1; +} + +static void wipe_priority_list(TCP_Client_Connection *con) +{ + TCP_Priority_List *p = con->priority_queue_start; + + while (p) { + TCP_Priority_List *pp = p; + p = p->next; + free(pp); + } +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int write_packet_TCP_client_secure_connection(TCP_Client_Connection *con, const uint8_t *data, uint16_t length, + bool priority) +{ + if (length + CRYPTO_MAC_SIZE > MAX_PACKET_SIZE) { + return -1; + } + + bool sendpriority = 1; + + if (client_send_pending_data(con) == -1) { + if (priority) { + sendpriority = 0; + } else { + return 0; + } + } + + VLA(uint8_t, packet, sizeof(uint16_t) + length + CRYPTO_MAC_SIZE); + + uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE); + memcpy(packet, &c_length, sizeof(uint16_t)); + int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); + + if ((unsigned int)len != (SIZEOF_VLA(packet) - sizeof(uint16_t))) { + return -1; + } + + if (priority) { + len = sendpriority ? send(con->sock, (const char *)packet, SIZEOF_VLA(packet), MSG_NOSIGNAL) : 0; + + if (len <= 0) { + len = 0; + } + + increment_nonce(con->sent_nonce); + + if ((unsigned int)len == SIZEOF_VLA(packet)) { + return 1; + } + + return client_add_priority(con, packet, SIZEOF_VLA(packet), len); + } + + len = send(con->sock, (const char *)packet, SIZEOF_VLA(packet), MSG_NOSIGNAL); + + if (len <= 0) { + return 0; + } + + increment_nonce(con->sent_nonce); + + if ((unsigned int)len == SIZEOF_VLA(packet)) { + return 1; + } + + memcpy(con->last_packet, packet, SIZEOF_VLA(packet)); + con->last_packet_length = SIZEOF_VLA(packet); + con->last_packet_sent = len; + return 1; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key) +{ + uint8_t packet[1 + CRYPTO_PUBLIC_KEY_SIZE]; + packet[0] = TCP_PACKET_ROUTING_REQUEST; + memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); + return write_packet_TCP_client_secure_connection(con, packet, sizeof(packet), 1); +} + +void routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id, + const uint8_t *public_key), void *object) +{ + con->response_callback = response_callback; + con->response_callback_object = object; +} + +void routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number, + uint8_t connection_id, uint8_t status), void *object) +{ + con->status_callback = status_callback; + con->status_callback_object = object; +} + +static int tcp_send_ping_response(TCP_Client_Connection *con); +static int tcp_send_ping_request(TCP_Client_Connection *con); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_data(TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length) +{ + if (con_id >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + if (con->connections[con_id].status != 2) { + return -1; + } + + if (tcp_send_ping_response(con) == 0 || tcp_send_ping_request(con) == 0) { + return 0; + } + + VLA(uint8_t, packet, 1 + length); + packet[0] = con_id + NUM_RESERVED_PORTS; + memcpy(packet + 1, data, length); + return write_packet_TCP_client_secure_connection(con, packet, SIZEOF_VLA(packet), 0); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_oob_packet(TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data, uint16_t length) +{ + if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) { + return -1; + } + + VLA(uint8_t, packet, 1 + CRYPTO_PUBLIC_KEY_SIZE + length); + packet[0] = TCP_PACKET_OOB_SEND; + memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length); + return write_packet_TCP_client_secure_connection(con, packet, SIZEOF_VLA(packet), 0); +} + + +/* Set the number that will be used as an argument in the callbacks related to con_id. + * + * When not set by this function, the number is ~0. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number) +{ + if (con_id >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + if (con->connections[con_id].status == 0) { + return -1; + } + + con->connections[con_id].number = number; + return 0; +} + +void routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number, + uint8_t connection_id, const uint8_t *data, uint16_t length, void *userdata), void *object) +{ + con->data_callback = data_callback; + con->data_callback_object = object; +} + +void oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, const uint8_t *public_key, + const uint8_t *data, uint16_t length, void *userdata), void *object) +{ + con->oob_data_callback = oob_data_callback; + con->oob_data_callback_object = object; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int client_send_disconnect_notification(TCP_Client_Connection *con, uint8_t id) +{ + uint8_t packet[1 + 1]; + packet[0] = TCP_PACKET_DISCONNECT_NOTIFICATION; + packet[1] = id; + return write_packet_TCP_client_secure_connection(con, packet, sizeof(packet), 1); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int tcp_send_ping_request(TCP_Client_Connection *con) +{ + if (!con->ping_request_id) { + return 1; + } + + uint8_t packet[1 + sizeof(uint64_t)]; + packet[0] = TCP_PACKET_PING; + memcpy(packet + 1, &con->ping_request_id, sizeof(uint64_t)); + int ret; + + if ((ret = write_packet_TCP_client_secure_connection(con, packet, sizeof(packet), 1)) == 1) { + con->ping_request_id = 0; + } + + return ret; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int tcp_send_ping_response(TCP_Client_Connection *con) +{ + if (!con->ping_response_id) { + return 1; + } + + uint8_t packet[1 + sizeof(uint64_t)]; + packet[0] = TCP_PACKET_PONG; + memcpy(packet + 1, &con->ping_response_id, sizeof(uint64_t)); + int ret; + + if ((ret = write_packet_TCP_client_secure_connection(con, packet, sizeof(packet), 1)) == 1) { + con->ping_response_id = 0; + } + + return ret; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id) +{ + if (con_id >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + con->connections[con_id].status = 0; + con->connections[con_id].number = 0; + return client_send_disconnect_notification(con, con_id + NUM_RESERVED_PORTS); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_onion_request(TCP_Client_Connection *con, const uint8_t *data, uint16_t length) +{ + VLA(uint8_t, packet, 1 + length); + packet[0] = TCP_PACKET_ONION_REQUEST; + memcpy(packet + 1, data, length); + return write_packet_TCP_client_secure_connection(con, packet, SIZEOF_VLA(packet), 0); +} + +void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, const uint8_t *data, + uint16_t length, void *userdata), void *object) +{ + con->onion_callback = onion_callback; + con->onion_callback_object = object; +} + +/* Create new TCP connection to ip_port/public_key + */ +TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key, + const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info) +{ + if (networking_at_startup() != 0) { + return NULL; + } + + if (ip_port.ip.family != TOX_AF_INET && ip_port.ip.family != TOX_AF_INET6) { + return NULL; + } + + TCP_Proxy_Info default_proxyinfo; + + if (proxy_info == NULL) { + default_proxyinfo.proxy_type = TCP_PROXY_NONE; + proxy_info = &default_proxyinfo; + } + + uint8_t family = ip_port.ip.family; + + if (proxy_info->proxy_type != TCP_PROXY_NONE) { + family = proxy_info->ip_port.ip.family; + } + + Socket sock = net_socket(family, TOX_SOCK_STREAM, TOX_PROTO_TCP); + + if (!sock_valid(sock)) { + return NULL; + } + + if (!set_socket_nosigpipe(sock)) { + kill_sock(sock); + return 0; + } + + if (!(set_socket_nonblock(sock) && connect_sock_to(sock, ip_port, proxy_info))) { + kill_sock(sock); + return NULL; + } + + TCP_Client_Connection *temp = (TCP_Client_Connection *)calloc(sizeof(TCP_Client_Connection), 1); + + if (temp == NULL) { + kill_sock(sock); + return NULL; + } + + temp->sock = sock; + memcpy(temp->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(temp->self_public_key, self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + encrypt_precompute(temp->public_key, self_secret_key, temp->shared_key); + temp->ip_port = ip_port; + temp->proxy_info = *proxy_info; + + switch (proxy_info->proxy_type) { + case TCP_PROXY_HTTP: + temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING; + proxy_http_generate_connection_request(temp); + break; + + case TCP_PROXY_SOCKS5: + temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING; + proxy_socks5_generate_handshake(temp); + break; + + case TCP_PROXY_NONE: + temp->status = TCP_CLIENT_CONNECTING; + + if (generate_handshake(temp) == -1) { + kill_sock(sock); + free(temp); + return NULL; + } + + break; + } + + temp->kill_at = unix_time() + TCP_CONNECTION_TIMEOUT; + + return temp; +} + +/* return 0 on success + * return -1 on failure + */ +static int handle_TCP_client_packet(TCP_Client_Connection *conn, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length <= 1) { + return -1; + } + + switch (data[0]) { + case TCP_PACKET_ROUTING_RESPONSE: { + if (length != 1 + 1 + CRYPTO_PUBLIC_KEY_SIZE) { + return -1; + } + + if (data[1] < NUM_RESERVED_PORTS) { + return 0; + } + + uint8_t con_id = data[1] - NUM_RESERVED_PORTS; + + if (conn->connections[con_id].status != 0) { + return 0; + } + + conn->connections[con_id].status = 1; + conn->connections[con_id].number = ~0; + memcpy(conn->connections[con_id].public_key, data + 2, CRYPTO_PUBLIC_KEY_SIZE); + + if (conn->response_callback) { + conn->response_callback(conn->response_callback_object, con_id, conn->connections[con_id].public_key); + } + + return 0; + } + + case TCP_PACKET_CONNECTION_NOTIFICATION: { + if (length != 1 + 1) { + return -1; + } + + if (data[1] < NUM_RESERVED_PORTS) { + return -1; + } + + uint8_t con_id = data[1] - NUM_RESERVED_PORTS; + + if (conn->connections[con_id].status != 1) { + return 0; + } + + conn->connections[con_id].status = 2; + + if (conn->status_callback) { + conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, + conn->connections[con_id].status); + } + + return 0; + } + + case TCP_PACKET_DISCONNECT_NOTIFICATION: { + if (length != 1 + 1) { + return -1; + } + + if (data[1] < NUM_RESERVED_PORTS) { + return -1; + } + + uint8_t con_id = data[1] - NUM_RESERVED_PORTS; + + if (conn->connections[con_id].status == 0) { + return 0; + } + + if (conn->connections[con_id].status != 2) { + return 0; + } + + conn->connections[con_id].status = 1; + + if (conn->status_callback) { + conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, + conn->connections[con_id].status); + } + + return 0; + } + + case TCP_PACKET_PING: { + if (length != 1 + sizeof(uint64_t)) { + return -1; + } + + uint64_t ping_id; + memcpy(&ping_id, data + 1, sizeof(uint64_t)); + conn->ping_response_id = ping_id; + tcp_send_ping_response(conn); + return 0; + } + + case TCP_PACKET_PONG: { + if (length != 1 + sizeof(uint64_t)) { + return -1; + } + + uint64_t ping_id; + memcpy(&ping_id, data + 1, sizeof(uint64_t)); + + if (ping_id) { + if (ping_id == conn->ping_id) { + conn->ping_id = 0; + } + + return 0; + } + + return -1; + } + + case TCP_PACKET_OOB_RECV: { + if (length <= 1 + CRYPTO_PUBLIC_KEY_SIZE) { + return -1; + } + + if (conn->oob_data_callback) { + conn->oob_data_callback(conn->oob_data_callback_object, data + 1, data + 1 + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_PUBLIC_KEY_SIZE), userdata); + } + + return 0; + } + + case TCP_PACKET_ONION_RESPONSE: { + conn->onion_callback(conn->onion_callback_object, data + 1, length - 1, userdata); + return 0; + } + + default: { + if (data[0] < NUM_RESERVED_PORTS) { + return -1; + } + + uint8_t con_id = data[0] - NUM_RESERVED_PORTS; + + if (conn->data_callback) { + conn->data_callback(conn->data_callback_object, conn->connections[con_id].number, con_id, data + 1, length - 1, + userdata); + } + } + } + + return 0; +} + +static int do_confirmed_TCP(TCP_Client_Connection *conn, void *userdata) +{ + client_send_pending_data(conn); + tcp_send_ping_response(conn); + tcp_send_ping_request(conn); + + uint8_t packet[MAX_PACKET_SIZE]; + int len; + + if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) { + uint64_t ping_id = random_64b(); + + if (!ping_id) { + ++ping_id; + } + + conn->ping_request_id = conn->ping_id = ping_id; + tcp_send_ping_request(conn); + conn->last_pinged = unix_time(); + } + + if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) { + conn->status = TCP_CLIENT_DISCONNECTED; + return 0; + } + + while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, + conn->recv_nonce, packet, sizeof(packet)))) { + if (len == -1) { + conn->status = TCP_CLIENT_DISCONNECTED; + break; + } + + if (handle_TCP_client_packet(conn, packet, len, userdata) == -1) { + conn->status = TCP_CLIENT_DISCONNECTED; + break; + } + } + + return 0; +} + +/* Run the TCP connection + */ +void do_TCP_connection(TCP_Client_Connection *TCP_connection, void *userdata) +{ + unix_time_update(); + + if (TCP_connection->status == TCP_CLIENT_DISCONNECTED) { + return; + } + + if (TCP_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) { + if (client_send_pending_data(TCP_connection) == 0) { + int ret = proxy_http_read_connection_response(TCP_connection); + + if (ret == -1) { + TCP_connection->kill_at = 0; + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } + + if (ret == 1) { + generate_handshake(TCP_connection); + TCP_connection->status = TCP_CLIENT_CONNECTING; + } + } + } + + if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) { + if (client_send_pending_data(TCP_connection) == 0) { + int ret = socks5_read_handshake_response(TCP_connection); + + if (ret == -1) { + TCP_connection->kill_at = 0; + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } + + if (ret == 1) { + proxy_socks5_generate_connection_request(TCP_connection); + TCP_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED; + } + } + } + + if (TCP_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) { + if (client_send_pending_data(TCP_connection) == 0) { + int ret = proxy_socks5_read_connection_response(TCP_connection); + + if (ret == -1) { + TCP_connection->kill_at = 0; + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } + + if (ret == 1) { + generate_handshake(TCP_connection); + TCP_connection->status = TCP_CLIENT_CONNECTING; + } + } + } + + if (TCP_connection->status == TCP_CLIENT_CONNECTING) { + if (client_send_pending_data(TCP_connection) == 0) { + TCP_connection->status = TCP_CLIENT_UNCONFIRMED; + } + } + + if (TCP_connection->status == TCP_CLIENT_UNCONFIRMED) { + uint8_t data[TCP_SERVER_HANDSHAKE_SIZE]; + int len = read_TCP_packet(TCP_connection->sock, data, sizeof(data)); + + if (sizeof(data) == len) { + if (handle_handshake(TCP_connection, data) == 0) { + TCP_connection->kill_at = ~0; + TCP_connection->status = TCP_CLIENT_CONFIRMED; + } else { + TCP_connection->kill_at = 0; + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } + } + } + + if (TCP_connection->status == TCP_CLIENT_CONFIRMED) { + do_confirmed_TCP(TCP_connection, userdata); + } + + if (TCP_connection->kill_at <= unix_time()) { + TCP_connection->status = TCP_CLIENT_DISCONNECTED; + } +} + +/* Kill the TCP connection + */ +void kill_TCP_connection(TCP_Client_Connection *TCP_connection) +{ + if (TCP_connection == NULL) { + return; + } + + wipe_priority_list(TCP_connection); + kill_sock(TCP_connection->sock); + crypto_memzero(TCP_connection, sizeof(TCP_Client_Connection)); + free(TCP_connection); +} diff --git a/libs/libtox/src/toxcore/TCP_client.h b/libs/libtox/src/toxcore/TCP_client.h new file mode 100644 index 0000000000..212543147c --- /dev/null +++ b/libs/libtox/src/toxcore/TCP_client.h @@ -0,0 +1,167 @@ +/* + * Implementation of the TCP relay client part of Tox. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef TCP_CLIENT_H +#define TCP_CLIENT_H + +#include "TCP_server.h" +#include "crypto_core.h" + +#define TCP_CONNECTION_TIMEOUT 10 + +typedef enum { + TCP_PROXY_NONE, + TCP_PROXY_HTTP, + TCP_PROXY_SOCKS5 +} TCP_PROXY_TYPE; + +typedef struct { + IP_Port ip_port; + uint8_t proxy_type; // a value from TCP_PROXY_TYPE +} TCP_Proxy_Info; + +enum { + TCP_CLIENT_NO_STATUS, + TCP_CLIENT_PROXY_HTTP_CONNECTING, + TCP_CLIENT_PROXY_SOCKS5_CONNECTING, + TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED, + TCP_CLIENT_CONNECTING, + TCP_CLIENT_UNCONFIRMED, + TCP_CLIENT_CONFIRMED, + TCP_CLIENT_DISCONNECTED, +}; +typedef struct { + uint8_t status; + Socket sock; + uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* our public key */ + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* public key of the server */ + IP_Port ip_port; /* The ip and port of the server */ + TCP_Proxy_Info proxy_info; + uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ + uint8_t sent_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of sent packets. */ + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint16_t next_packet_length; + + uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + uint8_t last_packet[2 + MAX_PACKET_SIZE]; + uint16_t last_packet_length; + uint16_t last_packet_sent; + + TCP_Priority_List *priority_queue_start, *priority_queue_end; + + uint64_t kill_at; + + uint64_t last_pinged; + uint64_t ping_id; + + uint64_t ping_response_id; + uint64_t ping_request_id; + + struct { + uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */ + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint32_t number; + } connections[NUM_CLIENT_CONNECTIONS]; + int (*response_callback)(void *object, uint8_t connection_id, const uint8_t *public_key); + void *response_callback_object; + int (*status_callback)(void *object, uint32_t number, uint8_t connection_id, uint8_t status); + void *status_callback_object; + int (*data_callback)(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data, uint16_t length, + void *userdata); + void *data_callback_object; + int (*oob_data_callback)(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length, void *userdata); + void *oob_data_callback_object; + + int (*onion_callback)(void *object, const uint8_t *data, uint16_t length, void *userdata); + void *onion_callback_object; + + /* Can be used by user. */ + void *custom_object; + uint32_t custom_uint; +} TCP_Client_Connection; + +/* Create new TCP connection to ip_port/public_key + */ +TCP_Client_Connection *new_TCP_connection(IP_Port ip_port, const uint8_t *public_key, const uint8_t *self_public_key, + const uint8_t *self_secret_key, TCP_Proxy_Info *proxy_info); + +/* Run the TCP connection + */ +void do_TCP_connection(TCP_Client_Connection *TCP_connection, void *userdata); + +/* Kill the TCP connection + */ +void kill_TCP_connection(TCP_Client_Connection *TCP_connection); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_onion_request(TCP_Client_Connection *con, const uint8_t *data, uint16_t length); +void onion_response_handler(TCP_Client_Connection *con, int (*onion_callback)(void *object, const uint8_t *data, + uint16_t length, void *userdata), void *object); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_routing_request(TCP_Client_Connection *con, uint8_t *public_key); +void routing_response_handler(TCP_Client_Connection *con, int (*response_callback)(void *object, uint8_t connection_id, + const uint8_t *public_key), void *object); +void routing_status_handler(TCP_Client_Connection *con, int (*status_callback)(void *object, uint32_t number, + uint8_t connection_id, uint8_t status), void *object); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +int send_disconnect_request(TCP_Client_Connection *con, uint8_t con_id); + +/* Set the number that will be used as an argument in the callbacks related to con_id. + * + * When not set by this function, the number is ~0. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_data(TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length); +void routing_data_handler(TCP_Client_Connection *con, int (*data_callback)(void *object, uint32_t number, + uint8_t connection_id, const uint8_t *data, uint16_t length, void *userdata), void *object); + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure. + */ +int send_oob_packet(TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data, uint16_t length); +void oob_data_handler(TCP_Client_Connection *con, int (*oob_data_callback)(void *object, const uint8_t *public_key, + const uint8_t *data, uint16_t length, void *userdata), void *object); + + +#endif diff --git a/libs/libtox/src/toxcore/TCP_connection.c b/libs/libtox/src/toxcore/TCP_connection.c new file mode 100644 index 0000000000..251594912a --- /dev/null +++ b/libs/libtox/src/toxcore/TCP_connection.c @@ -0,0 +1,1491 @@ +/* + * Handles TCP relay connections between two Tox clients. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2015 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "TCP_connection.h" + +#include "util.h" + +#include + + +struct TCP_Connections { + DHT *dht; + + uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + TCP_Connection_to *connections; + uint32_t connections_length; /* Length of connections array. */ + + TCP_con *tcp_connections; + uint32_t tcp_connections_length; /* Length of tcp_connections array. */ + + int (*tcp_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + void *tcp_data_callback_object; + + int (*tcp_oob_callback)(void *object, const uint8_t *public_key, unsigned int tcp_connections_number, + const uint8_t *data, uint16_t length, void *userdata); + void *tcp_oob_callback_object; + + int (*tcp_onion_callback)(void *object, const uint8_t *data, uint16_t length, void *userdata); + void *tcp_onion_callback_object; + + TCP_Proxy_Info proxy_info; + + bool onion_status; + uint16_t onion_num_conns; +}; + + +const uint8_t *tcp_connections_public_key(const TCP_Connections *tcp_c) +{ + return tcp_c->self_public_key; +} + + +/* Set the size of the array to num. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +#define realloc_tox_array(array, element_type, num, temp_pointer) \ + (num \ + ? (temp_pointer = (element_type *)realloc( \ + array, \ + (num) * sizeof(element_type)), \ + temp_pointer ? (array = temp_pointer, 0) : -1) \ + : (free(array), array = NULL, 0)) + + +/* return 1 if the connections_number is not valid. + * return 0 if the connections_number is valid. + */ +static bool connections_number_not_valid(const TCP_Connections *tcp_c, int connections_number) +{ + if ((unsigned int)connections_number >= tcp_c->connections_length) { + return 1; + } + + if (tcp_c->connections == NULL) { + return 1; + } + + if (tcp_c->connections[connections_number].status == TCP_CONN_NONE) { + return 1; + } + + return 0; +} + +/* return 1 if the tcp_connections_number is not valid. + * return 0 if the tcp_connections_number is valid. + */ +static bool tcp_connections_number_not_valid(const TCP_Connections *tcp_c, int tcp_connections_number) +{ + if ((unsigned int)tcp_connections_number >= tcp_c->tcp_connections_length) { + return 1; + } + + if (tcp_c->tcp_connections == NULL) { + return 1; + } + + if (tcp_c->tcp_connections[tcp_connections_number].status == TCP_CONN_NONE) { + return 1; + } + + return 0; +} + +/* Create a new empty connection. + * + * return -1 on failure. + * return connections_number on success. + */ +static int create_connection(TCP_Connections *tcp_c) +{ + uint32_t i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + if (tcp_c->connections[i].status == TCP_CONN_NONE) { + return i; + } + } + + int id = -1; + + TCP_Connection_to *temp_pointer; + + if (realloc_tox_array(tcp_c->connections, TCP_Connection_to, tcp_c->connections_length + 1, + temp_pointer) == 0) { + id = tcp_c->connections_length; + ++tcp_c->connections_length; + memset(&(tcp_c->connections[id]), 0, sizeof(TCP_Connection_to)); + } + + return id; +} + +/* Create a new empty tcp connection. + * + * return -1 on failure. + * return tcp_connections_number on success. + */ +static int create_tcp_connection(TCP_Connections *tcp_c) +{ + uint32_t i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + if (tcp_c->tcp_connections[i].status == TCP_CONN_NONE) { + return i; + } + } + + int id = -1; + + TCP_con *temp_pointer; + + if (realloc_tox_array(tcp_c->tcp_connections, TCP_con, tcp_c->tcp_connections_length + 1, temp_pointer) == 0) { + id = tcp_c->tcp_connections_length; + ++tcp_c->tcp_connections_length; + memset(&(tcp_c->tcp_connections[id]), 0, sizeof(TCP_con)); + } + + return id; +} + +/* Wipe a connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_connection(TCP_Connections *tcp_c, int connections_number) +{ + if (connections_number_not_valid(tcp_c, connections_number)) { + return -1; + } + + uint32_t i; + memset(&(tcp_c->connections[connections_number]), 0 , sizeof(TCP_Connection_to)); + + for (i = tcp_c->connections_length; i != 0; --i) { + if (tcp_c->connections[i - 1].status != TCP_CONN_NONE) { + break; + } + } + + if (tcp_c->connections_length != i) { + tcp_c->connections_length = i; + TCP_Connection_to *temp_pointer; + realloc_tox_array(tcp_c->connections, TCP_Connection_to, tcp_c->connections_length, temp_pointer); + } + + return 0; +} + +/* Wipe a connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_tcp_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + if (tcp_connections_number_not_valid(tcp_c, tcp_connections_number)) { + return -1; + } + + uint32_t i; + memset(&(tcp_c->tcp_connections[tcp_connections_number]), 0 , sizeof(TCP_con)); + + for (i = tcp_c->tcp_connections_length; i != 0; --i) { + if (tcp_c->tcp_connections[i - 1].status != TCP_CONN_NONE) { + break; + } + } + + if (tcp_c->tcp_connections_length != i) { + tcp_c->tcp_connections_length = i; + TCP_con *temp_pointer; + realloc_tox_array(tcp_c->tcp_connections, TCP_con, tcp_c->tcp_connections_length, temp_pointer); + } + + return 0; +} + +static TCP_Connection_to *get_connection(const TCP_Connections *tcp_c, int connections_number) +{ + if (connections_number_not_valid(tcp_c, connections_number)) { + return 0; + } + + return &tcp_c->connections[connections_number]; +} + +static TCP_con *get_tcp_connection(const TCP_Connections *tcp_c, int tcp_connections_number) +{ + if (tcp_connections_number_not_valid(tcp_c, tcp_connections_number)) { + return 0; + } + + return &tcp_c->tcp_connections[tcp_connections_number]; +} + +/* Send a packet to the TCP connection. + * + * return -1 on failure. + * return 0 on success. + */ +int send_packet_tcp_connection(TCP_Connections *tcp_c, int connections_number, const uint8_t *packet, uint16_t length) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + // TODO(irungentoo): detect and kill bad relays. + // TODO(irungentoo): thread safety? + unsigned int i; + int ret = -1; + + bool limit_reached = 0; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + uint32_t tcp_con_num = con_to->connections[i].tcp_connection; + uint8_t status = con_to->connections[i].status; + uint8_t connection_id = con_to->connections[i].connection_id; + + if (tcp_con_num && status == TCP_CONNECTIONS_STATUS_ONLINE) { + tcp_con_num -= 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_con_num); + + if (!tcp_con) { + continue; + } + + ret = send_data(tcp_con->connection, connection_id, packet, length); + + if (ret == 0) { + limit_reached = 1; + } + + if (ret == 1) { + break; + } + } + } + + if (ret == 1) { + return 0; + } + + if (!limit_reached) { + ret = 0; + + /* Send oob packets to all relays tied to the connection. */ + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + uint32_t tcp_con_num = con_to->connections[i].tcp_connection; + uint8_t status = con_to->connections[i].status; + + if (tcp_con_num && status == TCP_CONNECTIONS_STATUS_REGISTERED) { + tcp_con_num -= 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_con_num); + + if (!tcp_con) { + continue; + } + + if (send_oob_packet(tcp_con->connection, con_to->public_key, packet, length) == 1) { + ret += 1; + } + } + } + + if (ret >= 1) { + return 0; + } + + return -1; + } + + return -1; +} + +/* Return a random TCP connection number for use in send_tcp_onion_request. + * + * TODO(irungentoo): This number is just the index of an array that the elements + * can change without warning. + * + * return TCP connection number on success. + * return -1 on failure. + */ +int get_random_tcp_onion_conn_number(TCP_Connections *tcp_c) +{ + unsigned int i, r = rand(); + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + unsigned int index = ((i + r) % tcp_c->tcp_connections_length); + + if (tcp_c->tcp_connections[index].onion && tcp_c->tcp_connections[index].status == TCP_CONN_CONNECTED) { + return index; + } + } + + return -1; +} + +/* Send an onion packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int tcp_send_onion_request(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *data, + uint16_t length) +{ + if (tcp_connections_number >= tcp_c->tcp_connections_length) { + return -1; + } + + if (tcp_c->tcp_connections[tcp_connections_number].status == TCP_CONN_CONNECTED) { + int ret = send_onion_request(tcp_c->tcp_connections[tcp_connections_number].connection, data, length); + + if (ret == 1) { + return 0; + } + } + + return -1; +} + +/* Send an oob packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int tcp_send_oob_packet(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *public_key, + const uint8_t *packet, uint16_t length) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status != TCP_CONN_CONNECTED) { + return -1; + } + + int ret = send_oob_packet(tcp_con->connection, public_key, packet, length); + + if (ret == 1) { + return 0; + } + + return -1; +} + +/* Set the callback for TCP data packets. + */ +void set_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_data_callback)(void *object, int id, + const uint8_t *data, uint16_t length, void *userdata), void *object) +{ + tcp_c->tcp_data_callback = tcp_data_callback; + tcp_c->tcp_data_callback_object = object; +} + +/* Set the callback for TCP onion packets. + */ +void set_oob_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_oob_callback)(void *object, + const uint8_t *public_key, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length, void *userdata), + void *object) +{ + tcp_c->tcp_oob_callback = tcp_oob_callback; + tcp_c->tcp_oob_callback_object = object; +} + +/* Set the callback for TCP oob data packets. + */ +void set_onion_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_onion_callback)(void *object, + const uint8_t *data, uint16_t length, void *userdata), void *object) +{ + tcp_c->tcp_onion_callback = tcp_onion_callback; + tcp_c->tcp_onion_callback_object = object; +} + + +/* Find the TCP connection with public_key. + * + * return connections_number on success. + * return -1 on failure. + */ +static int find_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key) +{ + unsigned int i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + if (public_key_cmp(con_to->public_key, public_key) == 0) { + return i; + } + } + } + + return -1; +} + +/* Find the TCP connection to a relay with relay_pk. + * + * return connections_number on success. + * return -1 on failure. + */ +static int find_tcp_connection_relay(TCP_Connections *tcp_c, const uint8_t *relay_pk) +{ + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status == TCP_CONN_SLEEPING) { + if (public_key_cmp(tcp_con->relay_pk, relay_pk) == 0) { + return i; + } + } else { + if (public_key_cmp(tcp_con->connection->public_key, relay_pk) == 0) { + return i; + } + } + } + } + + return -1; +} + +/* Create a new TCP connection to public_key. + * + * public_key must be the counterpart to the secret key that the other peer used with new_tcp_connections(). + * + * id is the id in the callbacks for that connection. + * + * return connections_number on success. + * return -1 on failure. + */ +int new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id) +{ + if (find_tcp_connection_to(tcp_c, public_key) != -1) { + return -1; + } + + int connections_number = create_connection(tcp_c); + + if (connections_number == -1) { + return -1; + } + + TCP_Connection_to *con_to = &tcp_c->connections[connections_number]; + + con_to->status = TCP_CONN_VALID; + memcpy(con_to->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + con_to->id = id; + + return connections_number; +} + +/* return 0 on success. + * return -1 on failure. + */ +int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection) { + unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + continue; + } + + if (tcp_con->status == TCP_CONN_CONNECTED) { + send_disconnect_request(tcp_con->connection, con_to->connections[i].connection_id); + } + + if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) { + --tcp_con->lock_count; + + if (con_to->status == TCP_CONN_SLEEPING) { + --tcp_con->sleep_count; + } + } + } + } + + return wipe_connection(tcp_c, connections_number); +} + +/* Set connection status. + * + * status of 1 means we are using the connection. + * status of 0 means we are not using it. + * + * Unused tcp connections will be disconnected from but kept in case they are needed. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_to_status(TCP_Connections *tcp_c, int connections_number, bool status) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + if (status) { + /* Connection is unsleeping. */ + if (con_to->status != TCP_CONN_SLEEPING) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection) { + unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + continue; + } + + if (tcp_con->status == TCP_CONN_SLEEPING) { + tcp_con->unsleep = 1; + } + } + } + + con_to->status = TCP_CONN_VALID; + return 0; + } + + /* Connection is going to sleep. */ + if (con_to->status != TCP_CONN_VALID) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection) { + unsigned int tcp_connections_number = con_to->connections[i].tcp_connection - 1; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + continue; + } + + if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) { + ++tcp_con->sleep_count; + } + } + } + + con_to->status = TCP_CONN_SLEEPING; + return 0; +} + +static bool tcp_connection_in_conn(TCP_Connection_to *con_to, unsigned int tcp_connections_number) +{ + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) { + return 1; + } + } + + return 0; +} + +/* return index on success. + * return -1 on failure. + */ +static int add_tcp_connection_to_conn(TCP_Connection_to *con_to, unsigned int tcp_connections_number) +{ + unsigned int i; + + if (tcp_connection_in_conn(con_to, tcp_connections_number)) { + return -1; + } + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection == 0) { + con_to->connections[i].tcp_connection = tcp_connections_number + 1; + con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE; + con_to->connections[i].connection_id = 0; + return i; + } + } + + return -1; +} + +/* return index on success. + * return -1 on failure. + */ +static int rm_tcp_connection_from_conn(TCP_Connection_to *con_to, unsigned int tcp_connections_number) +{ + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) { + con_to->connections[i].tcp_connection = 0; + con_to->connections[i].status = TCP_CONNECTIONS_STATUS_NONE; + con_to->connections[i].connection_id = 0; + return i; + } + } + + return -1; +} + +/* return number of online connections on success. + * return -1 on failure. + */ +static unsigned int online_tcp_connection_from_conn(TCP_Connection_to *con_to) +{ + unsigned int i, count = 0; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection) { + if (con_to->connections[i].status == TCP_CONNECTIONS_STATUS_ONLINE) { + ++count; + } + } + } + + return count; +} + +/* return index on success. + * return -1 on failure. + */ +static int set_tcp_connection_status(TCP_Connection_to *con_to, unsigned int tcp_connections_number, + unsigned int status, uint8_t connection_id) +{ + unsigned int i; + + for (i = 0; i < MAX_FRIEND_TCP_CONNECTIONS; ++i) { + if (con_to->connections[i].tcp_connection == (tcp_connections_number + 1)) { + + if (con_to->connections[i].status == status) { + return -1; + } + + con_to->connections[i].status = status; + con_to->connections[i].connection_id = connection_id; + return i; + } + } + + return -1; +} + +/* Kill a TCP relay connection. + * + * return 0 on success. + * return -1 on failure. + */ +static int kill_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + unsigned int i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + rm_tcp_connection_from_conn(con_to, tcp_connections_number); + } + } + + if (tcp_con->onion) { + --tcp_c->onion_num_conns; + } + + kill_TCP_connection(tcp_con->connection); + + return wipe_tcp_connection(tcp_c, tcp_connections_number); +} + +static int reconnect_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status == TCP_CONN_SLEEPING) { + return -1; + } + + IP_Port ip_port = tcp_con->connection->ip_port; + uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE]; + memcpy(relay_pk, tcp_con->connection->public_key, CRYPTO_PUBLIC_KEY_SIZE); + kill_TCP_connection(tcp_con->connection); + tcp_con->connection = new_TCP_connection(ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, + &tcp_c->proxy_info); + + if (!tcp_con->connection) { + kill_tcp_relay_connection(tcp_c, tcp_connections_number); + return -1; + } + + unsigned int i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0); + } + } + + if (tcp_con->onion) { + --tcp_c->onion_num_conns; + tcp_con->onion = 0; + } + + tcp_con->lock_count = 0; + tcp_con->sleep_count = 0; + tcp_con->connected_time = 0; + tcp_con->status = TCP_CONN_VALID; + tcp_con->unsleep = 0; + + return 0; +} + +static int sleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status != TCP_CONN_CONNECTED) { + return -1; + } + + if (tcp_con->lock_count != tcp_con->sleep_count) { + return -1; + } + + tcp_con->ip_port = tcp_con->connection->ip_port; + memcpy(tcp_con->relay_pk, tcp_con->connection->public_key, CRYPTO_PUBLIC_KEY_SIZE); + + kill_TCP_connection(tcp_con->connection); + tcp_con->connection = NULL; + + unsigned int i; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_NONE, 0); + } + } + + if (tcp_con->onion) { + --tcp_c->onion_num_conns; + tcp_con->onion = 0; + } + + tcp_con->lock_count = 0; + tcp_con->sleep_count = 0; + tcp_con->connected_time = 0; + tcp_con->status = TCP_CONN_SLEEPING; + tcp_con->unsleep = 0; + + return 0; +} + +static int unsleep_tcp_relay_connection(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status != TCP_CONN_SLEEPING) { + return -1; + } + + tcp_con->connection = new_TCP_connection(tcp_con->ip_port, tcp_con->relay_pk, tcp_c->self_public_key, + tcp_c->self_secret_key, &tcp_c->proxy_info); + + if (!tcp_con->connection) { + kill_tcp_relay_connection(tcp_c, tcp_connections_number); + return -1; + } + + tcp_con->lock_count = 0; + tcp_con->sleep_count = 0; + tcp_con->connected_time = 0; + tcp_con->status = TCP_CONN_VALID; + tcp_con->unsleep = 0; + return 0; +} + +/* Send a TCP routing request. + * + * return 0 on success. + * return -1 on failure. + */ +static int send_tcp_relay_routing_request(TCP_Connections *tcp_c, int tcp_connections_number, uint8_t *public_key) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (tcp_con->status == TCP_CONN_SLEEPING) { + return -1; + } + + if (send_routing_request(tcp_con->connection, public_key) != 1) { + return -1; + } + + return 0; +} + +static int tcp_response_callback(void *object, uint8_t connection_id, const uint8_t *public_key) +{ + TCP_Client_Connection *TCP_client_con = (TCP_Client_Connection *)object; + TCP_Connections *tcp_c = (TCP_Connections *)TCP_client_con->custom_object; + + unsigned int tcp_connections_number = TCP_client_con->custom_uint; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + int connections_number = find_tcp_connection_to(tcp_c, public_key); + + if (connections_number == -1) { + return -1; + } + + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (con_to == NULL) { + return -1; + } + + if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1) { + return -1; + } + + set_tcp_connection_number(tcp_con->connection, connection_id, connections_number); + + return 0; +} + +static int tcp_status_callback(void *object, uint32_t number, uint8_t connection_id, uint8_t status) +{ + TCP_Client_Connection *TCP_client_con = (TCP_Client_Connection *)object; + TCP_Connections *tcp_c = (TCP_Connections *)TCP_client_con->custom_object; + + unsigned int tcp_connections_number = TCP_client_con->custom_uint; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + TCP_Connection_to *con_to = get_connection(tcp_c, number); + + if (!con_to || !tcp_con) { + return -1; + } + + if (status == 1) { + if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_REGISTERED, connection_id) == -1) { + return -1; + } + + --tcp_con->lock_count; + + if (con_to->status == TCP_CONN_SLEEPING) { + --tcp_con->sleep_count; + } + } else if (status == 2) { + if (set_tcp_connection_status(con_to, tcp_connections_number, TCP_CONNECTIONS_STATUS_ONLINE, connection_id) == -1) { + return -1; + } + + ++tcp_con->lock_count; + + if (con_to->status == TCP_CONN_SLEEPING) { + ++tcp_con->sleep_count; + } + } + + return 0; +} + +static int tcp_conn_data_callback(void *object, uint32_t number, uint8_t connection_id, const uint8_t *data, + uint16_t length, void *userdata) +{ + if (length == 0) { + return -1; + } + + TCP_Client_Connection *TCP_client_con = (TCP_Client_Connection *)object; + TCP_Connections *tcp_c = (TCP_Connections *)TCP_client_con->custom_object; + + unsigned int tcp_connections_number = TCP_client_con->custom_uint; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + TCP_Connection_to *con_to = get_connection(tcp_c, number); + + if (!con_to) { + return -1; + } + + if (tcp_c->tcp_data_callback) { + tcp_c->tcp_data_callback(tcp_c->tcp_data_callback_object, con_to->id, data, length, userdata); + } + + return 0; +} + +static int tcp_conn_oob_callback(void *object, const uint8_t *public_key, const uint8_t *data, uint16_t length, + void *userdata) +{ + if (length == 0) { + return -1; + } + + TCP_Client_Connection *TCP_client_con = (TCP_Client_Connection *)object; + TCP_Connections *tcp_c = (TCP_Connections *)TCP_client_con->custom_object; + + unsigned int tcp_connections_number = TCP_client_con->custom_uint; + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + /* TODO(irungentoo): optimize */ + int connections_number = find_tcp_connection_to(tcp_c, public_key); + + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (con_to && tcp_connection_in_conn(con_to, tcp_connections_number)) { + return tcp_conn_data_callback(object, connections_number, 0, data, length, userdata); + } + + if (tcp_c->tcp_oob_callback) { + tcp_c->tcp_oob_callback(tcp_c->tcp_oob_callback_object, public_key, tcp_connections_number, data, length, userdata); + } + + return 0; +} + +static int tcp_onion_callback(void *object, const uint8_t *data, uint16_t length, void *userdata) +{ + TCP_Connections *tcp_c = (TCP_Connections *)object; + + if (tcp_c->tcp_onion_callback) { + tcp_c->tcp_onion_callback(tcp_c->tcp_onion_callback_object, data, length, userdata); + } + + return 0; +} + +/* Set callbacks for the TCP relay connection. + * + * return 0 on success. + * return -1 on failure. + */ +static int tcp_relay_set_callbacks(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + TCP_Client_Connection *con = tcp_con->connection; + + con->custom_object = tcp_c; + con->custom_uint = tcp_connections_number; + onion_response_handler(con, &tcp_onion_callback, tcp_c); + routing_response_handler(con, &tcp_response_callback, con); + routing_status_handler(con, &tcp_status_callback, con); + routing_data_handler(con, &tcp_conn_data_callback, con); + oob_data_handler(con, &tcp_conn_oob_callback, con); + + return 0; +} + +static int tcp_relay_on_online(TCP_Connections *tcp_c, int tcp_connections_number) +{ + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + unsigned int i, sent = 0; + + for (i = 0; i < tcp_c->connections_length; ++i) { + TCP_Connection_to *con_to = get_connection(tcp_c, i); + + if (con_to) { + if (tcp_connection_in_conn(con_to, tcp_connections_number)) { + if (send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key) == 0) { + ++sent; + } + } + } + } + + tcp_relay_set_callbacks(tcp_c, tcp_connections_number); + tcp_con->status = TCP_CONN_CONNECTED; + + /* If this connection isn't used by any connection, we don't need to wait for them to come online. */ + if (sent) { + tcp_con->connected_time = unix_time(); + } else { + tcp_con->connected_time = 0; + } + + if (tcp_c->onion_status && tcp_c->onion_num_conns < NUM_ONION_TCP_CONNECTIONS) { + tcp_con->onion = 1; + ++tcp_c->onion_num_conns; + } + + return 0; +} + +static int add_tcp_relay_instance(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk) +{ + if (ip_port.ip.family == TCP_INET) { + ip_port.ip.family = TOX_AF_INET; + } else if (ip_port.ip.family == TCP_INET6) { + ip_port.ip.family = TOX_AF_INET6; + } + + if (ip_port.ip.family != TOX_AF_INET && ip_port.ip.family != TOX_AF_INET6) { + return -1; + } + + int tcp_connections_number = create_tcp_connection(tcp_c); + + if (tcp_connections_number == -1) { + return -1; + } + + TCP_con *tcp_con = &tcp_c->tcp_connections[tcp_connections_number]; + + tcp_con->connection = new_TCP_connection(ip_port, relay_pk, tcp_c->self_public_key, tcp_c->self_secret_key, + &tcp_c->proxy_info); + + if (!tcp_con->connection) { + return -1; + } + + tcp_con->status = TCP_CONN_VALID; + + return tcp_connections_number; +} + +/* Add a TCP relay to the TCP_Connections instance. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_relay_global(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk) +{ + int tcp_connections_number = find_tcp_connection_relay(tcp_c, relay_pk); + + if (tcp_connections_number != -1) { + return -1; + } + + if (add_tcp_relay_instance(tcp_c, ip_port, relay_pk) == -1) { + return -1; + } + + return 0; +} + +/* Add a TCP relay tied to a connection. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_number_relay_connection(TCP_Connections *tcp_c, int connections_number, unsigned int tcp_connections_number) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (con_to->status != TCP_CONN_SLEEPING && tcp_con->status == TCP_CONN_SLEEPING) { + tcp_con->unsleep = 1; + } + + if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1) { + return -1; + } + + if (tcp_con->status == TCP_CONN_CONNECTED) { + if (send_tcp_relay_routing_request(tcp_c, tcp_connections_number, con_to->public_key) == 0) { + tcp_con->connected_time = unix_time(); + } + } + + return 0; +} + +/* Add a TCP relay tied to a connection. + * + * This should be called with the same relay by two peers who want to create a TCP connection with each other. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, IP_Port ip_port, const uint8_t *relay_pk) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return -1; + } + + int tcp_connections_number = find_tcp_connection_relay(tcp_c, relay_pk); + + if (tcp_connections_number != -1) { + return add_tcp_number_relay_connection(tcp_c, connections_number, tcp_connections_number); + } + + if (online_tcp_connection_from_conn(con_to) >= RECOMMENDED_FRIEND_TCP_CONNECTIONS) { + return -1; + } + + tcp_connections_number = add_tcp_relay_instance(tcp_c, ip_port, relay_pk); + + TCP_con *tcp_con = get_tcp_connection(tcp_c, tcp_connections_number); + + if (!tcp_con) { + return -1; + } + + if (add_tcp_connection_to_conn(con_to, tcp_connections_number) == -1) { + return -1; + } + + return 0; +} + +/* return number of online tcp relays tied to the connection on success. + * return 0 on failure. + */ +unsigned int tcp_connection_to_online_tcp_relays(TCP_Connections *tcp_c, int connections_number) +{ + TCP_Connection_to *con_to = get_connection(tcp_c, connections_number); + + if (!con_to) { + return 0; + } + + return online_tcp_connection_from_conn(con_to); +} + +/* Copy a maximum of max_num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. + * + * return number of relays copied to tcp_relays on success. + * return 0 on failure. + */ +unsigned int tcp_copy_connected_relays(TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num) +{ + unsigned int i, copied = 0, r = rand(); + + for (i = 0; (i < tcp_c->tcp_connections_length) && (copied < max_num); ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, (i + r) % tcp_c->tcp_connections_length); + + if (!tcp_con) { + continue; + } + + if (tcp_con->status == TCP_CONN_CONNECTED) { + memcpy(tcp_relays[copied].public_key, tcp_con->connection->public_key, CRYPTO_PUBLIC_KEY_SIZE); + tcp_relays[copied].ip_port = tcp_con->connection->ip_port; + + if (tcp_relays[copied].ip_port.ip.family == TOX_AF_INET) { + tcp_relays[copied].ip_port.ip.family = TCP_INET; + } else if (tcp_relays[copied].ip_port.ip.family == TOX_AF_INET6) { + tcp_relays[copied].ip_port.ip.family = TCP_INET6; + } + + ++copied; + } + } + + return copied; +} + +/* Set if we want TCP_connection to allocate some connection for onion use. + * + * If status is 1, allocate some connections. if status is 0, don't. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_onion_status(TCP_Connections *tcp_c, bool status) +{ + if (tcp_c->onion_status == status) { + return -1; + } + + if (status) { + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status == TCP_CONN_CONNECTED && !tcp_con->onion) { + ++tcp_c->onion_num_conns; + tcp_con->onion = 1; + } + } + + if (tcp_c->onion_num_conns >= NUM_ONION_TCP_CONNECTIONS) { + break; + } + } + + if (tcp_c->onion_num_conns < NUM_ONION_TCP_CONNECTIONS) { + unsigned int wakeup = NUM_ONION_TCP_CONNECTIONS - tcp_c->onion_num_conns; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status == TCP_CONN_SLEEPING) { + tcp_con->unsleep = 1; + } + } + + if (!wakeup) { + break; + } + } + } + + tcp_c->onion_status = 1; + } else { + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->onion) { + --tcp_c->onion_num_conns; + tcp_con->onion = 0; + } + } + } + + tcp_c->onion_status = 0; + } + + return 0; +} + +/* Returns a new TCP_Connections object associated with the secret_key. + * + * In order for others to connect to this instance new_tcp_connection_to() must be called with the + * public_key associated with secret_key. + * + * Returns NULL on failure. + */ +TCP_Connections *new_tcp_connections(const uint8_t *secret_key, TCP_Proxy_Info *proxy_info) +{ + if (secret_key == NULL) { + return NULL; + } + + TCP_Connections *temp = (TCP_Connections *)calloc(1, sizeof(TCP_Connections)); + + if (temp == NULL) { + return NULL; + } + + memcpy(temp->self_secret_key, secret_key, CRYPTO_SECRET_KEY_SIZE); + crypto_derive_public_key(temp->self_public_key, temp->self_secret_key); + temp->proxy_info = *proxy_info; + + return temp; +} + +static void do_tcp_conns(TCP_Connections *tcp_c, void *userdata) +{ + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status != TCP_CONN_SLEEPING) { + do_TCP_connection(tcp_con->connection, userdata); + + /* callbacks can change TCP connection address. */ + tcp_con = get_tcp_connection(tcp_c, i); + + // Make sure the TCP connection wasn't dropped in any of the callbacks. + assert(tcp_con != NULL); + + if (tcp_con->connection->status == TCP_CLIENT_DISCONNECTED) { + if (tcp_con->status == TCP_CONN_CONNECTED) { + reconnect_tcp_relay_connection(tcp_c, i); + } else { + kill_tcp_relay_connection(tcp_c, i); + } + + continue; + } + + if (tcp_con->status == TCP_CONN_VALID && tcp_con->connection->status == TCP_CLIENT_CONFIRMED) { + tcp_relay_on_online(tcp_c, i); + } + + if (tcp_con->status == TCP_CONN_CONNECTED && !tcp_con->onion && tcp_con->lock_count + && tcp_con->lock_count == tcp_con->sleep_count + && is_timeout(tcp_con->connected_time, TCP_CONNECTION_ANNOUNCE_TIMEOUT)) { + sleep_tcp_relay_connection(tcp_c, i); + } + } + + if (tcp_con->status == TCP_CONN_SLEEPING && tcp_con->unsleep) { + unsleep_tcp_relay_connection(tcp_c, i); + } + } + } +} + +static void kill_nonused_tcp(TCP_Connections *tcp_c) +{ + if (tcp_c->tcp_connections_length == 0) { + return; + } + + unsigned int i; + unsigned int num_online = 0; + unsigned int num_kill = 0; + VLA(unsigned int, to_kill, tcp_c->tcp_connections_length); + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + TCP_con *tcp_con = get_tcp_connection(tcp_c, i); + + if (tcp_con) { + if (tcp_con->status == TCP_CONN_CONNECTED) { + if (!tcp_con->onion && !tcp_con->lock_count && is_timeout(tcp_con->connected_time, TCP_CONNECTION_ANNOUNCE_TIMEOUT)) { + to_kill[num_kill] = i; + ++num_kill; + } + + ++num_online; + } + } + } + + if (num_online <= RECOMMENDED_FRIEND_TCP_CONNECTIONS) { + return; + } + + unsigned int n = num_online - RECOMMENDED_FRIEND_TCP_CONNECTIONS; + + if (n < num_kill) { + num_kill = n; + } + + for (i = 0; i < num_kill; ++i) { + kill_tcp_relay_connection(tcp_c, to_kill[i]); + } +} + +void do_tcp_connections(TCP_Connections *tcp_c, void *userdata) +{ + do_tcp_conns(tcp_c, userdata); + kill_nonused_tcp(tcp_c); +} + +void kill_tcp_connections(TCP_Connections *tcp_c) +{ + unsigned int i; + + for (i = 0; i < tcp_c->tcp_connections_length; ++i) { + kill_TCP_connection(tcp_c->tcp_connections[i].connection); + } + + free(tcp_c->tcp_connections); + free(tcp_c->connections); + free(tcp_c); +} diff --git a/libs/libtox/src/toxcore/TCP_connection.h b/libs/libtox/src/toxcore/TCP_connection.h new file mode 100644 index 0000000000..a45129a7e8 --- /dev/null +++ b/libs/libtox/src/toxcore/TCP_connection.h @@ -0,0 +1,223 @@ +/* + * Handles TCP relay connections between two Tox clients. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2015 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef TCP_CONNECTION_H +#define TCP_CONNECTION_H + +#include "TCP_client.h" + +#define TCP_CONN_NONE 0 +#define TCP_CONN_VALID 1 + +/* NOTE: only used by TCP_con */ +#define TCP_CONN_CONNECTED 2 + +/* Connection is not connected but can be quickly reconnected in case it is needed. */ +#define TCP_CONN_SLEEPING 3 + +#define TCP_CONNECTIONS_STATUS_NONE 0 +#define TCP_CONNECTIONS_STATUS_REGISTERED 1 +#define TCP_CONNECTIONS_STATUS_ONLINE 2 + +#define MAX_FRIEND_TCP_CONNECTIONS 6 + +/* Time until connection to friend gets killed (if it doesn't get locked within that time) */ +#define TCP_CONNECTION_ANNOUNCE_TIMEOUT (TCP_CONNECTION_TIMEOUT) + +/* The amount of recommended connections for each friend + NOTE: Must be at most (MAX_FRIEND_TCP_CONNECTIONS / 2) */ +#define RECOMMENDED_FRIEND_TCP_CONNECTIONS (MAX_FRIEND_TCP_CONNECTIONS / 2) + +/* Number of TCP connections used for onion purposes. */ +#define NUM_ONION_TCP_CONNECTIONS RECOMMENDED_FRIEND_TCP_CONNECTIONS + +typedef struct { + uint8_t status; + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer */ + + struct { + uint32_t tcp_connection; + unsigned int status; + unsigned int connection_id; + } connections[MAX_FRIEND_TCP_CONNECTIONS]; + + int id; /* id used in callbacks. */ +} TCP_Connection_to; + +typedef struct { + uint8_t status; + TCP_Client_Connection *connection; + uint64_t connected_time; + uint32_t lock_count; + uint32_t sleep_count; + bool onion; + + /* Only used when connection is sleeping. */ + IP_Port ip_port; + uint8_t relay_pk[CRYPTO_PUBLIC_KEY_SIZE]; + bool unsleep; /* set to 1 to unsleep connection. */ +} TCP_con; + +typedef struct TCP_Connections TCP_Connections; + +const uint8_t *tcp_connections_public_key(const TCP_Connections *tcp_c); + +/* Send a packet to the TCP connection. + * + * return -1 on failure. + * return 0 on success. + */ +int send_packet_tcp_connection(TCP_Connections *tcp_c, int connections_number, const uint8_t *packet, uint16_t length); + +/* Return a random TCP connection number for use in send_tcp_onion_request. + * + * TODO(irungentoo): This number is just the index of an array that the elements + * can change without warning. + * + * return TCP connection number on success. + * return -1 on failure. + */ +int get_random_tcp_onion_conn_number(TCP_Connections *tcp_c); + +/* Send an onion packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int tcp_send_onion_request(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *data, + uint16_t length); + +/* Set if we want TCP_connection to allocate some connection for onion use. + * + * If status is 1, allocate some connections. if status is 0, don't. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_onion_status(TCP_Connections *tcp_c, bool status); + +/* Send an oob packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int tcp_send_oob_packet(TCP_Connections *tcp_c, unsigned int tcp_connections_number, const uint8_t *public_key, + const uint8_t *packet, uint16_t length); + +/* Set the callback for TCP data packets. + */ +void set_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_data_callback)(void *object, int id, + const uint8_t *data, uint16_t length, void *userdata), void *object); + +/* Set the callback for TCP onion packets. + */ +void set_onion_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_onion_callback)(void *object, + const uint8_t *data, uint16_t length, void *userdata), void *object); + +/* Set the callback for TCP oob data packets. + */ +void set_oob_packet_tcp_connection_callback(TCP_Connections *tcp_c, int (*tcp_oob_callback)(void *object, + const uint8_t *public_key, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length, void *userdata), + void *object); + +/* Create a new TCP connection to public_key. + * + * public_key must be the counterpart to the secret key that the other peer used with new_tcp_connections(). + * + * id is the id in the callbacks for that connection. + * + * return connections_number on success. + * return -1 on failure. + */ +int new_tcp_connection_to(TCP_Connections *tcp_c, const uint8_t *public_key, int id); + +/* return 0 on success. + * return -1 on failure. + */ +int kill_tcp_connection_to(TCP_Connections *tcp_c, int connections_number); + +/* Set connection status. + * + * status of 1 means we are using the connection. + * status of 0 means we are not using it. + * + * Unused tcp connections will be disconnected from but kept in case they are needed. + * + * return 0 on success. + * return -1 on failure. + */ +int set_tcp_connection_to_status(TCP_Connections *tcp_c, int connections_number, bool status); + +/* return number of online tcp relays tied to the connection on success. + * return 0 on failure. + */ +unsigned int tcp_connection_to_online_tcp_relays(TCP_Connections *tcp_c, int connections_number); + +/* Add a TCP relay tied to a connection. + * + * NOTE: This can only be used during the tcp_oob_callback. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_number_relay_connection(TCP_Connections *tcp_c, int connections_number, + unsigned int tcp_connections_number); + +/* Add a TCP relay tied to a connection. + * + * This should be called with the same relay by two peers who want to create a TCP connection with each other. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_relay_connection(TCP_Connections *tcp_c, int connections_number, IP_Port ip_port, const uint8_t *relay_pk); + +/* Add a TCP relay to the instance. + * + * return 0 on success. + * return -1 on failure. + */ +int add_tcp_relay_global(TCP_Connections *tcp_c, IP_Port ip_port, const uint8_t *relay_pk); + +/* Copy a maximum of max_num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. + * + * return number of relays copied to tcp_relays on success. + * return 0 on failure. + */ +unsigned int tcp_copy_connected_relays(TCP_Connections *tcp_c, Node_format *tcp_relays, uint16_t max_num); + +/* Returns a new TCP_Connections object associated with the secret_key. + * + * In order for others to connect to this instance new_tcp_connection_to() must be called with the + * public_key associated with secret_key. + * + * Returns NULL on failure. + */ +TCP_Connections *new_tcp_connections(const uint8_t *secret_key, TCP_Proxy_Info *proxy_info); + +void do_tcp_connections(TCP_Connections *tcp_c, void *userdata); +void kill_tcp_connections(TCP_Connections *tcp_c); + +#endif + diff --git a/libs/libtox/src/toxcore/TCP_server.c b/libs/libtox/src/toxcore/TCP_server.c new file mode 100644 index 0000000000..9b94667aa1 --- /dev/null +++ b/libs/libtox/src/toxcore/TCP_server.c @@ -0,0 +1,1417 @@ +/* + * Implementation of the TCP relay server part of Tox. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "TCP_server.h" + +#include "util.h" + +#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) +#include +#endif + +struct TCP_Server { + Onion *onion; + +#ifdef TCP_SERVER_USE_EPOLL + int efd; + uint64_t last_run_pinged; +#endif + Socket *socks_listening; + unsigned int num_listening_socks; + + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t secret_key[CRYPTO_SECRET_KEY_SIZE]; + TCP_Secure_Connection incoming_connection_queue[MAX_INCOMING_CONNECTIONS]; + uint16_t incoming_connection_queue_index; + TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMING_CONNECTIONS]; + uint16_t unconfirmed_connection_queue_index; + + TCP_Secure_Connection *accepted_connection_array; + uint32_t size_accepted_connections; + uint32_t num_accepted_connections; + + uint64_t counter; + + BS_LIST accepted_key_list; +}; + +const uint8_t *tcp_server_public_key(const TCP_Server *tcp_server) +{ + return tcp_server->public_key; +} + +size_t tcp_server_listen_count(const TCP_Server *tcp_server) +{ + return tcp_server->num_listening_socks; +} + +/* This is needed to compile on Android below API 21 + */ +#ifndef EPOLLRDHUP +#define EPOLLRDHUP 0x2000 +#endif + +/* Set the size of the connection list to numfriends. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_connection(TCP_Server *TCP_server, uint32_t num) +{ + if (num == 0) { + free(TCP_server->accepted_connection_array); + TCP_server->accepted_connection_array = NULL; + TCP_server->size_accepted_connections = 0; + return 0; + } + + if (num == TCP_server->size_accepted_connections) { + return 0; + } + + TCP_Secure_Connection *new_connections = (TCP_Secure_Connection *)realloc( + TCP_server->accepted_connection_array, + num * sizeof(TCP_Secure_Connection)); + + if (new_connections == NULL) { + return -1; + } + + if (num > TCP_server->size_accepted_connections) { + uint32_t old_size = TCP_server->size_accepted_connections; + uint32_t size_new_entries = (num - old_size) * sizeof(TCP_Secure_Connection); + memset(new_connections + old_size, 0, size_new_entries); + } + + TCP_server->accepted_connection_array = new_connections; + TCP_server->size_accepted_connections = num; + return 0; +} + +/* return index corresponding to connection with peer on success + * return -1 on failure. + */ +static int get_TCP_connection_index(const TCP_Server *TCP_server, const uint8_t *public_key) +{ + return bs_list_find(&TCP_server->accepted_key_list, public_key); +} + + +static int kill_accepted(TCP_Server *TCP_server, int index); + +/* Add accepted TCP connection to the list. + * + * return index on success + * return -1 on failure + */ +static int add_accepted(TCP_Server *TCP_server, const TCP_Secure_Connection *con) +{ + int index = get_TCP_connection_index(TCP_server, con->public_key); + + if (index != -1) { /* If an old connection to the same public key exists, kill it. */ + kill_accepted(TCP_server, index); + index = -1; + } + + if (TCP_server->size_accepted_connections == TCP_server->num_accepted_connections) { + if (realloc_connection(TCP_server, TCP_server->size_accepted_connections + 4) == -1) { + return -1; + } + + index = TCP_server->num_accepted_connections; + } else { + uint32_t i; + + for (i = TCP_server->size_accepted_connections; i != 0; --i) { + if (TCP_server->accepted_connection_array[i - 1].status == TCP_STATUS_NO_STATUS) { + index = i - 1; + break; + } + } + } + + if (index == -1) { + fprintf(stderr, "FAIL index is -1\n"); + return -1; + } + + if (!bs_list_add(&TCP_server->accepted_key_list, con->public_key, index)) { + return -1; + } + + memcpy(&TCP_server->accepted_connection_array[index], con, sizeof(TCP_Secure_Connection)); + TCP_server->accepted_connection_array[index].status = TCP_STATUS_CONFIRMED; + ++TCP_server->num_accepted_connections; + TCP_server->accepted_connection_array[index].identifier = ++TCP_server->counter; + TCP_server->accepted_connection_array[index].last_pinged = unix_time(); + TCP_server->accepted_connection_array[index].ping_id = 0; + + return index; +} + +/* Delete accepted connection from list. + * + * return 0 on success + * return -1 on failure + */ +static int del_accepted(TCP_Server *TCP_server, int index) +{ + if ((uint32_t)index >= TCP_server->size_accepted_connections) { + return -1; + } + + if (TCP_server->accepted_connection_array[index].status == TCP_STATUS_NO_STATUS) { + return -1; + } + + if (!bs_list_remove(&TCP_server->accepted_key_list, TCP_server->accepted_connection_array[index].public_key, index)) { + return -1; + } + + crypto_memzero(&TCP_server->accepted_connection_array[index], sizeof(TCP_Secure_Connection)); + --TCP_server->num_accepted_connections; + + if (TCP_server->num_accepted_connections == 0) { + realloc_connection(TCP_server, 0); + } + + return 0; +} + +/* return the amount of data in the tcp recv buffer. + * return 0 on failure. + */ +unsigned int TCP_socket_data_recv_buffer(Socket sock) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + unsigned long count = 0; + ioctlsocket(sock, FIONREAD, &count); +#else + int count = 0; + ioctl(sock, FIONREAD, &count); +#endif + + return count; +} + +/* Read the next two bytes in TCP stream then convert them to + * length (host byte order). + * + * return length on success + * return 0 if nothing has been read from socket. + * return ~0 on failure. + */ +uint16_t read_TCP_length(Socket sock) +{ + unsigned int count = TCP_socket_data_recv_buffer(sock); + + if (count >= sizeof(uint16_t)) { + uint16_t length; + int len = recv(sock, (char *)&length, sizeof(uint16_t), MSG_NOSIGNAL); + + if (len != sizeof(uint16_t)) { + fprintf(stderr, "FAIL recv packet\n"); + return 0; + } + + length = net_ntohs(length); + + if (length > MAX_PACKET_SIZE) { + return ~0; + } + + return length; + } + + return 0; +} + +/* Read length bytes from socket. + * + * return length on success + * return -1 on failure/no data in buffer. + */ +int read_TCP_packet(Socket sock, uint8_t *data, uint16_t length) +{ + unsigned int count = TCP_socket_data_recv_buffer(sock); + + if (count >= length) { + int len = recv(sock, (char *)data, length, MSG_NOSIGNAL); + + if (len != length) { + fprintf(stderr, "FAIL recv packet\n"); + return -1; + } + + return len; + } + + return -1; +} + +/* return length of received packet on success. + * return 0 if could not read any packet. + * return -1 on failure (connection must be killed). + */ +int read_packet_TCP_secure_connection(Socket sock, uint16_t *next_packet_length, const uint8_t *shared_key, + uint8_t *recv_nonce, uint8_t *data, uint16_t max_len) +{ + if (*next_packet_length == 0) { + uint16_t len = read_TCP_length(sock); + + if (len == (uint16_t)~0) { + return -1; + } + + if (len == 0) { + return 0; + } + + *next_packet_length = len; + } + + if (max_len + CRYPTO_MAC_SIZE < *next_packet_length) { + return -1; + } + + VLA(uint8_t, data_encrypted, *next_packet_length); + int len_packet = read_TCP_packet(sock, data_encrypted, *next_packet_length); + + if (len_packet != *next_packet_length) { + return 0; + } + + *next_packet_length = 0; + + int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data); + + if (len + CRYPTO_MAC_SIZE != len_packet) { + return -1; + } + + increment_nonce(recv_nonce); + + return len; +} + +/* return 0 if pending data was sent completely + * return -1 if it wasn't + */ +static int send_pending_data_nonpriority(TCP_Secure_Connection *con) +{ + if (con->last_packet_length == 0) { + return 0; + } + + uint16_t left = con->last_packet_length - con->last_packet_sent; + int len = send(con->sock, (const char *)(con->last_packet + con->last_packet_sent), left, MSG_NOSIGNAL); + + if (len <= 0) { + return -1; + } + + if (len == left) { + con->last_packet_length = 0; + con->last_packet_sent = 0; + return 0; + } + + con->last_packet_sent += len; + return -1; +} + +/* return 0 if pending data was sent completely + * return -1 if it wasn't + */ +static int send_pending_data(TCP_Secure_Connection *con) +{ + /* finish sending current non-priority packet */ + if (send_pending_data_nonpriority(con) == -1) { + return -1; + } + + TCP_Priority_List *p = con->priority_queue_start; + + while (p) { + uint16_t left = p->size - p->sent; + int len = send(con->sock, (const char *)(p->data + p->sent), left, MSG_NOSIGNAL); + + if (len != left) { + if (len > 0) { + p->sent += len; + } + + break; + } + + TCP_Priority_List *pp = p; + p = p->next; + free(pp); + } + + con->priority_queue_start = p; + + if (!p) { + con->priority_queue_end = NULL; + return 0; + } + + return -1; +} + +/* return 0 on failure (only if malloc fails) + * return 1 on success + */ +static bool add_priority(TCP_Secure_Connection *con, const uint8_t *packet, uint16_t size, uint16_t sent) +{ + TCP_Priority_List *p = con->priority_queue_end; + TCP_Priority_List *new_list = (TCP_Priority_List *)malloc(sizeof(TCP_Priority_List) + size); + + if (!new_list) { + return 0; + } + + new_list->next = NULL; + new_list->size = size; + new_list->sent = sent; + memcpy(new_list->data, packet, size); + + if (p) { + p->next = new_list; + } else { + con->priority_queue_start = new_list; + } + + con->priority_queue_end = new_list; + return 1; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int write_packet_TCP_secure_connection(TCP_Secure_Connection *con, const uint8_t *data, uint16_t length, + bool priority) +{ + if (length + CRYPTO_MAC_SIZE > MAX_PACKET_SIZE) { + return -1; + } + + bool sendpriority = 1; + + if (send_pending_data(con) == -1) { + if (priority) { + sendpriority = 0; + } else { + return 0; + } + } + + VLA(uint8_t, packet, sizeof(uint16_t) + length + CRYPTO_MAC_SIZE); + + uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE); + memcpy(packet, &c_length, sizeof(uint16_t)); + int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t)); + + if ((unsigned int)len != (SIZEOF_VLA(packet) - sizeof(uint16_t))) { + return -1; + } + + if (priority) { + len = sendpriority ? send(con->sock, (const char *)packet, SIZEOF_VLA(packet), MSG_NOSIGNAL) : 0; + + if (len <= 0) { + len = 0; + } + + increment_nonce(con->sent_nonce); + + if ((unsigned int)len == SIZEOF_VLA(packet)) { + return 1; + } + + return add_priority(con, packet, SIZEOF_VLA(packet), len); + } + + len = send(con->sock, (const char *)packet, SIZEOF_VLA(packet), MSG_NOSIGNAL); + + if (len <= 0) { + return 0; + } + + increment_nonce(con->sent_nonce); + + if ((unsigned int)len == SIZEOF_VLA(packet)) { + return 1; + } + + memcpy(con->last_packet, packet, SIZEOF_VLA(packet)); + con->last_packet_length = SIZEOF_VLA(packet); + con->last_packet_sent = len; + return 1; +} + +/* Kill a TCP_Secure_Connection + */ +static void kill_TCP_secure_connection(TCP_Secure_Connection *con) +{ + kill_sock(con->sock); + crypto_memzero(con, sizeof(TCP_Secure_Connection)); +} + +static int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number); + +/* Kill an accepted TCP_Secure_Connection + * + * return -1 on failure. + * return 0 on success. + */ +static int kill_accepted(TCP_Server *TCP_server, int index) +{ + if ((uint32_t)index >= TCP_server->size_accepted_connections) { + return -1; + } + + uint32_t i; + + for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { + rm_connection_index(TCP_server, &TCP_server->accepted_connection_array[index], i); + } + + Socket sock = TCP_server->accepted_connection_array[index].sock; + + if (del_accepted(TCP_server, index) != 0) { + return -1; + } + + kill_sock(sock); + return 0; +} + +/* return 1 if everything went well. + * return -1 if the connection must be killed. + */ +static int handle_TCP_handshake(TCP_Secure_Connection *con, const uint8_t *data, uint16_t length, + const uint8_t *self_secret_key) +{ + if (length != TCP_CLIENT_HANDSHAKE_SIZE) { + return -1; + } + + if (con->status != TCP_STATUS_CONNECTED) { + return -1; + } + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + encrypt_precompute(data, self_secret_key, shared_key); + uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE]; + int len = decrypt_data_symmetric(shared_key, data + CRYPTO_PUBLIC_KEY_SIZE, + data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE, plain); + + if (len != TCP_HANDSHAKE_PLAIN_SIZE) { + return -1; + } + + memcpy(con->public_key, data, CRYPTO_PUBLIC_KEY_SIZE); + uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; + uint8_t resp_plain[TCP_HANDSHAKE_PLAIN_SIZE]; + crypto_new_keypair(resp_plain, temp_secret_key); + random_nonce(con->sent_nonce); + memcpy(resp_plain + CRYPTO_PUBLIC_KEY_SIZE, con->sent_nonce, CRYPTO_NONCE_SIZE); + memcpy(con->recv_nonce, plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE); + + uint8_t response[TCP_SERVER_HANDSHAKE_SIZE]; + random_nonce(response); + + len = encrypt_data_symmetric(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, + response + CRYPTO_NONCE_SIZE); + + if (len != TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE) { + return -1; + } + + if (TCP_SERVER_HANDSHAKE_SIZE != send(con->sock, (const char *)response, TCP_SERVER_HANDSHAKE_SIZE, MSG_NOSIGNAL)) { + return -1; + } + + encrypt_precompute(plain, temp_secret_key, con->shared_key); + con->status = TCP_STATUS_UNCONFIRMED; + return 1; +} + +/* return 1 if connection handshake was handled correctly. + * return 0 if we didn't get it yet. + * return -1 if the connection must be killed. + */ +static int read_connection_handshake(TCP_Secure_Connection *con, const uint8_t *self_secret_key) +{ + uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE]; + int len = 0; + + if ((len = read_TCP_packet(con->sock, data, TCP_CLIENT_HANDSHAKE_SIZE)) != -1) { + return handle_TCP_handshake(con, data, len, self_secret_key); + } + + return 0; +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int send_routing_response(TCP_Secure_Connection *con, uint8_t rpid, const uint8_t *public_key) +{ + uint8_t data[1 + 1 + CRYPTO_PUBLIC_KEY_SIZE]; + data[0] = TCP_PACKET_ROUTING_RESPONSE; + data[1] = rpid; + memcpy(data + 2, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + return write_packet_TCP_secure_connection(con, data, sizeof(data), 1); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int send_connect_notification(TCP_Secure_Connection *con, uint8_t id) +{ + uint8_t data[2] = {TCP_PACKET_CONNECTION_NOTIFICATION, (uint8_t)(id + NUM_RESERVED_PORTS)}; + return write_packet_TCP_secure_connection(con, data, sizeof(data), 1); +} + +/* return 1 on success. + * return 0 if could not send packet. + * return -1 on failure (connection must be killed). + */ +static int send_disconnect_notification(TCP_Secure_Connection *con, uint8_t id) +{ + uint8_t data[2] = {TCP_PACKET_DISCONNECT_NOTIFICATION, (uint8_t)(id + NUM_RESERVED_PORTS)}; + return write_packet_TCP_secure_connection(con, data, sizeof(data), 1); +} + +/* return 0 on success. + * return -1 on failure (connection must be killed). + */ +static int handle_TCP_routing_req(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *public_key) +{ + uint32_t i; + uint32_t index = ~0; + TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; + + /* If person tries to cennect to himself we deny the request*/ + if (public_key_cmp(con->public_key, public_key) == 0) { + if (send_routing_response(con, 0, public_key) == -1) { + return -1; + } + + return 0; + } + + for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { + if (con->connections[i].status != 0) { + if (public_key_cmp(public_key, con->connections[i].public_key) == 0) { + if (send_routing_response(con, i + NUM_RESERVED_PORTS, public_key) == -1) { + return -1; + } + + return 0; + } + } else if (index == (uint32_t)~0) { + index = i; + } + } + + if (index == (uint32_t)~0) { + if (send_routing_response(con, 0, public_key) == -1) { + return -1; + } + + return 0; + } + + int ret = send_routing_response(con, index + NUM_RESERVED_PORTS, public_key); + + if (ret == 0) { + return 0; + } + + if (ret == -1) { + return -1; + } + + con->connections[index].status = 1; + memcpy(con->connections[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + int other_index = get_TCP_connection_index(TCP_server, public_key); + + if (other_index != -1) { + uint32_t other_id = ~0; + TCP_Secure_Connection *other_conn = &TCP_server->accepted_connection_array[other_index]; + + for (i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { + if (other_conn->connections[i].status == 1 + && public_key_cmp(other_conn->connections[i].public_key, con->public_key) == 0) { + other_id = i; + break; + } + } + + if (other_id != (uint32_t)~0) { + con->connections[index].status = 2; + con->connections[index].index = other_index; + con->connections[index].other_id = other_id; + other_conn->connections[other_id].status = 2; + other_conn->connections[other_id].index = con_id; + other_conn->connections[other_id].other_id = index; + // TODO(irungentoo): return values? + send_connect_notification(con, index); + send_connect_notification(other_conn, other_id); + } + } + + return 0; +} + +/* return 0 on success. + * return -1 on failure (connection must be killed). + */ +static int handle_TCP_oob_send(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *public_key, const uint8_t *data, + uint16_t length) +{ + if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) { + return -1; + } + + TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; + + int other_index = get_TCP_connection_index(TCP_server, public_key); + + if (other_index != -1) { + VLA(uint8_t, resp_packet, 1 + CRYPTO_PUBLIC_KEY_SIZE + length); + resp_packet[0] = TCP_PACKET_OOB_RECV; + memcpy(resp_packet + 1, con->public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(resp_packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length); + write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[other_index], resp_packet, + SIZEOF_VLA(resp_packet), 0); + } + + return 0; +} + +/* Remove connection with con_number from the connections array of con. + * + * return -1 on failure. + * return 0 on success. + */ +static int rm_connection_index(TCP_Server *TCP_server, TCP_Secure_Connection *con, uint8_t con_number) +{ + if (con_number >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + if (con->connections[con_number].status) { + uint32_t index = con->connections[con_number].index; + uint8_t other_id = con->connections[con_number].other_id; + + if (con->connections[con_number].status == 2) { + + if (index >= TCP_server->size_accepted_connections) { + return -1; + } + + TCP_server->accepted_connection_array[index].connections[other_id].other_id = 0; + TCP_server->accepted_connection_array[index].connections[other_id].index = 0; + TCP_server->accepted_connection_array[index].connections[other_id].status = 1; + // TODO(irungentoo): return values? + send_disconnect_notification(&TCP_server->accepted_connection_array[index], other_id); + } + + con->connections[con_number].index = 0; + con->connections[con_number].other_id = 0; + con->connections[con_number].status = 0; + return 0; + } + + return -1; +} + +static int handle_onion_recv_1(void *object, IP_Port dest, const uint8_t *data, uint16_t length) +{ + TCP_Server *TCP_server = (TCP_Server *)object; + uint32_t index = dest.ip.ip6.uint32[0]; + + if (index >= TCP_server->size_accepted_connections) { + return 1; + } + + TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[index]; + + if (con->identifier != dest.ip.ip6.uint64[1]) { + return 1; + } + + VLA(uint8_t, packet, 1 + length); + memcpy(packet + 1, data, length); + packet[0] = TCP_PACKET_ONION_RESPONSE; + + if (write_packet_TCP_secure_connection(con, packet, SIZEOF_VLA(packet), 0) != 1) { + return 1; + } + + return 0; +} + +/* return 0 on success + * return -1 on failure + */ +static int handle_TCP_packet(TCP_Server *TCP_server, uint32_t con_id, const uint8_t *data, uint16_t length) +{ + if (length == 0) { + return -1; + } + + TCP_Secure_Connection *con = &TCP_server->accepted_connection_array[con_id]; + + switch (data[0]) { + case TCP_PACKET_ROUTING_REQUEST: { + if (length != 1 + CRYPTO_PUBLIC_KEY_SIZE) { + return -1; + } + + return handle_TCP_routing_req(TCP_server, con_id, data + 1); + } + + case TCP_PACKET_CONNECTION_NOTIFICATION: { + if (length != 2) { + return -1; + } + + break; + } + + case TCP_PACKET_DISCONNECT_NOTIFICATION: { + if (length != 2) { + return -1; + } + + return rm_connection_index(TCP_server, con, data[1] - NUM_RESERVED_PORTS); + } + + case TCP_PACKET_PING: { + if (length != 1 + sizeof(uint64_t)) { + return -1; + } + + uint8_t response[1 + sizeof(uint64_t)]; + response[0] = TCP_PACKET_PONG; + memcpy(response + 1, data + 1, sizeof(uint64_t)); + write_packet_TCP_secure_connection(con, response, sizeof(response), 1); + return 0; + } + + case TCP_PACKET_PONG: { + if (length != 1 + sizeof(uint64_t)) { + return -1; + } + + uint64_t ping_id; + memcpy(&ping_id, data + 1, sizeof(uint64_t)); + + if (ping_id) { + if (ping_id == con->ping_id) { + con->ping_id = 0; + } + + return 0; + } + + return -1; + } + + case TCP_PACKET_OOB_SEND: { + if (length <= 1 + CRYPTO_PUBLIC_KEY_SIZE) { + return -1; + } + + return handle_TCP_oob_send(TCP_server, con_id, data + 1, data + 1 + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_PUBLIC_KEY_SIZE)); + } + + case TCP_PACKET_ONION_REQUEST: { + if (TCP_server->onion) { + if (length <= 1 + CRYPTO_NONCE_SIZE + ONION_SEND_BASE * 2) { + return -1; + } + + IP_Port source; + source.port = 0; // dummy initialise + source.ip.family = TCP_ONION_FAMILY; + source.ip.ip6.uint32[0] = con_id; + source.ip.ip6.uint32[1] = 0; + source.ip.ip6.uint64[1] = con->identifier; + onion_send_1(TCP_server->onion, data + 1 + CRYPTO_NONCE_SIZE, length - (1 + CRYPTO_NONCE_SIZE), source, + data + 1); + } + + return 0; + } + + case TCP_PACKET_ONION_RESPONSE: { + return -1; + } + + default: { + if (data[0] < NUM_RESERVED_PORTS) { + return -1; + } + + uint8_t c_id = data[0] - NUM_RESERVED_PORTS; + + if (c_id >= NUM_CLIENT_CONNECTIONS) { + return -1; + } + + if (con->connections[c_id].status == 0) { + return -1; + } + + if (con->connections[c_id].status != 2) { + return 0; + } + + uint32_t index = con->connections[c_id].index; + uint8_t other_c_id = con->connections[c_id].other_id + NUM_RESERVED_PORTS; + VLA(uint8_t, new_data, length); + memcpy(new_data, data, length); + new_data[0] = other_c_id; + int ret = write_packet_TCP_secure_connection(&TCP_server->accepted_connection_array[index], new_data, length, 0); + + if (ret == -1) { + return -1; + } + + return 0; + } + } + + return 0; +} + + +static int confirm_TCP_connection(TCP_Server *TCP_server, TCP_Secure_Connection *con, const uint8_t *data, + uint16_t length) +{ + int index = add_accepted(TCP_server, con); + + if (index == -1) { + kill_TCP_secure_connection(con); + return -1; + } + + crypto_memzero(con, sizeof(TCP_Secure_Connection)); + + if (handle_TCP_packet(TCP_server, index, data, length) == -1) { + kill_accepted(TCP_server, index); + return -1; + } + + return index; +} + +/* return index on success + * return -1 on failure + */ +static int accept_connection(TCP_Server *TCP_server, Socket sock) +{ + if (!sock_valid(sock)) { + return -1; + } + + if (!set_socket_nonblock(sock)) { + kill_sock(sock); + return -1; + } + + if (!set_socket_nosigpipe(sock)) { + kill_sock(sock); + return -1; + } + + uint16_t index = TCP_server->incoming_connection_queue_index % MAX_INCOMING_CONNECTIONS; + + TCP_Secure_Connection *conn = &TCP_server->incoming_connection_queue[index]; + + if (conn->status != TCP_STATUS_NO_STATUS) { + kill_TCP_secure_connection(conn); + } + + conn->status = TCP_STATUS_CONNECTED; + conn->sock = sock; + conn->next_packet_length = 0; + + ++TCP_server->incoming_connection_queue_index; + return index; +} + +static Socket new_listening_TCP_socket(int family, uint16_t port) +{ + Socket sock = net_socket(family, TOX_SOCK_STREAM, TOX_PROTO_TCP); + + if (!sock_valid(sock)) { + return ~0; + } + + int ok = set_socket_nonblock(sock); + + if (ok && family == TOX_AF_INET6) { + ok = set_socket_dualstack(sock); + } + + if (ok) { + ok = set_socket_reuseaddr(sock); + } + + ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0); + + if (!ok) { + kill_sock(sock); + return ~0; + } + + return sock; +} + +TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key, + Onion *onion) +{ + if (num_sockets == 0 || ports == NULL) { + return NULL; + } + + if (networking_at_startup() != 0) { + return NULL; + } + + TCP_Server *temp = (TCP_Server *)calloc(1, sizeof(TCP_Server)); + + if (temp == NULL) { + return NULL; + } + + temp->socks_listening = (Socket *)calloc(num_sockets, sizeof(Socket)); + + if (temp->socks_listening == NULL) { + free(temp); + return NULL; + } + +#ifdef TCP_SERVER_USE_EPOLL + temp->efd = epoll_create(8); + + if (temp->efd == -1) { + free(temp->socks_listening); + free(temp); + return NULL; + } + +#endif + + uint8_t family; + + if (ipv6_enabled) { + family = TOX_AF_INET6; + } else { + family = TOX_AF_INET; + } + + uint32_t i; +#ifdef TCP_SERVER_USE_EPOLL + struct epoll_event ev; +#endif + + for (i = 0; i < num_sockets; ++i) { + Socket sock = new_listening_TCP_socket(family, ports[i]); + + if (sock_valid(sock)) { +#ifdef TCP_SERVER_USE_EPOLL + ev.events = EPOLLIN | EPOLLET; + ev.data.u64 = sock | ((uint64_t)TCP_SOCKET_LISTENING << 32); + + if (epoll_ctl(temp->efd, EPOLL_CTL_ADD, sock, &ev) == -1) { + continue; + } + +#endif + + temp->socks_listening[temp->num_listening_socks] = sock; + ++temp->num_listening_socks; + } + } + + if (temp->num_listening_socks == 0) { + free(temp->socks_listening); + free(temp); + return NULL; + } + + if (onion) { + temp->onion = onion; + set_callback_handle_recv_1(onion, &handle_onion_recv_1, temp); + } + + memcpy(temp->secret_key, secret_key, CRYPTO_SECRET_KEY_SIZE); + crypto_derive_public_key(temp->public_key, temp->secret_key); + + bs_list_init(&temp->accepted_key_list, CRYPTO_PUBLIC_KEY_SIZE, 8); + + return temp; +} + +static void do_TCP_accept_new(TCP_Server *TCP_server) +{ + uint32_t i; + + for (i = 0; i < TCP_server->num_listening_socks; ++i) { + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + Socket sock; + + do { + sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen); + } while (accept_connection(TCP_server, sock) != -1); + } +} + +static int do_incoming(TCP_Server *TCP_server, uint32_t i) +{ + if (TCP_server->incoming_connection_queue[i].status != TCP_STATUS_CONNECTED) { + return -1; + } + + int ret = read_connection_handshake(&TCP_server->incoming_connection_queue[i], TCP_server->secret_key); + + if (ret == -1) { + kill_TCP_secure_connection(&TCP_server->incoming_connection_queue[i]); + } else if (ret == 1) { + int index_new = TCP_server->unconfirmed_connection_queue_index % MAX_INCOMING_CONNECTIONS; + TCP_Secure_Connection *conn_old = &TCP_server->incoming_connection_queue[i]; + TCP_Secure_Connection *conn_new = &TCP_server->unconfirmed_connection_queue[index_new]; + + if (conn_new->status != TCP_STATUS_NO_STATUS) { + kill_TCP_secure_connection(conn_new); + } + + memcpy(conn_new, conn_old, sizeof(TCP_Secure_Connection)); + crypto_memzero(conn_old, sizeof(TCP_Secure_Connection)); + ++TCP_server->unconfirmed_connection_queue_index; + + return index_new; + } + + return -1; +} + +static int do_unconfirmed(TCP_Server *TCP_server, uint32_t i) +{ + TCP_Secure_Connection *conn = &TCP_server->unconfirmed_connection_queue[i]; + + if (conn->status != TCP_STATUS_UNCONFIRMED) { + return -1; + } + + uint8_t packet[MAX_PACKET_SIZE]; + int len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, conn->recv_nonce, + packet, sizeof(packet)); + + if (len == 0) { + return -1; + } + + if (len == -1) { + kill_TCP_secure_connection(conn); + return -1; + } + + return confirm_TCP_connection(TCP_server, conn, packet, len); +} + +static void do_confirmed_recv(TCP_Server *TCP_server, uint32_t i) +{ + TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[i]; + + uint8_t packet[MAX_PACKET_SIZE]; + int len; + + while ((len = read_packet_TCP_secure_connection(conn->sock, &conn->next_packet_length, conn->shared_key, + conn->recv_nonce, packet, sizeof(packet)))) { + if (len == -1) { + kill_accepted(TCP_server, i); + break; + } + + if (handle_TCP_packet(TCP_server, i, packet, len) == -1) { + kill_accepted(TCP_server, i); + break; + } + } +} + +static void do_TCP_incoming(TCP_Server *TCP_server) +{ + uint32_t i; + + for (i = 0; i < MAX_INCOMING_CONNECTIONS; ++i) { + do_incoming(TCP_server, i); + } +} + +static void do_TCP_unconfirmed(TCP_Server *TCP_server) +{ + uint32_t i; + + for (i = 0; i < MAX_INCOMING_CONNECTIONS; ++i) { + do_unconfirmed(TCP_server, i); + } +} + +static void do_TCP_confirmed(TCP_Server *TCP_server) +{ +#ifdef TCP_SERVER_USE_EPOLL + + if (TCP_server->last_run_pinged == unix_time()) { + return; + } + + TCP_server->last_run_pinged = unix_time(); +#endif + uint32_t i; + + for (i = 0; i < TCP_server->size_accepted_connections; ++i) { + TCP_Secure_Connection *conn = &TCP_server->accepted_connection_array[i]; + + if (conn->status != TCP_STATUS_CONFIRMED) { + continue; + } + + if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY)) { + uint8_t ping[1 + sizeof(uint64_t)]; + ping[0] = TCP_PACKET_PING; + uint64_t ping_id = random_64b(); + + if (!ping_id) { + ++ping_id; + } + + memcpy(ping + 1, &ping_id, sizeof(uint64_t)); + int ret = write_packet_TCP_secure_connection(conn, ping, sizeof(ping), 1); + + if (ret == 1) { + conn->last_pinged = unix_time(); + conn->ping_id = ping_id; + } else { + if (is_timeout(conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) { + kill_accepted(TCP_server, i); + continue; + } + } + } + + if (conn->ping_id && is_timeout(conn->last_pinged, TCP_PING_TIMEOUT)) { + kill_accepted(TCP_server, i); + continue; + } + + send_pending_data(conn); + +#ifndef TCP_SERVER_USE_EPOLL + + do_confirmed_recv(TCP_server, i); + +#endif + } +} + +#ifdef TCP_SERVER_USE_EPOLL +static void do_TCP_epoll(TCP_Server *TCP_server) +{ +#define MAX_EVENTS 16 + struct epoll_event events[MAX_EVENTS]; + int nfds; + + while ((nfds = epoll_wait(TCP_server->efd, events, MAX_EVENTS, 0)) > 0) { + int n; + + for (n = 0; n < nfds; ++n) { + Socket sock = events[n].data.u64 & 0xFFFFFFFF; + int status = (events[n].data.u64 >> 32) & 0xFF, index = (events[n].data.u64 >> 40); + + if ((events[n].events & EPOLLERR) || (events[n].events & EPOLLHUP) || (events[n].events & EPOLLRDHUP)) { + switch (status) { + case TCP_SOCKET_LISTENING: { + //should never happen + break; + } + + case TCP_SOCKET_INCOMING: { + kill_TCP_secure_connection(&TCP_server->incoming_connection_queue[index]); + break; + } + + case TCP_SOCKET_UNCONFIRMED: { + kill_TCP_secure_connection(&TCP_server->unconfirmed_connection_queue[index]); + break; + } + + case TCP_SOCKET_CONFIRMED: { + kill_accepted(TCP_server, index); + break; + } + } + + continue; + } + + + if (!(events[n].events & EPOLLIN)) { + continue; + } + + switch (status) { + case TCP_SOCKET_LISTENING: { + //socket is from socks_listening, accept connection + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + + while (1) { + Socket sock_new = accept(sock, (struct sockaddr *)&addr, &addrlen); + + if (!sock_valid(sock_new)) { + break; + } + + int index_new = accept_connection(TCP_server, sock_new); + + if (index_new == -1) { + continue; + } + + struct epoll_event ev = { + .events = EPOLLIN | EPOLLET | EPOLLRDHUP, + .data.u64 = sock_new | ((uint64_t)TCP_SOCKET_INCOMING << 32) | ((uint64_t)index_new << 40) + }; + + if (epoll_ctl(TCP_server->efd, EPOLL_CTL_ADD, sock_new, &ev) == -1) { + kill_TCP_secure_connection(&TCP_server->incoming_connection_queue[index_new]); + continue; + } + } + + break; + } + + case TCP_SOCKET_INCOMING: { + int index_new; + + if ((index_new = do_incoming(TCP_server, index)) != -1) { + events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP; + events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_UNCONFIRMED << 32) | ((uint64_t)index_new << 40); + + if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) { + kill_TCP_secure_connection(&TCP_server->unconfirmed_connection_queue[index_new]); + break; + } + } + + break; + } + + case TCP_SOCKET_UNCONFIRMED: { + int index_new; + + if ((index_new = do_unconfirmed(TCP_server, index)) != -1) { + events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP; + events[n].data.u64 = sock | ((uint64_t)TCP_SOCKET_CONFIRMED << 32) | ((uint64_t)index_new << 40); + + if (epoll_ctl(TCP_server->efd, EPOLL_CTL_MOD, sock, &events[n]) == -1) { + //remove from confirmed connections + kill_accepted(TCP_server, index_new); + break; + } + } + + break; + } + + case TCP_SOCKET_CONFIRMED: { + do_confirmed_recv(TCP_server, index); + break; + } + } + } + } + +#undef MAX_EVENTS +} +#endif + +void do_TCP_server(TCP_Server *TCP_server) +{ + unix_time_update(); + +#ifdef TCP_SERVER_USE_EPOLL + do_TCP_epoll(TCP_server); + +#else + do_TCP_accept_new(TCP_server); + do_TCP_incoming(TCP_server); + do_TCP_unconfirmed(TCP_server); +#endif + + do_TCP_confirmed(TCP_server); +} + +void kill_TCP_server(TCP_Server *TCP_server) +{ + uint32_t i; + + for (i = 0; i < TCP_server->num_listening_socks; ++i) { + kill_sock(TCP_server->socks_listening[i]); + } + + if (TCP_server->onion) { + set_callback_handle_recv_1(TCP_server->onion, NULL, NULL); + } + + bs_list_free(&TCP_server->accepted_key_list); + +#ifdef TCP_SERVER_USE_EPOLL + close(TCP_server->efd); +#endif + + free(TCP_server->socks_listening); + free(TCP_server->accepted_connection_array); + free(TCP_server); +} diff --git a/libs/libtox/src/toxcore/TCP_server.h b/libs/libtox/src/toxcore/TCP_server.h new file mode 100644 index 0000000000..f213c078e6 --- /dev/null +++ b/libs/libtox/src/toxcore/TCP_server.h @@ -0,0 +1,167 @@ +/* + * Implementation of the TCP relay server part of Tox. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef TCP_SERVER_H +#define TCP_SERVER_H + +#include "crypto_core.h" +#include "list.h" +#include "onion.h" + +#ifdef TCP_SERVER_USE_EPOLL +#include +#endif + +// Disable MSG_NOSIGNAL on systems not supporting it, e.g. Windows, FreeBSD +#if !defined(MSG_NOSIGNAL) +#define MSG_NOSIGNAL 0 +#endif + +#define MAX_INCOMING_CONNECTIONS 256 + +#define TCP_MAX_BACKLOG MAX_INCOMING_CONNECTIONS + +#define MAX_PACKET_SIZE 2048 + +#define TCP_HANDSHAKE_PLAIN_SIZE (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE) +#define TCP_SERVER_HANDSHAKE_SIZE (CRYPTO_NONCE_SIZE + TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE) +#define TCP_CLIENT_HANDSHAKE_SIZE (CRYPTO_PUBLIC_KEY_SIZE + TCP_SERVER_HANDSHAKE_SIZE) +#define TCP_MAX_OOB_DATA_LENGTH 1024 + +#define NUM_RESERVED_PORTS 16 +#define NUM_CLIENT_CONNECTIONS (256 - NUM_RESERVED_PORTS) + +#define TCP_PACKET_ROUTING_REQUEST 0 +#define TCP_PACKET_ROUTING_RESPONSE 1 +#define TCP_PACKET_CONNECTION_NOTIFICATION 2 +#define TCP_PACKET_DISCONNECT_NOTIFICATION 3 +#define TCP_PACKET_PING 4 +#define TCP_PACKET_PONG 5 +#define TCP_PACKET_OOB_SEND 6 +#define TCP_PACKET_OOB_RECV 7 +#define TCP_PACKET_ONION_REQUEST 8 +#define TCP_PACKET_ONION_RESPONSE 9 + +#define ARRAY_ENTRY_SIZE 6 + +/* frequency to ping connected nodes and timeout in seconds */ +#define TCP_PING_FREQUENCY 30 +#define TCP_PING_TIMEOUT 10 + +#ifdef TCP_SERVER_USE_EPOLL +#define TCP_SOCKET_LISTENING 0 +#define TCP_SOCKET_INCOMING 1 +#define TCP_SOCKET_UNCONFIRMED 2 +#define TCP_SOCKET_CONFIRMED 3 +#endif + +enum { + TCP_STATUS_NO_STATUS, + TCP_STATUS_CONNECTED, + TCP_STATUS_UNCONFIRMED, + TCP_STATUS_CONFIRMED, +}; + +typedef struct TCP_Priority_List TCP_Priority_List; + +struct TCP_Priority_List { + TCP_Priority_List *next; + uint16_t size, sent; + uint8_t data[]; +}; + +typedef struct TCP_Secure_Connection { + Socket sock; + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ + uint8_t sent_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of sent packets. */ + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint16_t next_packet_length; + struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint32_t index; + uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */ + uint8_t other_id; + } connections[NUM_CLIENT_CONNECTIONS]; + uint8_t last_packet[2 + MAX_PACKET_SIZE]; + uint8_t status; + uint16_t last_packet_length; + uint16_t last_packet_sent; + + TCP_Priority_List *priority_queue_start, *priority_queue_end; + + uint64_t identifier; + + uint64_t last_pinged; + uint64_t ping_id; +} TCP_Secure_Connection; + + +typedef struct TCP_Server TCP_Server; + +const uint8_t *tcp_server_public_key(const TCP_Server *tcp_server); +size_t tcp_server_listen_count(const TCP_Server *tcp_server); + +/* Create new TCP server instance. + */ +TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, const uint16_t *ports, const uint8_t *secret_key, + Onion *onion); + +/* Run the TCP_server + */ +void do_TCP_server(TCP_Server *TCP_server); + +/* Kill the TCP server + */ +void kill_TCP_server(TCP_Server *TCP_server); + +/* return the amount of data in the tcp recv buffer. + * return 0 on failure. + */ +unsigned int TCP_socket_data_recv_buffer(Socket sock); + +/* Read the next two bytes in TCP stream then convert them to + * length (host byte order). + * + * return length on success + * return 0 if nothing has been read from socket. + * return ~0 on failure. + */ +uint16_t read_TCP_length(Socket sock); + +/* Read length bytes from socket. + * + * return length on success + * return -1 on failure/no data in buffer. + */ +int read_TCP_packet(Socket sock, uint8_t *data, uint16_t length); + +/* return length of received packet on success. + * return 0 if could not read any packet. + * return -1 on failure (connection must be killed). + */ +int read_packet_TCP_secure_connection(Socket sock, uint16_t *next_packet_length, const uint8_t *shared_key, + uint8_t *recv_nonce, uint8_t *data, uint16_t max_len); + + +#endif diff --git a/libs/libtox/src/toxcore/ccompat.h b/libs/libtox/src/toxcore/ccompat.h new file mode 100644 index 0000000000..e72e66ae58 --- /dev/null +++ b/libs/libtox/src/toxcore/ccompat.h @@ -0,0 +1,43 @@ +/* + * C language compatibility macros for varying compiler support. + */ +#ifndef CCOMPAT_H +#define CCOMPAT_H + +// Marking GNU extensions to avoid warnings. +#if defined(__GNUC__) +#define GNU_EXTENSION __extension__ +#else +#define GNU_EXTENSION +#endif + +// Variable length arrays. +// VLA(type, name, size) allocates a variable length array with automatic +// storage duration. VLA_SIZE(name) evaluates to the runtime size of that array +// in bytes. +// +// If C99 VLAs are not available, an emulation using alloca (stack allocation +// "function") is used. Note the semantic difference: alloca'd memory does not +// get freed at the end of the declaration's scope. Do not use VLA() in loops or +// you may run out of stack space. +#if !defined(_MSC_VER) && __STDC_VERSION__ >= 199901L +// C99 VLAs. +#define VLA(type, name, size) type name[size] +#define SIZEOF_VLA sizeof +#else + +// Emulation using alloca. +#ifdef _WIN32 +#include +#else +#include +#endif + +#define VLA(type, name, size) \ + const size_t name##_size = (size) * sizeof(type); \ + type *const name = (type *)alloca(name##_size) +#define SIZEOF_VLA(name) name##_size + +#endif + +#endif /* CCOMPAT_H */ diff --git a/libs/libtox/src/toxcore/crypto_core.api.h b/libs/libtox/src/toxcore/crypto_core.api.h new file mode 100644 index 0000000000..cef1a52c14 --- /dev/null +++ b/libs/libtox/src/toxcore/crypto_core.api.h @@ -0,0 +1,246 @@ +%{ +/* + * Functions for the core crypto. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef CRYPTO_CORE_H +#define CRYPTO_CORE_H + +#include +#include +#include +%} + +/** + * The number of bytes in a Tox public key. + */ +const CRYPTO_PUBLIC_KEY_SIZE = 32; + +/** + * The number of bytes in a Tox secret key. + */ +const CRYPTO_SECRET_KEY_SIZE = 32; + +/** + * The number of bytes in a shared key computed from public and secret keys. + */ +const CRYPTO_SHARED_KEY_SIZE = 32; + +/** + * The number of bytes in a symmetric key. + */ +const CRYPTO_SYMMETRIC_KEY_SIZE = CRYPTO_SHARED_KEY_SIZE; + +/** + * The number of bytes needed for the MAC (message authentication code) in an + * encrypted message. + */ +const CRYPTO_MAC_SIZE = 16; + +/** + * The number of bytes in a nonce used for encryption/decryption. + */ +const CRYPTO_NONCE_SIZE = 24; + +/** + * The number of bytes in a SHA256 hash. + */ +const CRYPTO_SHA256_SIZE = 32; + +/** + * The number of bytes in a SHA512 hash. + */ +const CRYPTO_SHA512_SIZE = 64; + +/** + * A `memcmp`-like function whose running time does not depend on the input + * bytes, only on the input length. Useful to compare sensitive data where + * timing attacks could reveal that data. + * + * This means for instance that comparing "aaaa" and "aaaa" takes 4 time, and + * "aaaa" and "baaa" also takes 4 time. With a regular `memcmp`, the latter may + * take 1 time, because it immediately knows that the two strings are not equal. + */ +static int32_t crypto_memcmp(const void *p1, const void *p2, size_t length); + +/** + * A `bzero`-like function which won't be optimised away by the compiler. Some + * compilers will inline `bzero` or `memset` if they can prove that there will + * be no reads to the written data. Use this function if you want to be sure the + * memory is indeed zeroed. + */ +static void crypto_memzero(void *data, size_t length); + +/** + * Compute a SHA256 hash (32 bytes). + */ +static void crypto_sha256(uint8_t[CRYPTO_SHA256_SIZE] hash, const uint8_t[length] data); + +/** + * Compute a SHA512 hash (64 bytes). + */ +static void crypto_sha512(uint8_t[CRYPTO_SHA512_SIZE] hash, const uint8_t[length] data); + +/** + * Compare 2 public keys of length CRYPTO_PUBLIC_KEY_SIZE, not vulnerable to + * timing attacks. + * + * @return 0 if both mem locations of length are equal, -1 if they are not. + */ +static int32_t public_key_cmp( + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] pk1, + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] pk2); + +/** + * Return a random 32 bit integer. + */ +static uint32_t random_int(); + +/** + * Return a random 64 bit integer. + */ +static uint64_t random_64b(); + +/** + * Check if a Tox public key CRYPTO_PUBLIC_KEY_SIZE is valid or not. This + * should only be used for input validation. + * + * @return false if it isn't, true if it is. + */ +static bool public_key_valid(const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key); + +/** + * Generate a new random keypair. Every call to this function is likely to + * generate a different keypair. + */ +static int32_t crypto_new_keypair( + uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key); + +/** + * Derive the public key from a given secret key. + */ +static void crypto_derive_public_key( + uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + const uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key); + +/** + * Encrypt plain text of the given length to encrypted of length + + * $CRYPTO_MAC_SIZE using the public key ($CRYPTO_PUBLIC_KEY_SIZE bytes) of the + * receiver and the secret key of the sender and a $CRYPTO_NONCE_SIZE byte + * nonce. + * + * @return -1 if there was a problem, length of encrypted data if everything + * was fine. + */ +static int32_t encrypt_data( + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + const uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key, + const uint8_t[CRYPTO_NONCE_SIZE] nonce, + const uint8_t[length] plain, + uint8_t *encrypted); + + +/** + * Decrypt encrypted text of the given length to plain text of the given length + * - $CRYPTO_MAC_SIZE using the public key ($CRYPTO_PUBLIC_KEY_SIZE bytes) of + * the sender, the secret key of the receiver and a $CRYPTO_NONCE_SIZE byte + * nonce. + * + * @return -1 if there was a problem (decryption failed), length of plain text + * data if everything was fine. + */ +static int32_t decrypt_data( + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + const uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key, + const uint8_t[CRYPTO_NONCE_SIZE] nonce, + const uint8_t[length] encrypted, + uint8_t *plain); + +/** + * Fast encrypt/decrypt operations. Use if this is not a one-time communication. + * $encrypt_precompute does the shared-key generation once so it does not have + * to be preformed on every encrypt/decrypt. + */ +static int32_t encrypt_precompute( + const uint8_t[CRYPTO_PUBLIC_KEY_SIZE] public_key, + const uint8_t[CRYPTO_SECRET_KEY_SIZE] secret_key, + uint8_t[CRYPTO_SHARED_KEY_SIZE] shared_key); + +/** + * Encrypts plain of length length to encrypted of length + $CRYPTO_MAC_SIZE + * using a shared key $CRYPTO_SYMMETRIC_KEY_SIZE big and a $CRYPTO_NONCE_SIZE + * byte nonce. + * + * @return -1 if there was a problem, length of encrypted data if everything + * was fine. + */ +static int32_t encrypt_data_symmetric( + const uint8_t[CRYPTO_SHARED_KEY_SIZE] shared_key, + const uint8_t[CRYPTO_NONCE_SIZE] nonce, + const uint8_t[length] plain, + uint8_t *encrypted); + +/** + * Decrypts encrypted of length length to plain of length length - + * $CRYPTO_MAC_SIZE using a shared key CRYPTO_SHARED_KEY_SIZE big and a + * $CRYPTO_NONCE_SIZE byte nonce. + * + * @return -1 if there was a problem (decryption failed), length of plain data + * if everything was fine. + */ +static int32_t decrypt_data_symmetric( + const uint8_t[CRYPTO_SHARED_KEY_SIZE] shared_key, + const uint8_t[CRYPTO_NONCE_SIZE] nonce, + const uint8_t[length] encrypted, + uint8_t *plain); + +/** + * Increment the given nonce by 1 in big endian (rightmost byte incremented + * first). + */ +static void increment_nonce(uint8_t[CRYPTO_NONCE_SIZE] nonce); + +/** + * Increment the given nonce by a given number. The number should be in host + * byte order. + */ +static void increment_nonce_number(uint8_t[CRYPTO_NONCE_SIZE] nonce, uint32_t host_order_num); + +/** + * Fill the given nonce with random bytes. + */ +static void random_nonce(uint8_t[CRYPTO_NONCE_SIZE] nonce); + +/** + * Fill a key CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes. + */ +static void new_symmetric_key(uint8_t[CRYPTO_SYMMETRIC_KEY_SIZE] key); + +/** + * Fill an array of bytes with random values. + */ +static void random_bytes(uint8_t[length] bytes); + +%{ +#endif /* CRYPTO_CORE_H */ +%} diff --git a/libs/libtox/src/toxcore/crypto_core.c b/libs/libtox/src/toxcore/crypto_core.c new file mode 100644 index 0000000000..8e34b5876a --- /dev/null +++ b/libs/libtox/src/toxcore/crypto_core.c @@ -0,0 +1,287 @@ +/* + * Functions for the core crypto. + * + * NOTE: This code has to be perfect. We don't mess around with encryption. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ccompat.h" +#include "crypto_core.h" + +#include + +#ifndef VANILLA_NACL +/* We use libsodium by default. */ +#include +#else +#include +#include +#include +#include +#include +#include +#include +#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) +#endif + +#if CRYPTO_PUBLIC_KEY_SIZE != crypto_box_PUBLICKEYBYTES +#error CRYPTO_PUBLIC_KEY_SIZE should be equal to crypto_box_PUBLICKEYBYTES +#endif + +#if CRYPTO_SECRET_KEY_SIZE != crypto_box_SECRETKEYBYTES +#error CRYPTO_SECRET_KEY_SIZE should be equal to crypto_box_SECRETKEYBYTES +#endif + +#if CRYPTO_SHARED_KEY_SIZE != crypto_box_BEFORENMBYTES +#error CRYPTO_SHARED_KEY_SIZE should be equal to crypto_box_BEFORENMBYTES +#endif + +#if CRYPTO_SYMMETRIC_KEY_SIZE != crypto_box_BEFORENMBYTES +#error CRYPTO_SYMMETRIC_KEY_SIZE should be equal to crypto_box_BEFORENMBYTES +#endif + +#if CRYPTO_MAC_SIZE != crypto_box_MACBYTES +#error CRYPTO_MAC_SIZE should be equal to crypto_box_MACBYTES +#endif + +#if CRYPTO_NONCE_SIZE != crypto_box_NONCEBYTES +#error CRYPTO_NONCE_SIZE should be equal to crypto_box_NONCEBYTES +#endif + +#if CRYPTO_SHA256_SIZE != crypto_hash_sha256_BYTES +#error CRYPTO_SHA256_SIZE should be equal to crypto_hash_sha256_BYTES +#endif + +#if CRYPTO_SHA512_SIZE != crypto_hash_sha512_BYTES +#error CRYPTO_SHA512_SIZE should be equal to crypto_hash_sha512_BYTES +#endif + +int32_t public_key_cmp(const uint8_t *pk1, const uint8_t *pk2) +{ +#if CRYPTO_PUBLIC_KEY_SIZE != 32 +#error CRYPTO_PUBLIC_KEY_SIZE is required to be 32 bytes for public_key_cmp to work, +#endif + return crypto_verify_32(pk1, pk2); +} + +uint32_t random_int(void) +{ + uint32_t randnum; + randombytes((uint8_t *)&randnum , sizeof(randnum)); + return randnum; +} + +uint64_t random_64b(void) +{ + uint64_t randnum; + randombytes((uint8_t *)&randnum, sizeof(randnum)); + return randnum; +} + +bool public_key_valid(const uint8_t *public_key) +{ + if (public_key[31] >= 128) { /* Last bit of key is always zero. */ + return 0; + } + + return 1; +} + +/* Precomputes the shared key from their public_key and our secret_key. + * This way we can avoid an expensive elliptic curve scalar multiply for each + * encrypt/decrypt operation. + * shared_key has to be crypto_box_BEFORENMBYTES bytes long. + */ +int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *shared_key) +{ + return crypto_box_beforenm(shared_key, public_key, secret_key); +} + +int32_t encrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *plain, size_t length, + uint8_t *encrypted) +{ + if (length == 0 || !secret_key || !nonce || !plain || !encrypted) { + return -1; + } + + VLA(uint8_t, temp_plain, length + crypto_box_ZEROBYTES); + VLA(uint8_t, temp_encrypted, length + crypto_box_MACBYTES + crypto_box_BOXZEROBYTES); + + memset(temp_plain, 0, crypto_box_ZEROBYTES); + memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); // Pad the message with 32 0 bytes. + + if (crypto_box_afternm(temp_encrypted, temp_plain, length + crypto_box_ZEROBYTES, nonce, secret_key) != 0) { + return -1; + } + + /* Unpad the encrypted message. */ + memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, length + crypto_box_MACBYTES); + return length + crypto_box_MACBYTES; +} + +int32_t decrypt_data_symmetric(const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *encrypted, size_t length, + uint8_t *plain) +{ + if (length <= crypto_box_BOXZEROBYTES || !secret_key || !nonce || !encrypted || !plain) { + return -1; + } + + VLA(uint8_t, temp_plain, length + crypto_box_ZEROBYTES); + VLA(uint8_t, temp_encrypted, length + crypto_box_BOXZEROBYTES); + + memset(temp_encrypted, 0, crypto_box_BOXZEROBYTES); + memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); // Pad the message with 16 0 bytes. + + if (crypto_box_open_afternm(temp_plain, temp_encrypted, length + crypto_box_BOXZEROBYTES, nonce, secret_key) != 0) { + return -1; + } + + memcpy(plain, temp_plain + crypto_box_ZEROBYTES, length - crypto_box_MACBYTES); + return length - crypto_box_MACBYTES; +} + +int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, + const uint8_t *plain, size_t length, uint8_t *encrypted) +{ + if (!public_key || !secret_key) { + return -1; + } + + uint8_t k[crypto_box_BEFORENMBYTES]; + encrypt_precompute(public_key, secret_key, k); + int ret = encrypt_data_symmetric(k, nonce, plain, length, encrypted); + crypto_memzero(k, sizeof k); + return ret; +} + +int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, + const uint8_t *encrypted, size_t length, uint8_t *plain) +{ + if (!public_key || !secret_key) { + return -1; + } + + uint8_t k[crypto_box_BEFORENMBYTES]; + encrypt_precompute(public_key, secret_key, k); + int ret = decrypt_data_symmetric(k, nonce, encrypted, length, plain); + crypto_memzero(k, sizeof k); + return ret; +} + + +/* Increment the given nonce by 1. */ +void increment_nonce(uint8_t *nonce) +{ + /* TODO(irungentoo): use increment_nonce_number(nonce, 1) or sodium_increment (change to little endian) + * NOTE don't use breaks inside this loop + * In particular, make sure, as far as possible, + * that loop bounds and their potential underflow or overflow + * are independent of user-controlled input (you may have heard of the Heartbleed bug). + */ + uint32_t i = crypto_box_NONCEBYTES; + uint_fast16_t carry = 1U; + + for (; i != 0; --i) { + carry += (uint_fast16_t) nonce[i - 1]; + nonce[i - 1] = (uint8_t) carry; + carry >>= 8; + } +} + +static uint32_t host_to_network(uint32_t x) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + return + ((x >> 24) & 0x000000FF) | // move byte 3 to byte 0 + ((x >> 8) & 0x0000FF00) | // move byte 2 to byte 1 + ((x << 8) & 0x00FF0000) | // move byte 1 to byte 2 + ((x << 24) & 0xFF000000); // move byte 0 to byte 3 +#else + return x; +#endif +} + +/* increment the given nonce by num */ +void increment_nonce_number(uint8_t *nonce, uint32_t host_order_num) +{ + /* NOTE don't use breaks inside this loop + * In particular, make sure, as far as possible, + * that loop bounds and their potential underflow or overflow + * are independent of user-controlled input (you may have heard of the Heartbleed bug). + */ + const uint32_t big_endian_num = host_to_network(host_order_num); + const uint8_t *const num_vec = (const uint8_t *) &big_endian_num; + uint8_t num_as_nonce[crypto_box_NONCEBYTES] = {0}; + num_as_nonce[crypto_box_NONCEBYTES - 4] = num_vec[0]; + num_as_nonce[crypto_box_NONCEBYTES - 3] = num_vec[1]; + num_as_nonce[crypto_box_NONCEBYTES - 2] = num_vec[2]; + num_as_nonce[crypto_box_NONCEBYTES - 1] = num_vec[3]; + + uint32_t i = crypto_box_NONCEBYTES; + uint_fast16_t carry = 0U; + + for (; i != 0; --i) { + carry += (uint_fast16_t) nonce[i - 1] + (uint_fast16_t) num_as_nonce[i - 1]; + nonce[i - 1] = (unsigned char) carry; + carry >>= 8; + } +} + +/* Fill the given nonce with random bytes. */ +void random_nonce(uint8_t *nonce) +{ + randombytes(nonce, crypto_box_NONCEBYTES); +} + +/* Fill a key CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes */ +void new_symmetric_key(uint8_t *key) +{ + randombytes(key, CRYPTO_SYMMETRIC_KEY_SIZE); +} + +int32_t crypto_new_keypair(uint8_t *public_key, uint8_t *secret_key) +{ + return crypto_box_keypair(public_key, secret_key); +} + +void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key) +{ + crypto_scalarmult_curve25519_base(public_key, secret_key); +} + +void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length) +{ + crypto_hash_sha256(hash, data, length); +} + +void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length) +{ + crypto_hash_sha512(hash, data, length); +} + +void random_bytes(uint8_t *data, size_t length) +{ + randombytes(data, length); +} diff --git a/libs/libtox/src/toxcore/crypto_core.h b/libs/libtox/src/toxcore/crypto_core.h new file mode 100644 index 0000000000..fc5756c1d2 --- /dev/null +++ b/libs/libtox/src/toxcore/crypto_core.h @@ -0,0 +1,234 @@ +/* + * Functions for the core crypto. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef CRYPTO_CORE_H +#define CRYPTO_CORE_H + +#include +#include +#include + +/** + * The number of bytes in a Tox public key. + */ +#define CRYPTO_PUBLIC_KEY_SIZE 32 + +uint32_t crypto_public_key_size(void); + +/** + * The number of bytes in a Tox secret key. + */ +#define CRYPTO_SECRET_KEY_SIZE 32 + +uint32_t crypto_secret_key_size(void); + +/** + * The number of bytes in a shared key computed from public and secret keys. + */ +#define CRYPTO_SHARED_KEY_SIZE 32 + +uint32_t crypto_shared_key_size(void); + +/** + * The number of bytes in a symmetric key. + */ +#define CRYPTO_SYMMETRIC_KEY_SIZE CRYPTO_SHARED_KEY_SIZE + +uint32_t crypto_symmetric_key_size(void); + +/** + * The number of bytes needed for the MAC (message authentication code) in an + * encrypted message. + */ +#define CRYPTO_MAC_SIZE 16 + +uint32_t crypto_mac_size(void); + +/** + * The number of bytes in a nonce used for encryption/decryption. + */ +#define CRYPTO_NONCE_SIZE 24 + +uint32_t crypto_nonce_size(void); + +/** + * The number of bytes in a SHA256 hash. + */ +#define CRYPTO_SHA256_SIZE 32 + +uint32_t crypto_sha256_size(void); + +/** + * The number of bytes in a SHA512 hash. + */ +#define CRYPTO_SHA512_SIZE 64 + +uint32_t crypto_sha512_size(void); + +/** + * A `memcmp`-like function whose running time does not depend on the input + * bytes, only on the input length. Useful to compare sensitive data where + * timing attacks could reveal that data. + * + * This means for instance that comparing "aaaa" and "aaaa" takes 4 time, and + * "aaaa" and "baaa" also takes 4 time. With a regular `memcmp`, the latter may + * take 1 time, because it immediately knows that the two strings are not equal. + */ +int32_t crypto_memcmp(const void *p1, const void *p2, size_t length); + +/** + * A `bzero`-like function which won't be optimised away by the compiler. Some + * compilers will inline `bzero` or `memset` if they can prove that there will + * be no reads to the written data. Use this function if you want to be sure the + * memory is indeed zeroed. + */ +void crypto_memzero(void *data, size_t length); + +/** + * Compute a SHA256 hash (32 bytes). + */ +void crypto_sha256(uint8_t *hash, const uint8_t *data, size_t length); + +/** + * Compute a SHA512 hash (64 bytes). + */ +void crypto_sha512(uint8_t *hash, const uint8_t *data, size_t length); + +/** + * Compare 2 public keys of length CRYPTO_PUBLIC_KEY_SIZE, not vulnerable to + * timing attacks. + * + * @return 0 if both mem locations of length are equal, -1 if they are not. + */ +int32_t public_key_cmp(const uint8_t *pk1, const uint8_t *pk2); + +/** + * Return a random 32 bit integer. + */ +uint32_t random_int(void); + +/** + * Return a random 64 bit integer. + */ +uint64_t random_64b(void); + +/** + * Check if a Tox public key CRYPTO_PUBLIC_KEY_SIZE is valid or not. This + * should only be used for input validation. + * + * @return false if it isn't, true if it is. + */ +bool public_key_valid(const uint8_t *public_key); + +/** + * Generate a new random keypair. Every call to this function is likely to + * generate a different keypair. + */ +int32_t crypto_new_keypair(uint8_t *public_key, uint8_t *secret_key); + +/** + * Derive the public key from a given secret key. + */ +void crypto_derive_public_key(uint8_t *public_key, const uint8_t *secret_key); + +/** + * Encrypt plain text of the given length to encrypted of length + + * CRYPTO_MAC_SIZE using the public key (CRYPTO_PUBLIC_KEY_SIZE bytes) of the + * receiver and the secret key of the sender and a CRYPTO_NONCE_SIZE byte + * nonce. + * + * @return -1 if there was a problem, length of encrypted data if everything + * was fine. + */ +int32_t encrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, const uint8_t *plain, + size_t length, uint8_t *encrypted); + +/** + * Decrypt encrypted text of the given length to plain text of the given length + * - CRYPTO_MAC_SIZE using the public key (CRYPTO_PUBLIC_KEY_SIZE bytes) of + * the sender, the secret key of the receiver and a CRYPTO_NONCE_SIZE byte + * nonce. + * + * @return -1 if there was a problem (decryption failed), length of plain text + * data if everything was fine. + */ +int32_t decrypt_data(const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *nonce, + const uint8_t *encrypted, size_t length, uint8_t *plain); + +/** + * Fast encrypt/decrypt operations. Use if this is not a one-time communication. + * encrypt_precompute does the shared-key generation once so it does not have + * to be preformed on every encrypt/decrypt. + */ +int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *shared_key); + +/** + * Encrypts plain of length length to encrypted of length + CRYPTO_MAC_SIZE + * using a shared key CRYPTO_SYMMETRIC_KEY_SIZE big and a CRYPTO_NONCE_SIZE + * byte nonce. + * + * @return -1 if there was a problem, length of encrypted data if everything + * was fine. + */ +int32_t encrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *plain, size_t length, + uint8_t *encrypted); + +/** + * Decrypts encrypted of length length to plain of length length - + * CRYPTO_MAC_SIZE using a shared key CRYPTO_SHARED_KEY_SIZE big and a + * CRYPTO_NONCE_SIZE byte nonce. + * + * @return -1 if there was a problem (decryption failed), length of plain data + * if everything was fine. + */ +int32_t decrypt_data_symmetric(const uint8_t *shared_key, const uint8_t *nonce, const uint8_t *encrypted, size_t length, + uint8_t *plain); + +/** + * Increment the given nonce by 1 in big endian (rightmost byte incremented + * first). + */ +void increment_nonce(uint8_t *nonce); + +/** + * Increment the given nonce by a given number. The number should be in host + * byte order. + */ +void increment_nonce_number(uint8_t *nonce, uint32_t host_order_num); + +/** + * Fill the given nonce with random bytes. + */ +void random_nonce(uint8_t *nonce); + +/** + * Fill a key CRYPTO_SYMMETRIC_KEY_SIZE big with random bytes. + */ +void new_symmetric_key(uint8_t *key); + +/** + * Fill an array of bytes with random values. + */ +void random_bytes(uint8_t *bytes, size_t length); + +#endif /* CRYPTO_CORE_H */ diff --git a/libs/libtox/src/toxcore/crypto_core_mem.c b/libs/libtox/src/toxcore/crypto_core_mem.c new file mode 100644 index 0000000000..b8f4223e65 --- /dev/null +++ b/libs/libtox/src/toxcore/crypto_core_mem.c @@ -0,0 +1,87 @@ +/* + * ISC License + * + * Copyright (c) 2013-2016 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "crypto_core.h" + +#ifndef VANILLA_NACL +/* We use libsodium by default. */ +#include +#else +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#include +#include +#endif +#endif + + +void crypto_memzero(void *data, size_t length) +{ +#ifndef VANILLA_NACL + sodium_memzero(data, length); +#else +#ifdef _WIN32 + SecureZeroMemory(data, length); +#elif defined(HAVE_MEMSET_S) + + if (length > 0U) { + errno_t code = memset_s(data, (rsize_t) length, 0, (rsize_t) length); + + if (code != 0) { + abort(); /* LCOV_EXCL_LINE */ + } + } + +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(data, length); +#else + volatile unsigned char *volatile pnt = + (volatile unsigned char *volatile) data; + size_t i = (size_t) 0U; + + while (i < length) { + pnt[i++] = 0U; + } + +#endif +#endif +} + +int32_t crypto_memcmp(const void *p1, const void *p2, size_t length) +{ +#ifndef VANILLA_NACL + return sodium_memcmp(p1, p2, length); +#else + const volatile unsigned char *volatile b1 = + (const volatile unsigned char *volatile) p1; + const volatile unsigned char *volatile b2 = + (const volatile unsigned char *volatile) p2; + + size_t i; + unsigned char d = (unsigned char) 0U; + + for (i = 0U; i < length; i++) { + d |= b1[i] ^ b2[i]; + } + + return (1 & ((d - 1) >> 8)) - 1; +#endif +} diff --git a/libs/libtox/src/toxcore/friend_connection.c b/libs/libtox/src/toxcore/friend_connection.c new file mode 100644 index 0000000000..9f0677b109 --- /dev/null +++ b/libs/libtox/src/toxcore/friend_connection.c @@ -0,0 +1,937 @@ +/* + * Connection to friends. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "friend_connection.h" + +#include "util.h" + +#define PORTS_PER_DISCOVERY 10 + +/* return 1 if the friendcon_id is not valid. + * return 0 if the friendcon_id is valid. + */ +static uint8_t friendconn_id_not_valid(const Friend_Connections *fr_c, int friendcon_id) +{ + if ((unsigned int)friendcon_id >= fr_c->num_cons) { + return 1; + } + + if (fr_c->conns == NULL) { + return 1; + } + + if (fr_c->conns[friendcon_id].status == FRIENDCONN_STATUS_NONE) { + return 1; + } + + return 0; +} + + +/* Set the size of the friend connections list to num. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_friendconns(Friend_Connections *fr_c, uint32_t num) +{ + if (num == 0) { + free(fr_c->conns); + fr_c->conns = NULL; + return 0; + } + + Friend_Conn *newgroup_cons = (Friend_Conn *)realloc(fr_c->conns, num * sizeof(Friend_Conn)); + + if (newgroup_cons == NULL) { + return -1; + } + + fr_c->conns = newgroup_cons; + return 0; +} + +/* Create a new empty friend connection. + * + * return -1 on failure. + * return friendcon_id on success. + */ +static int create_friend_conn(Friend_Connections *fr_c) +{ + uint32_t i; + + for (i = 0; i < fr_c->num_cons; ++i) { + if (fr_c->conns[i].status == FRIENDCONN_STATUS_NONE) { + return i; + } + } + + int id = -1; + + if (realloc_friendconns(fr_c, fr_c->num_cons + 1) == 0) { + id = fr_c->num_cons; + ++fr_c->num_cons; + memset(&(fr_c->conns[id]), 0, sizeof(Friend_Conn)); + } + + return id; +} + +/* Wipe a friend connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_friend_conn(Friend_Connections *fr_c, int friendcon_id) +{ + if (friendconn_id_not_valid(fr_c, friendcon_id)) { + return -1; + } + + uint32_t i; + memset(&(fr_c->conns[friendcon_id]), 0 , sizeof(Friend_Conn)); + + for (i = fr_c->num_cons; i != 0; --i) { + if (fr_c->conns[i - 1].status != FRIENDCONN_STATUS_NONE) { + break; + } + } + + if (fr_c->num_cons != i) { + fr_c->num_cons = i; + realloc_friendconns(fr_c, fr_c->num_cons); + } + + return 0; +} + +static Friend_Conn *get_conn(const Friend_Connections *fr_c, int friendcon_id) +{ + if (friendconn_id_not_valid(fr_c, friendcon_id)) { + return 0; + } + + return &fr_c->conns[friendcon_id]; +} + +/* return friendcon_id corresponding to the real public key on success. + * return -1 on failure. + */ +int getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < fr_c->num_cons; ++i) { + Friend_Conn *friend_con = get_conn(fr_c, i); + + if (friend_con) { + if (public_key_cmp(friend_con->real_public_key, real_pk) == 0) { + return i; + } + } + } + + return -1; +} + +/* Add a TCP relay associated to the friend. + * + * return -1 on failure. + * return 0 on success. + */ +int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + /* Local ip and same pk means that they are hosting a TCP relay. */ + if (Local_ip(ip_port.ip) && public_key_cmp(friend_con->dht_temp_pk, public_key) == 0) { + if (friend_con->dht_ip_port.ip.family != 0) { + ip_port.ip = friend_con->dht_ip_port.ip; + } else { + friend_con->hosting_tcp_relay = 0; + } + } + + unsigned int i; + + uint16_t index = friend_con->tcp_relay_counter % FRIEND_MAX_STORED_TCP_RELAYS; + + for (i = 0; i < FRIEND_MAX_STORED_TCP_RELAYS; ++i) { + if (friend_con->tcp_relays[i].ip_port.ip.family != 0 + && public_key_cmp(friend_con->tcp_relays[i].public_key, public_key) == 0) { + memset(&friend_con->tcp_relays[i], 0, sizeof(Node_format)); + } + } + + friend_con->tcp_relays[index].ip_port = ip_port; + memcpy(friend_con->tcp_relays[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + ++friend_con->tcp_relay_counter; + + return add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, public_key); +} + +/* Connect to number saved relays for friend. */ +static void connect_to_saved_tcp_relays(Friend_Connections *fr_c, int friendcon_id, unsigned int number) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return; + } + + unsigned int i; + + for (i = 0; (i < FRIEND_MAX_STORED_TCP_RELAYS) && (number != 0); ++i) { + uint16_t index = (friend_con->tcp_relay_counter - (i + 1)) % FRIEND_MAX_STORED_TCP_RELAYS; + + if (friend_con->tcp_relays[index].ip_port.ip.family) { + if (add_tcp_relay_peer(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->tcp_relays[index].ip_port, + friend_con->tcp_relays[index].public_key) == 0) { + --number; + } + } + } +} + +static unsigned int send_relays(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return 0; + } + + Node_format nodes[MAX_SHARED_RELAYS]; + uint8_t data[1024]; + int n, length; + + n = copy_connected_tcp_relays(fr_c->net_crypto, nodes, MAX_SHARED_RELAYS); + + int i; + + for (i = 0; i < n; ++i) { + /* Associated the relays being sent with this connection. + On receiving the peer will do the same which will establish the connection. */ + friend_add_tcp_relay(fr_c, friendcon_id, nodes[i].ip_port, nodes[i].public_key); + } + + length = pack_nodes(data + 1, sizeof(data) - 1, nodes, n); + + if (length <= 0) { + return 0; + } + + data[0] = PACKET_ID_SHARE_RELAYS; + ++length; + + if (write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, data, length, 0) != -1) { + friend_con->share_relays_lastsent = unix_time(); + return 1; + } + + return 0; +} + +/* callback for recv TCP relay nodes. */ +static int tcp_relay_node_callback(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + + if (friend_con->crypt_connection_id != -1) { + return friend_add_tcp_relay(fr_c, number, ip_port, public_key); + } + + return add_tcp_relay(fr_c->net_crypto, ip_port, public_key); +} + +static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id); +/* Callback for DHT ip_port changes. */ +static void dht_ip_callback(void *object, int32_t number, IP_Port ip_port) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return; + } + + if (friend_con->crypt_connection_id == -1) { + friend_new_connection(fr_c, number); + } + + set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, ip_port, 1); + friend_con->dht_ip_port = ip_port; + friend_con->dht_ip_port_lastrecv = unix_time(); + + if (friend_con->hosting_tcp_relay) { + friend_add_tcp_relay(fr_c, number, ip_port, friend_con->dht_temp_pk); + friend_con->hosting_tcp_relay = 0; + } +} + +static void change_dht_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_public_key) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return; + } + + friend_con->dht_pk_lastrecv = unix_time(); + + if (friend_con->dht_lock) { + if (DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock) != 0) { + printf("a. Could not delete dht peer. Please report this.\n"); + return; + } + + friend_con->dht_lock = 0; + } + + DHT_addfriend(fr_c->dht, dht_public_key, dht_ip_callback, fr_c, friendcon_id, &friend_con->dht_lock); + memcpy(friend_con->dht_temp_pk, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); +} + +static int handle_status(void *object, int number, uint8_t status, void *userdata) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + + bool call_cb = 0; + + if (status) { /* Went online. */ + call_cb = 1; + friend_con->status = FRIENDCONN_STATUS_CONNECTED; + friend_con->ping_lastrecv = unix_time(); + friend_con->share_relays_lastsent = 0; + onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); + } else { /* Went offline. */ + if (friend_con->status != FRIENDCONN_STATUS_CONNECTING) { + call_cb = 1; + friend_con->dht_pk_lastrecv = unix_time(); + onion_set_friend_online(fr_c->onion_c, friend_con->onion_friendnum, status); + } + + friend_con->status = FRIENDCONN_STATUS_CONNECTING; + friend_con->crypt_connection_id = -1; + friend_con->hosting_tcp_relay = 0; + } + + if (call_cb) { + unsigned int i; + + for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { + if (friend_con->callbacks[i].status_callback) { + friend_con->callbacks[i].status_callback( + friend_con->callbacks[i].callback_object, + friend_con->callbacks[i].callback_id, status, userdata); + } + } + } + + return 0; +} + +/* Callback for dht public key changes. */ +static void dht_pk_callback(void *object, int32_t number, const uint8_t *dht_public_key, void *userdata) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return; + } + + if (public_key_cmp(friend_con->dht_temp_pk, dht_public_key) == 0) { + return; + } + + change_dht_pk(fr_c, number, dht_public_key); + + /* if pk changed, create a new connection.*/ + if (friend_con->crypt_connection_id != -1) { + crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); + friend_con->crypt_connection_id = -1; + handle_status(object, number, 0, userdata); /* Going offline. */ + } + + friend_new_connection(fr_c, number); + onion_set_friend_DHT_pubkey(fr_c->onion_c, friend_con->onion_friendnum, dht_public_key); +} + +static int handle_packet(void *object, int number, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0) { + return -1; + } + + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + + if (data[0] == PACKET_ID_FRIEND_REQUESTS) { + if (fr_c->fr_request_callback) { + fr_c->fr_request_callback(fr_c->fr_request_object, friend_con->real_public_key, data, length, userdata); + } + + return 0; + } + + if (data[0] == PACKET_ID_ALIVE) { + friend_con->ping_lastrecv = unix_time(); + return 0; + } + + if (data[0] == PACKET_ID_SHARE_RELAYS) { + Node_format nodes[MAX_SHARED_RELAYS]; + int n; + + if ((n = unpack_nodes(nodes, MAX_SHARED_RELAYS, NULL, data + 1, length - 1, 1)) == -1) { + return -1; + } + + int j; + + for (j = 0; j < n; j++) { + friend_add_tcp_relay(fr_c, number, nodes[j].ip_port, nodes[j].public_key); + } + + return 0; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { + if (friend_con->callbacks[i].data_callback) { + friend_con->callbacks[i].data_callback( + friend_con->callbacks[i].callback_object, + friend_con->callbacks[i].callback_id, data, length, userdata); + } + + friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + } + + return 0; +} + +static int handle_lossy_packet(void *object, int number, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0) { + return -1; + } + + Friend_Connections *fr_c = (Friend_Connections *)object; + Friend_Conn *friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_FRIEND_CONNECTION_CALLBACKS; ++i) { + if (friend_con->callbacks[i].lossy_data_callback) { + friend_con->callbacks[i].lossy_data_callback( + friend_con->callbacks[i].callback_object, + friend_con->callbacks[i].callback_id, data, length, userdata); + } + + friend_con = get_conn(fr_c, number); + + if (!friend_con) { + return -1; + } + } + + return 0; +} + +static int handle_new_connections(void *object, New_Connection *n_c) +{ + Friend_Connections *fr_c = (Friend_Connections *)object; + int friendcon_id = getfriend_conn_id_pk(fr_c, n_c->public_key); + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (friend_con) { + + if (friend_con->crypt_connection_id != -1) { + return -1; + } + + int id = accept_crypto_connection(fr_c->net_crypto, n_c); + + if (id == -1) { + return -1; + } + + connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); + connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); + connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); + friend_con->crypt_connection_id = id; + + if (n_c->source.ip.family != TOX_AF_INET && n_c->source.ip.family != TOX_AF_INET6) { + set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port, 0); + } else { + friend_con->dht_ip_port = n_c->source; + friend_con->dht_ip_port_lastrecv = unix_time(); + } + + if (public_key_cmp(friend_con->dht_temp_pk, n_c->dht_public_key) != 0) { + change_dht_pk(fr_c, friendcon_id, n_c->dht_public_key); + } + + nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); + return 0; + } + + return -1; +} + +static int friend_new_connection(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + if (friend_con->crypt_connection_id != -1) { + return -1; + } + + /* If dht_temp_pk does not contains a pk. */ + if (!friend_con->dht_lock) { + return -1; + } + + int id = new_crypto_connection(fr_c->net_crypto, friend_con->real_public_key, friend_con->dht_temp_pk); + + if (id == -1) { + return -1; + } + + friend_con->crypt_connection_id = id; + connection_status_handler(fr_c->net_crypto, id, &handle_status, fr_c, friendcon_id); + connection_data_handler(fr_c->net_crypto, id, &handle_packet, fr_c, friendcon_id); + connection_lossy_data_handler(fr_c->net_crypto, id, &handle_lossy_packet, fr_c, friendcon_id); + nc_dht_pk_callback(fr_c->net_crypto, id, &dht_pk_callback, fr_c, friendcon_id); + + return 0; +} + +static int send_ping(const Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + uint8_t ping = PACKET_ID_ALIVE; + int64_t ret = write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, &ping, sizeof(ping), 0); + + if (ret != -1) { + friend_con->ping_lastsent = unix_time(); + return 0; + } + + return -1; +} + +/* Increases lock_count for the connection with friendcon_id by 1. + * + * return 0 on success. + * return -1 on failure. + */ +int friend_connection_lock(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + ++friend_con->lock_count; + return 0; +} + +/* return FRIENDCONN_STATUS_CONNECTED if the friend is connected. + * return FRIENDCONN_STATUS_CONNECTING if the friend isn't connected. + * return FRIENDCONN_STATUS_NONE on failure. + */ +unsigned int friend_con_connected(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return 0; + } + + return friend_con->status; +} + +/* Copy public keys associated to friendcon_id. + * + * return 0 on success. + * return -1 on failure. + */ +int get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + if (real_pk) { + memcpy(real_pk, friend_con->real_public_key, CRYPTO_PUBLIC_KEY_SIZE); + } + + if (dht_temp_pk) { + memcpy(dht_temp_pk, friend_con->dht_temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + } + + return 0; +} + +/* Set temp dht key for connection. + */ +void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk, void *userdata) +{ + dht_pk_callback(fr_c, friendcon_id, dht_temp_pk, userdata); +} + +/* Set the callbacks for the friend connection. + * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. + * + * return 0 on success. + * return -1 on failure + */ +int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, + int (*status_callback)(void *object, int id, uint8_t status, void *userdata), + int (*data_callback)(void *object, int id, const uint8_t *data, uint16_t len, void *userdata), + int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata), + void *object, int number) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + if (index >= MAX_FRIEND_CONNECTION_CALLBACKS) { + return -1; + } + + friend_con->callbacks[index].status_callback = status_callback; + friend_con->callbacks[index].data_callback = data_callback; + friend_con->callbacks[index].lossy_data_callback = lossy_data_callback; + + friend_con->callbacks[index].callback_object = object; + friend_con->callbacks[index].callback_id = number; + + return 0; +} + +/* return the crypt_connection_id for the connection. + * + * return crypt_connection_id on success. + * return -1 on failure. + */ +int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + return friend_con->crypt_connection_id; +} + +/* Create a new friend connection. + * If one to that real public key already exists, increase lock count and return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key) +{ + int friendcon_id = getfriend_conn_id_pk(fr_c, real_public_key); + + if (friendcon_id != -1) { + ++fr_c->conns[friendcon_id].lock_count; + return friendcon_id; + } + + friendcon_id = create_friend_conn(fr_c); + + if (friendcon_id == -1) { + return -1; + } + + int32_t onion_friendnum = onion_addfriend(fr_c->onion_c, real_public_key); + + if (onion_friendnum == -1) { + return -1; + } + + Friend_Conn *friend_con = &fr_c->conns[friendcon_id]; + + friend_con->crypt_connection_id = -1; + friend_con->status = FRIENDCONN_STATUS_CONNECTING; + memcpy(friend_con->real_public_key, real_public_key, CRYPTO_PUBLIC_KEY_SIZE); + friend_con->onion_friendnum = onion_friendnum; + + recv_tcp_relay_handler(fr_c->onion_c, onion_friendnum, &tcp_relay_node_callback, fr_c, friendcon_id); + onion_dht_pk_callback(fr_c->onion_c, onion_friendnum, &dht_pk_callback, fr_c, friendcon_id); + + return friendcon_id; +} + +/* Kill a friend connection. + * + * return -1 on failure. + * return 0 on success. + */ +int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id) +{ + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + if (friend_con->lock_count) { + --friend_con->lock_count; + return 0; + } + + onion_delfriend(fr_c->onion_c, friend_con->onion_friendnum); + crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); + + if (friend_con->dht_lock) { + DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); + } + + return wipe_friend_conn(fr_c, friendcon_id); +} + + +/* Set friend request callback. + * + * This function will be called every time a friend request packet is received. + */ +void set_friend_request_callback(Friend_Connections *fr_c, int (*fr_request_callback)(void *, const uint8_t *, + const uint8_t *, uint16_t, void *), void *object) +{ + fr_c->fr_request_callback = fr_request_callback; + fr_c->fr_request_object = object; + oniondata_registerhandler(fr_c->onion_c, CRYPTO_PACKET_FRIEND_REQ, fr_request_callback, object); +} + +/* Send a Friend request packet. + * + * return -1 if failure. + * return 0 if it sent the friend request directly to the friend. + * return the number of peers it was routed through if it did not send it directly. + */ +int send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data, + uint16_t length) +{ + if (1 + sizeof(nospam_num) + length > ONION_CLIENT_MAX_DATA_SIZE || length == 0) { + return -1; + } + + Friend_Conn *friend_con = get_conn(fr_c, friendcon_id); + + if (!friend_con) { + return -1; + } + + VLA(uint8_t, packet, 1 + sizeof(nospam_num) + length); + memcpy(packet + 1, &nospam_num, sizeof(nospam_num)); + memcpy(packet + 1 + sizeof(nospam_num), data, length); + + if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { + packet[0] = PACKET_ID_FRIEND_REQUESTS; + return write_cryptpacket(fr_c->net_crypto, friend_con->crypt_connection_id, packet, SIZEOF_VLA(packet), 0) != -1; + } + + packet[0] = CRYPTO_PACKET_FRIEND_REQ; + int num = send_onion_data(fr_c->onion_c, friend_con->onion_friendnum, packet, SIZEOF_VLA(packet)); + + if (num <= 0) { + return -1; + } + + return num; +} + +/* Create new friend_connections instance. */ +Friend_Connections *new_friend_connections(Onion_Client *onion_c, bool local_discovery_enabled) +{ + if (!onion_c) { + return NULL; + } + + Friend_Connections *temp = (Friend_Connections *)calloc(1, sizeof(Friend_Connections)); + + if (temp == NULL) { + return NULL; + } + + temp->dht = onion_c->dht; + temp->net_crypto = onion_c->c; + temp->onion_c = onion_c; + temp->local_discovery_enabled = local_discovery_enabled; + // Don't include default port in port range + temp->next_LANport = TOX_PORTRANGE_FROM + 1; + + new_connection_handler(temp->net_crypto, &handle_new_connections, temp); + + if (temp->local_discovery_enabled) { + LANdiscovery_init(temp->dht); + } + + return temp; +} + +/* Send a LAN discovery packet every LAN_DISCOVERY_INTERVAL seconds. */ +static void LANdiscovery(Friend_Connections *fr_c) +{ + if (fr_c->last_LANdiscovery + LAN_DISCOVERY_INTERVAL < unix_time()) { + const uint16_t first = fr_c->next_LANport; + uint16_t last = first + PORTS_PER_DISCOVERY; + last = last > TOX_PORTRANGE_TO ? TOX_PORTRANGE_TO : last; + + // Always send to default port + send_LANdiscovery(net_htons(TOX_PORT_DEFAULT), fr_c->dht); + + // And check some extra ports + for (uint16_t port = first; port < last; port++) { + send_LANdiscovery(net_htons(port), fr_c->dht); + } + + // Don't include default port in port range + fr_c->next_LANport = last != TOX_PORTRANGE_TO ? last : TOX_PORTRANGE_FROM + 1; + fr_c->last_LANdiscovery = unix_time(); + } +} + +/* main friend_connections loop. */ +void do_friend_connections(Friend_Connections *fr_c, void *userdata) +{ + uint32_t i; + uint64_t temp_time = unix_time(); + + for (i = 0; i < fr_c->num_cons; ++i) { + Friend_Conn *friend_con = get_conn(fr_c, i); + + if (friend_con) { + if (friend_con->status == FRIENDCONN_STATUS_CONNECTING) { + if (friend_con->dht_pk_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { + if (friend_con->dht_lock) { + DHT_delfriend(fr_c->dht, friend_con->dht_temp_pk, friend_con->dht_lock); + friend_con->dht_lock = 0; + memset(friend_con->dht_temp_pk, 0, CRYPTO_PUBLIC_KEY_SIZE); + } + } + + if (friend_con->dht_ip_port_lastrecv + FRIEND_DHT_TIMEOUT < temp_time) { + friend_con->dht_ip_port.ip.family = 0; + } + + if (friend_con->dht_lock) { + if (friend_new_connection(fr_c, i) == 0) { + set_direct_ip_port(fr_c->net_crypto, friend_con->crypt_connection_id, friend_con->dht_ip_port, 0); + connect_to_saved_tcp_relays(fr_c, i, (MAX_FRIEND_TCP_CONNECTIONS / 2)); /* Only fill it half up. */ + } + } + } else if (friend_con->status == FRIENDCONN_STATUS_CONNECTED) { + if (friend_con->ping_lastsent + FRIEND_PING_INTERVAL < temp_time) { + send_ping(fr_c, i); + } + + if (friend_con->share_relays_lastsent + SHARE_RELAYS_INTERVAL < temp_time) { + send_relays(fr_c, i); + } + + if (friend_con->ping_lastrecv + FRIEND_CONNECTION_TIMEOUT < temp_time) { + /* If we stopped receiving ping packets, kill it. */ + crypto_kill(fr_c->net_crypto, friend_con->crypt_connection_id); + friend_con->crypt_connection_id = -1; + handle_status(fr_c, i, 0, userdata); /* Going offline. */ + } + } + } + } + + if (fr_c->local_discovery_enabled) { + LANdiscovery(fr_c); + } +} + +/* Free everything related with friend_connections. */ +void kill_friend_connections(Friend_Connections *fr_c) +{ + if (!fr_c) { + return; + } + + uint32_t i; + + for (i = 0; i < fr_c->num_cons; ++i) { + kill_friend_connection(fr_c, i); + } + + if (fr_c->local_discovery_enabled) { + LANdiscovery_kill(fr_c->dht); + } + + free(fr_c); +} diff --git a/libs/libtox/src/toxcore/friend_connection.h b/libs/libtox/src/toxcore/friend_connection.h new file mode 100644 index 0000000000..e993a103d3 --- /dev/null +++ b/libs/libtox/src/toxcore/friend_connection.h @@ -0,0 +1,210 @@ +/* + * Connection to friends. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef FRIEND_CONNECTION_H +#define FRIEND_CONNECTION_H + +#include "DHT.h" +#include "LAN_discovery.h" +#include "net_crypto.h" +#include "onion_client.h" + +#define MAX_FRIEND_CONNECTION_CALLBACKS 2 +#define MESSENGER_CALLBACK_INDEX 0 +#define GROUPCHAT_CALLBACK_INDEX 1 + +#define PACKET_ID_ALIVE 16 +#define PACKET_ID_SHARE_RELAYS 17 +#define PACKET_ID_FRIEND_REQUESTS 18 + +/* Interval between the sending of ping packets. */ +#define FRIEND_PING_INTERVAL 8 + +/* If no packets are received from friend in this time interval, kill the connection. */ +#define FRIEND_CONNECTION_TIMEOUT (FRIEND_PING_INTERVAL * 4) + +/* Time before friend is removed from the DHT after last hearing about him. */ +#define FRIEND_DHT_TIMEOUT BAD_NODE_TIMEOUT + +#define FRIEND_MAX_STORED_TCP_RELAYS (MAX_FRIEND_TCP_CONNECTIONS * 4) + +/* Max number of tcp relays sent to friends */ +#define MAX_SHARED_RELAYS (RECOMMENDED_FRIEND_TCP_CONNECTIONS) + +/* Interval between the sending of tcp relay information */ +#define SHARE_RELAYS_INTERVAL (5 * 60) + + +enum { + FRIENDCONN_STATUS_NONE, + FRIENDCONN_STATUS_CONNECTING, + FRIENDCONN_STATUS_CONNECTED +}; + +typedef struct { + uint8_t status; + + uint8_t real_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint16_t dht_lock; + IP_Port dht_ip_port; + uint64_t dht_pk_lastrecv, dht_ip_port_lastrecv; + + int onion_friendnum; + int crypt_connection_id; + + uint64_t ping_lastrecv, ping_lastsent; + uint64_t share_relays_lastsent; + + struct { + int (*status_callback)(void *object, int id, uint8_t status, void *userdata); + int (*data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + + void *callback_object; + int callback_id; + } callbacks[MAX_FRIEND_CONNECTION_CALLBACKS]; + + uint16_t lock_count; + + Node_format tcp_relays[FRIEND_MAX_STORED_TCP_RELAYS]; + uint16_t tcp_relay_counter; + + bool hosting_tcp_relay; +} Friend_Conn; + + +typedef struct { + Net_Crypto *net_crypto; + DHT *dht; + Onion_Client *onion_c; + + Friend_Conn *conns; + uint32_t num_cons; + + int (*fr_request_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t len, + void *userdata); + void *fr_request_object; + + uint64_t last_LANdiscovery; + uint16_t next_LANport; + + bool local_discovery_enabled; +} Friend_Connections; + +/* return friendcon_id corresponding to the real public key on success. + * return -1 on failure. + */ +int getfriend_conn_id_pk(Friend_Connections *fr_c, const uint8_t *real_pk); + +/* Increases lock_count for the connection with friendcon_id by 1. + * + * return 0 on success. + * return -1 on failure. + */ +int friend_connection_lock(Friend_Connections *fr_c, int friendcon_id); + +/* return FRIENDCONN_STATUS_CONNECTED if the friend is connected. + * return FRIENDCONN_STATUS_CONNECTING if the friend isn't connected. + * return FRIENDCONN_STATUS_NONE on failure. + */ +unsigned int friend_con_connected(Friend_Connections *fr_c, int friendcon_id); + +/* Copy public keys associated to friendcon_id. + * + * return 0 on success. + * return -1 on failure. + */ +int get_friendcon_public_keys(uint8_t *real_pk, uint8_t *dht_temp_pk, Friend_Connections *fr_c, int friendcon_id); + +/* Set temp dht key for connection. + */ +void set_dht_temp_pk(Friend_Connections *fr_c, int friendcon_id, const uint8_t *dht_temp_pk, void *userdata); + +/* Add a TCP relay associated to the friend. + * + * return -1 on failure. + * return 0 on success. + */ +int friend_add_tcp_relay(Friend_Connections *fr_c, int friendcon_id, IP_Port ip_port, const uint8_t *public_key); + +/* Set the callbacks for the friend connection. + * index is the index (0 to (MAX_FRIEND_CONNECTION_CALLBACKS - 1)) we want the callback to set in the array. + * + * return 0 on success. + * return -1 on failure + */ +int friend_connection_callbacks(Friend_Connections *fr_c, int friendcon_id, unsigned int index, + int (*status_callback)(void *object, int id, uint8_t status, void *userdata), + int (*data_callback)(void *object, int id, const uint8_t *data, uint16_t len, void *userdata), + int (*lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata), + void *object, int number); + +/* return the crypt_connection_id for the connection. + * + * return crypt_connection_id on success. + * return -1 on failure. + */ +int friend_connection_crypt_connection_id(Friend_Connections *fr_c, int friendcon_id); + +/* Create a new friend connection. + * If one to that real public key already exists, increase lock count and return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_friend_connection(Friend_Connections *fr_c, const uint8_t *real_public_key); + +/* Kill a friend connection. + * + * return -1 on failure. + * return 0 on success. + */ +int kill_friend_connection(Friend_Connections *fr_c, int friendcon_id); + +/* Send a Friend request packet. + * + * return -1 if failure. + * return 0 if it sent the friend request directly to the friend. + * return the number of peers it was routed through if it did not send it directly. + */ +int send_friend_request_packet(Friend_Connections *fr_c, int friendcon_id, uint32_t nospam_num, const uint8_t *data, + uint16_t length); + +/* Set friend request callback. + * + * This function will be called every time a friend request is received. + */ +void set_friend_request_callback(Friend_Connections *fr_c, int (*fr_request_callback)(void *, const uint8_t *, + const uint8_t *, uint16_t, void *), void *object); + +/* Create new friend_connections instance. */ +Friend_Connections *new_friend_connections(Onion_Client *onion_c, bool local_discovery_enabled); + +/* main friend_connections loop. */ +void do_friend_connections(Friend_Connections *fr_c, void *userdata); + +/* Free everything related with friend_connections. */ +void kill_friend_connections(Friend_Connections *fr_c); + +#endif diff --git a/libs/libtox/src/toxcore/friend_requests.c b/libs/libtox/src/toxcore/friend_requests.c new file mode 100644 index 0000000000..ba782e2b01 --- /dev/null +++ b/libs/libtox/src/toxcore/friend_requests.c @@ -0,0 +1,152 @@ +/* + * Handle friend requests. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "friend_requests.h" + +#include "util.h" + +/* Set and get the nospam variable used to prevent one type of friend request spam. */ +void set_nospam(Friend_Requests *fr, uint32_t num) +{ + fr->nospam = num; +} + +uint32_t get_nospam(const Friend_Requests *fr) +{ + return fr->nospam; +} + + +/* Set the function that will be executed when a friend request is received. */ +void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, size_t, + void *), void *object) +{ + fr->handle_friendrequest = function; + fr->handle_friendrequest_isset = 1; + fr->handle_friendrequest_object = object; +} +/* Set the function used to check if a friend request should be displayed to the user or not. */ +void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata) +{ + fr->filter_function = function; + fr->filter_function_userdata = userdata; +} + +/* Add to list of received friend requests. */ +static void addto_receivedlist(Friend_Requests *fr, const uint8_t *real_pk) +{ + if (fr->received_requests_index >= MAX_RECEIVED_STORED) { + fr->received_requests_index = 0; + } + + id_copy(fr->received_requests[fr->received_requests_index], real_pk); + ++fr->received_requests_index; +} + +/* Check if a friend request was already received. + * + * return 0 if it did not. + * return 1 if it did. + */ +static int request_received(Friend_Requests *fr, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < MAX_RECEIVED_STORED; ++i) { + if (id_equal(fr->received_requests[i], real_pk)) { + return 1; + } + } + + return 0; +} + +/* Remove real pk from received_requests list. + * + * return 0 if it removed it successfully. + * return -1 if it didn't find it. + */ +int remove_request_received(Friend_Requests *fr, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < MAX_RECEIVED_STORED; ++i) { + if (id_equal(fr->received_requests[i], real_pk)) { + crypto_memzero(fr->received_requests[i], CRYPTO_PUBLIC_KEY_SIZE); + return 0; + } + } + + return -1; +} + + +static int friendreq_handlepacket(void *object, const uint8_t *source_pubkey, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Friend_Requests *fr = (Friend_Requests *)object; + + if (length <= 1 + sizeof(fr->nospam) || length > ONION_CLIENT_MAX_DATA_SIZE) { + return 1; + } + + ++packet; + --length; + + if (fr->handle_friendrequest_isset == 0) { + return 1; + } + + if (request_received(fr, source_pubkey)) { + return 1; + } + + if (memcmp(packet, &fr->nospam, sizeof(fr->nospam)) != 0) { + return 1; + } + + if (fr->filter_function) { + if ((*fr->filter_function)(source_pubkey, fr->filter_function_userdata) != 0) { + return 1; + } + } + + addto_receivedlist(fr, source_pubkey); + + uint32_t message_len = length - sizeof(fr->nospam); + VLA(uint8_t, message, message_len + 1); + memcpy(message, packet + sizeof(fr->nospam), message_len); + message[SIZEOF_VLA(message) - 1] = 0; /* Be sure the message is null terminated. */ + + (*fr->handle_friendrequest)(fr->handle_friendrequest_object, source_pubkey, message, message_len, userdata); + return 0; +} + +void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c) +{ + set_friend_request_callback(fr_c, &friendreq_handlepacket, fr); +} diff --git a/libs/libtox/src/toxcore/friend_requests.h b/libs/libtox/src/toxcore/friend_requests.h new file mode 100644 index 0000000000..316e1c671f --- /dev/null +++ b/libs/libtox/src/toxcore/friend_requests.h @@ -0,0 +1,76 @@ +/* + * Handle friend requests. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef FRIEND_REQUESTS_H +#define FRIEND_REQUESTS_H + +#include "friend_connection.h" + +#define MAX_FRIEND_REQUEST_DATA_SIZE (ONION_CLIENT_MAX_DATA_SIZE - (1 + sizeof(uint32_t))) + +typedef struct { + uint32_t nospam; + void (*handle_friendrequest)(void *, const uint8_t *, const uint8_t *, size_t, void *); + uint8_t handle_friendrequest_isset; + void *handle_friendrequest_object; + + int (*filter_function)(const uint8_t *, void *); + void *filter_function_userdata; + /* NOTE: The following is just a temporary fix for the multiple friend requests received at the same time problem. + * TODO(irungentoo): Make this better (This will most likely tie in with the way we will handle spam.) + */ + +#define MAX_RECEIVED_STORED 32 + + uint8_t received_requests[MAX_RECEIVED_STORED][CRYPTO_PUBLIC_KEY_SIZE]; + uint16_t received_requests_index; +} Friend_Requests; + +/* Set and get the nospam variable used to prevent one type of friend request spam. */ +void set_nospam(Friend_Requests *fr, uint32_t num); +uint32_t get_nospam(const Friend_Requests *fr); + +/* Remove real_pk from received_requests list. + * + * return 0 if it removed it successfully. + * return -1 if it didn't find it. + */ +int remove_request_received(Friend_Requests *fr, const uint8_t *real_pk); + +/* Set the function that will be executed when a friend request for us is received. + * Function format is function(uint8_t * public_key, uint8_t * data, size_t length, void * userdata) + */ +void callback_friendrequest(Friend_Requests *fr, void (*function)(void *, const uint8_t *, const uint8_t *, size_t, + void *), void *object); + +/* Set the function used to check if a friend request should be displayed to the user or not. + * Function format is int function(uint8_t * public_key, void * userdata) + * It must return 0 if the request is ok (anything else if it is bad.) + */ +void set_filter_function(Friend_Requests *fr, int (*function)(const uint8_t *, void *), void *userdata); + +/* Sets up friendreq packet handlers. */ +void friendreq_init(Friend_Requests *fr, Friend_Connections *fr_c); + + +#endif diff --git a/libs/libtox/src/toxcore/group.c b/libs/libtox/src/toxcore/group.c new file mode 100644 index 0000000000..d3f068dfce --- /dev/null +++ b/libs/libtox/src/toxcore/group.c @@ -0,0 +1,2544 @@ +/* + * Slightly better groupchats implementation. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "group.h" + +#include "util.h" + +/* return 1 if the groupnumber is not valid. + * return 0 if the groupnumber is valid. + */ +static uint8_t groupnumber_not_valid(const Group_Chats *g_c, int groupnumber) +{ + if ((unsigned int)groupnumber >= g_c->num_chats) { + return 1; + } + + if (g_c->chats == NULL) { + return 1; + } + + if (g_c->chats[groupnumber].status == GROUPCHAT_STATUS_NONE) { + return 1; + } + + return 0; +} + + +/* Set the size of the groupchat list to num. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_groupchats(Group_Chats *g_c, uint32_t num) +{ + if (num == 0) { + free(g_c->chats); + g_c->chats = NULL; + return 0; + } + + Group_c *newgroup_chats = (Group_c *)realloc(g_c->chats, num * sizeof(Group_c)); + + if (newgroup_chats == NULL) { + return -1; + } + + g_c->chats = newgroup_chats; + return 0; +} + + +/* Create a new empty groupchat connection. + * + * return -1 on failure. + * return groupnumber on success. + */ +static int create_group_chat(Group_Chats *g_c) +{ + uint32_t i; + + for (i = 0; i < g_c->num_chats; ++i) { + if (g_c->chats[i].status == GROUPCHAT_STATUS_NONE) { + return i; + } + } + + int id = -1; + + if (realloc_groupchats(g_c, g_c->num_chats + 1) == 0) { + id = g_c->num_chats; + ++g_c->num_chats; + memset(&(g_c->chats[id]), 0, sizeof(Group_c)); + } + + return id; +} + + +/* Wipe a groupchat. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_group_chat(Group_Chats *g_c, int groupnumber) +{ + if (groupnumber_not_valid(g_c, groupnumber)) { + return -1; + } + + uint32_t i; + crypto_memzero(&(g_c->chats[groupnumber]), sizeof(Group_c)); + + for (i = g_c->num_chats; i != 0; --i) { + if (g_c->chats[i - 1].status != GROUPCHAT_STATUS_NONE) { + break; + } + } + + if (g_c->num_chats != i) { + g_c->num_chats = i; + realloc_groupchats(g_c, g_c->num_chats); + } + + return 0; +} + +static Group_c *get_group_c(const Group_Chats *g_c, int groupnumber) +{ + if (groupnumber_not_valid(g_c, groupnumber)) { + return 0; + } + + return &g_c->chats[groupnumber]; +} + +/* + * check if peer with real_pk is in peer array. + * + * return peer index if peer is in chat. + * return -1 if peer is not in chat. + * + * TODO(irungentoo): make this more efficient. + */ + +static int peer_in_chat(const Group_c *chat, const uint8_t *real_pk) +{ + uint32_t i; + + for (i = 0; i < chat->numpeers; ++i) { + if (id_equal(chat->group[i].real_pk, real_pk)) { + return i; + } + } + + return -1; +} + +/* + * check if group with identifier is in group array. + * + * return group number if peer is in list. + * return -1 if group is not in list. + * + * TODO(irungentoo): make this more efficient and maybe use constant time comparisons? + */ +static int get_group_num(const Group_Chats *g_c, const uint8_t *identifier) +{ + uint32_t i; + + for (i = 0; i < g_c->num_chats; ++i) { + if (crypto_memcmp(g_c->chats[i].identifier, identifier, GROUP_IDENTIFIER_LENGTH) == 0) { + return i; + } + } + + return -1; +} + +/* + * check if peer with peer_number is in peer array. + * + * return peer number if peer is in chat. + * return -1 if peer is not in chat. + * + * TODO(irungentoo): make this more efficient. + */ +static int get_peer_index(Group_c *g, uint16_t peer_number) +{ + uint32_t i; + + for (i = 0; i < g->numpeers; ++i) { + if (g->group[i].peer_number == peer_number) { + return i; + } + } + + return -1; +} + + +static uint64_t calculate_comp_value(const uint8_t *pk1, const uint8_t *pk2) +{ + uint64_t cmp1 = 0, cmp2 = 0; + + unsigned int i; + + for (i = 0; i < sizeof(uint64_t); ++i) { + cmp1 = (cmp1 << 8) + (uint64_t)pk1[i]; + cmp2 = (cmp2 << 8) + (uint64_t)pk2[i]; + } + + return (cmp1 - cmp2); +} + +enum { + GROUPCHAT_CLOSEST_NONE, + GROUPCHAT_CLOSEST_ADDED, + GROUPCHAT_CLOSEST_REMOVED +}; + +static int friend_in_close(Group_c *g, int friendcon_id); +static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest, uint8_t lock); + +static int add_to_closest(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (public_key_cmp(g->real_pk, real_pk) == 0) { + return -1; + } + + unsigned int i; + unsigned int index = DESIRED_CLOSE_CONNECTIONS; + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { + if (g->closest_peers[i].entry && public_key_cmp(real_pk, g->closest_peers[i].real_pk) == 0) { + return 0; + } + } + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { + if (g->closest_peers[i].entry == 0) { + index = i; + break; + } + } + + if (index == DESIRED_CLOSE_CONNECTIONS) { + uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk); + uint64_t comp_d = 0; + + for (i = 0; i < (DESIRED_CLOSE_CONNECTIONS / 2); ++i) { + uint64_t comp; + comp = calculate_comp_value(g->real_pk, g->closest_peers[i].real_pk); + + if (comp > comp_val && comp > comp_d) { + index = i; + comp_d = comp; + } + } + + comp_val = calculate_comp_value(real_pk, g->real_pk); + + for (i = (DESIRED_CLOSE_CONNECTIONS / 2); i < DESIRED_CLOSE_CONNECTIONS; ++i) { + uint64_t comp = calculate_comp_value(g->closest_peers[i].real_pk, g->real_pk); + + if (comp > comp_val && comp > comp_d) { + index = i; + comp_d = comp; + } + } + } + + if (index == DESIRED_CLOSE_CONNECTIONS) { + return -1; + } + + uint8_t old_real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t old_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t old = 0; + + if (g->closest_peers[index].entry) { + memcpy(old_real_pk, g->closest_peers[index].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(old_temp_pk, g->closest_peers[index].temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + old = 1; + } + + g->closest_peers[index].entry = 1; + memcpy(g->closest_peers[index].real_pk, real_pk, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(g->closest_peers[index].temp_pk, temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + + if (old) { + add_to_closest(g_c, groupnumber, old_real_pk, old_temp_pk); + } + + if (!g->changed) { + g->changed = GROUPCHAT_CLOSEST_ADDED; + } + + return 0; +} + +static unsigned int pk_in_closest_peers(Group_c *g, uint8_t *real_pk) +{ + unsigned int i; + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { + if (!g->closest_peers[i].entry) { + continue; + } + + if (public_key_cmp(g->closest_peers[i].real_pk, real_pk) == 0) { + return 1; + } + } + + return 0; +} + +static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier); + +static int connect_to_closest(Group_Chats *g_c, int groupnumber, void *userdata) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (!g->changed) { + return 0; + } + + unsigned int i; + + if (g->changed == GROUPCHAT_CLOSEST_REMOVED) { + for (i = 0; i < g->numpeers; ++i) { + add_to_closest(g_c, groupnumber, g->group[i].real_pk, g->group[i].temp_pk); + } + } + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + if (!g->close[i].closest) { + continue; + } + + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[i].number); + + if (!pk_in_closest_peers(g, real_pk)) { + g->close[i].type = GROUPCHAT_CLOSE_NONE; + kill_friend_connection(g_c->fr_c, g->close[i].number); + } + } + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { + if (!g->closest_peers[i].entry) { + continue; + } + + int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->closest_peers[i].real_pk); + + uint8_t lock = 1; + + if (friendcon_id == -1) { + friendcon_id = new_friend_connection(g_c->fr_c, g->closest_peers[i].real_pk); + lock = 0; + + if (friendcon_id == -1) { + continue; + } + + set_dht_temp_pk(g_c->fr_c, friendcon_id, g->closest_peers[i].temp_pk, userdata); + } + + add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 1, lock); + + if (friend_con_connected(g_c->fr_c, friendcon_id) == FRIENDCONN_STATUS_CONNECTED) { + send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); + } + } + + g->changed = GROUPCHAT_CLOSEST_NONE; + + return 0; +} + +/* Add a peer to the group chat. + * + * do_gc_callback indicates whether we want to trigger callbacks set by the client + * via the public API. This should be set to false if this function is called + * from outside of the tox_iterate() loop. + * + * return peer_index if success or peer already in chat. + * return -1 if error. + */ +static int addpeer(Group_Chats *g_c, int groupnumber, const uint8_t *real_pk, const uint8_t *temp_pk, + uint16_t peer_number, void *userdata, bool do_gc_callback) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + // TODO(irungentoo): + int peer_index = peer_in_chat(g, real_pk); + + if (peer_index != -1) { + id_copy(g->group[peer_index].temp_pk, temp_pk); + + if (g->group[peer_index].peer_number != peer_number) { + return -1; + } + + return peer_index; + } + + peer_index = get_peer_index(g, peer_number); + + if (peer_index != -1) { + return -1; + } + + Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers + 1)); + + if (temp == NULL) { + return -1; + } + + memset(&(temp[g->numpeers]), 0, sizeof(Group_Peer)); + g->group = temp; + + id_copy(g->group[g->numpeers].real_pk, real_pk); + id_copy(g->group[g->numpeers].temp_pk, temp_pk); + g->group[g->numpeers].peer_number = peer_number; + + g->group[g->numpeers].last_recv = unix_time(); + ++g->numpeers; + + add_to_closest(g_c, groupnumber, real_pk, temp_pk); + + if (do_gc_callback && g_c->group_namelistchange) { + g_c->group_namelistchange(g_c->m, groupnumber, g->numpeers - 1, CHAT_CHANGE_PEER_ADD, userdata); + } + + if (g->peer_on_join) { + g->peer_on_join(g->object, groupnumber, g->numpeers - 1); + } + + return (g->numpeers - 1); +} + +static int remove_close_conn(Group_Chats *g_c, int groupnumber, int friendcon_id) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint32_t i; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + if (g->close[i].number == (unsigned int)friendcon_id) { + g->close[i].type = GROUPCHAT_CLOSE_NONE; + kill_friend_connection(g_c->fr_c, friendcon_id); + return 0; + } + } + + return -1; +} + + +/* + * Delete a peer from the group chat. + * + * return 0 if success + * return -1 if error. + */ +static int delpeer(Group_Chats *g_c, int groupnumber, int peer_index, void *userdata) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint32_t i; + + for (i = 0; i < DESIRED_CLOSE_CONNECTIONS; ++i) { /* If peer is in closest_peers list, remove it. */ + if (g->closest_peers[i].entry && id_equal(g->closest_peers[i].real_pk, g->group[peer_index].real_pk)) { + g->closest_peers[i].entry = 0; + g->changed = GROUPCHAT_CLOSEST_REMOVED; + break; + } + } + + int friendcon_id = getfriend_conn_id_pk(g_c->fr_c, g->group[peer_index].real_pk); + + if (friendcon_id != -1) { + remove_close_conn(g_c, groupnumber, friendcon_id); + } + + --g->numpeers; + + void *peer_object = g->group[peer_index].object; + + if (g->numpeers == 0) { + free(g->group); + g->group = NULL; + } else { + if (g->numpeers != (uint32_t)peer_index) { + memcpy(&g->group[peer_index], &g->group[g->numpeers], sizeof(Group_Peer)); + } + + Group_Peer *temp = (Group_Peer *)realloc(g->group, sizeof(Group_Peer) * (g->numpeers)); + + if (temp == NULL) { + return -1; + } + + g->group = temp; + } + + if (g_c->group_namelistchange) { + g_c->group_namelistchange(g_c->m, groupnumber, peer_index, CHAT_CHANGE_PEER_DEL, userdata); + } + + if (g->peer_on_leave) { + g->peer_on_leave(g->object, groupnumber, peer_index, peer_object); + } + + return 0; +} + +/* Set the nick for a peer. + * + * do_gc_callback indicates whether we want to trigger callbacks set by the client + * via the public API. This should be set to false if this function is called + * from outside of the tox_iterate() loop. + * + * return 0 on success. + * return -1 if error. + */ +static int setnick(Group_Chats *g_c, int groupnumber, int peer_index, const uint8_t *nick, uint16_t nick_len, + void *userdata, bool do_gc_callback) +{ + if (nick_len > MAX_NAME_LENGTH) { + return -1; + } + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + /* same name as already stored? */ + if (g->group[peer_index].nick_len == nick_len) { + if (nick_len == 0 || !memcmp(g->group[peer_index].nick, nick, nick_len)) { + return 0; + } + } + + if (nick_len) { + memcpy(g->group[peer_index].nick, nick, nick_len); + } + + g->group[peer_index].nick_len = nick_len; + + if (do_gc_callback && g_c->group_namelistchange) { + g_c->group_namelistchange(g_c->m, groupnumber, peer_index, CHAT_CHANGE_PEER_NAME, userdata); + } + + return 0; +} + +static int settitle(Group_Chats *g_c, int groupnumber, int peer_index, const uint8_t *title, uint8_t title_len, + void *userdata) +{ + if (title_len > MAX_NAME_LENGTH || title_len == 0) { + return -1; + } + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + /* same as already set? */ + if (g->title_len == title_len && !memcmp(g->title, title, title_len)) { + return 0; + } + + memcpy(g->title, title, title_len); + g->title_len = title_len; + + if (g_c->title_callback) { + g_c->title_callback(g_c->m, groupnumber, peer_index, title, title_len, userdata); + } + + return 0; +} + +static void set_conns_type_close(Group_Chats *g_c, int groupnumber, int friendcon_id, uint8_t type) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return; + } + + uint32_t i; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + if (g->close[i].number != (unsigned int)friendcon_id) { + continue; + } + + if (type == GROUPCHAT_CLOSE_ONLINE) { + send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); + } else { + g->close[i].type = type; + } + } +} +/* Set the type for all close connections with friendcon_id */ +static void set_conns_status_groups(Group_Chats *g_c, int friendcon_id, uint8_t type) +{ + uint32_t i; + + for (i = 0; i < g_c->num_chats; ++i) { + set_conns_type_close(g_c, i, friendcon_id, type); + } +} + +static int g_handle_status(void *object, int friendcon_id, uint8_t status, void *userdata) +{ + Group_Chats *g_c = (Group_Chats *)object; + + if (status) { /* Went online */ + set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_ONLINE); + } else { /* Went offline */ + set_conns_status_groups(g_c, friendcon_id, GROUPCHAT_CLOSE_CONNECTION); + // TODO(irungentoo): remove timedout connections? + } + + return 0; +} + +static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata); +static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata); + +/* Add friend to group chat. + * + * return close index on success + * return -1 on failure. + */ +static int add_conn_to_groupchat(Group_Chats *g_c, int friendcon_id, int groupnumber, uint8_t closest, uint8_t lock) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint16_t i, ind = MAX_GROUP_CONNECTIONS; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + ind = i; + continue; + } + + if (g->close[i].number == (uint32_t)friendcon_id) { + g->close[i].closest = closest; + return i; /* Already in list. */ + } + } + + if (ind == MAX_GROUP_CONNECTIONS) { + return -1; + } + + if (lock) { + friend_connection_lock(g_c->fr_c, friendcon_id); + } + + g->close[ind].type = GROUPCHAT_CLOSE_CONNECTION; + g->close[ind].number = friendcon_id; + g->close[ind].closest = closest; + // TODO(irungentoo): + friend_connection_callbacks(g_c->m->fr_c, friendcon_id, GROUPCHAT_CALLBACK_INDEX, &g_handle_status, &g_handle_packet, + &handle_lossy, g_c, friendcon_id); + + return ind; +} + +/* Creates a new groupchat and puts it in the chats array. + * + * type is one of GROUPCHAT_TYPE_* + * + * return group number on success. + * return -1 on failure. + */ +int add_groupchat(Group_Chats *g_c, uint8_t type) +{ + int groupnumber = create_group_chat(g_c); + + if (groupnumber == -1) { + return -1; + } + + Group_c *g = &g_c->chats[groupnumber]; + + g->status = GROUPCHAT_STATUS_CONNECTED; + g->number_joined = -1; + new_symmetric_key(g->identifier + 1); + g->identifier[0] = type; + g->peer_number = 0; /* Founder is peer 0. */ + memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + int peer_index = addpeer(g_c, groupnumber, g->real_pk, g_c->m->dht->self_public_key, 0, NULL, false); + + if (peer_index == -1) { + return -1; + } + + setnick(g_c, groupnumber, peer_index, g_c->m->name, g_c->m->name_length, NULL, false); + + return groupnumber; +} + +static int group_kill_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num); +/* Delete a groupchat from the chats array. + * + * return 0 on success. + * return -1 if groupnumber is invalid. + */ +int del_groupchat(Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + group_kill_peer_send(g_c, groupnumber, g->peer_number); + + unsigned int i; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + g->close[i].type = GROUPCHAT_CLOSE_NONE; + kill_friend_connection(g_c->fr_c, g->close[i].number); + } + + for (i = 0; i < g->numpeers; ++i) { + if (g->peer_on_leave) { + g->peer_on_leave(g->object, groupnumber, i, g->group[i].object); + } + } + + free(g->group); + + if (g->group_on_delete) { + g->group_on_delete(g->object, groupnumber); + } + + return wipe_group_chat(g_c, groupnumber); +} + +/* Copy the public key of peernumber who is in groupnumber to pk. + * pk must be CRYPTO_PUBLIC_KEY_SIZE long. + * + * return 0 on success + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peer_pubkey(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *pk) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -2; + } + + memcpy(pk, g->group[peernumber].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + return 0; +} + +/* + * Return the size of peernumber's name. + * + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peername_size(const Group_Chats *g_c, int groupnumber, int peernumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -2; + } + + if (g->group[peernumber].nick_len == 0) { + return 8; + } + + return g->group[peernumber].nick_len; +} + +/* Copy the name of peernumber who is in groupnumber to name. + * name must be at least MAX_NAME_LENGTH long. + * + * return length of name if success + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peername(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *name) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -2; + } + + if (g->group[peernumber].nick_len == 0) { + memcpy(name, "Tox User", 8); + return 8; + } + + memcpy(name, g->group[peernumber].nick, g->group[peernumber].nick_len); + return g->group[peernumber].nick_len; +} + +/* List all the peers in the group chat. + * + * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. + * + * Copies the lengths of the names to lengths[length] + * + * returns the number of peers on success. + * + * return -1 on failure. + */ +int group_names(const Group_Chats *g_c, int groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[], + uint16_t length) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + unsigned int i; + + for (i = 0; i < g->numpeers && i < length; ++i) { + lengths[i] = group_peername(g_c, groupnumber, i, names[i]); + } + + return i; +} + +/* Return the number of peers in the group chat on success. + * return -1 if groupnumber is invalid. + */ +int group_number_peers(const Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + return g->numpeers; +} + +/* return 1 if the peernumber corresponds to ours. + * return 0 if the peernumber is not ours. + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + * return -3 if we are not connected to the group chat. + */ +int group_peernumber_is_ours(const Group_Chats *g_c, int groupnumber, int peernumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -2; + } + + if (g->status != GROUPCHAT_STATUS_CONNECTED) { + return -3; + } + + return g->peer_number == g->group[peernumber].peer_number; +} + +/* return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is. + * + * return -1 on failure. + * return type on success. + */ +int group_get_type(const Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + return g->identifier[0]; +} + +/* Send a group packet to friendcon_id. + * + * return 1 on success + * return 0 on failure + */ +static unsigned int send_packet_group_peer(Friend_Connections *fr_c, int friendcon_id, uint8_t packet_id, + uint16_t group_num, const uint8_t *data, uint16_t length) +{ + if (1 + sizeof(uint16_t) + length > MAX_CRYPTO_DATA_SIZE) { + return 0; + } + + group_num = net_htons(group_num); + VLA(uint8_t, packet, 1 + sizeof(uint16_t) + length); + packet[0] = packet_id; + memcpy(packet + 1, &group_num, sizeof(uint16_t)); + memcpy(packet + 1 + sizeof(uint16_t), data, length); + return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet, + SIZEOF_VLA(packet), 0) != -1; +} + +/* Send a group lossy packet to friendcon_id. + * + * return 1 on success + * return 0 on failure + */ +static unsigned int send_lossy_group_peer(Friend_Connections *fr_c, int friendcon_id, uint8_t packet_id, + uint16_t group_num, const uint8_t *data, uint16_t length) +{ + if (1 + sizeof(uint16_t) + length > MAX_CRYPTO_DATA_SIZE) { + return 0; + } + + group_num = net_htons(group_num); + VLA(uint8_t, packet, 1 + sizeof(uint16_t) + length); + packet[0] = packet_id; + memcpy(packet + 1, &group_num, sizeof(uint16_t)); + memcpy(packet + 1 + sizeof(uint16_t), data, length); + return send_lossy_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet, + SIZEOF_VLA(packet)) != -1; +} + +#define INVITE_PACKET_SIZE (1 + sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) +#define INVITE_ID 0 + +#define INVITE_RESPONSE_PACKET_SIZE (1 + sizeof(uint16_t) * 2 + GROUP_IDENTIFIER_LENGTH) +#define INVITE_RESPONSE_ID 1 + +/* invite friendnumber to groupnumber. + * + * return 0 on success. + * return -1 if groupnumber is invalid. + * return -2 if invite packet failed to send. + */ +int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint8_t invite[INVITE_PACKET_SIZE]; + invite[0] = INVITE_ID; + uint16_t groupchat_num = net_htons((uint16_t)groupnumber); + memcpy(invite + 1, &groupchat_num, sizeof(groupchat_num)); + memcpy(invite + 1 + sizeof(groupchat_num), g->identifier, GROUP_IDENTIFIER_LENGTH); + + if (send_conference_invite_packet(g_c->m, friendnumber, invite, sizeof(invite))) { + return 0; + } + + wipe_group_chat(g_c, groupnumber); + return -2; +} + +static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num); + +/* Join a group (you need to have been invited first.) + * + * expected_type is the groupchat type we expect the chat we are joining is. + * + * return group number on success. + * return -1 if data length is invalid. + * return -2 if group is not the expected type. + * return -3 if friendnumber is invalid. + * return -4 if client is already in this group. + * return -5 if group instance failed to initialize. + * return -6 if join packet fails to send. + */ +int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t expected_type, const uint8_t *data, uint16_t length) +{ + if (length != sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) { + return -1; + } + + if (data[sizeof(uint16_t)] != expected_type) { + return -2; + } + + int friendcon_id = getfriendcon_id(g_c->m, friendnumber); + + if (friendcon_id == -1) { + return -3; + } + + if (get_group_num(g_c, data + sizeof(uint16_t)) != -1) { + return -4; + } + + int groupnumber = create_group_chat(g_c); + + if (groupnumber == -1) { + return -5; + } + + Group_c *g = &g_c->chats[groupnumber]; + + uint16_t group_num = net_htons(groupnumber); + g->status = GROUPCHAT_STATUS_VALID; + g->number_joined = -1; + memcpy(g->real_pk, g_c->m->net_crypto->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + uint8_t response[INVITE_RESPONSE_PACKET_SIZE]; + response[0] = INVITE_RESPONSE_ID; + memcpy(response + 1, &group_num, sizeof(uint16_t)); + memcpy(response + 1 + sizeof(uint16_t), data, sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH); + + if (send_conference_invite_packet(g_c->m, friendnumber, response, sizeof(response))) { + uint16_t other_groupnum; + memcpy(&other_groupnum, data, sizeof(other_groupnum)); + other_groupnum = net_ntohs(other_groupnum); + memcpy(g->identifier, data + sizeof(uint16_t), GROUP_IDENTIFIER_LENGTH); + int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnumber, 0, 1); + + if (close_index != -1) { + g->close[close_index].group_number = other_groupnum; + g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; + g->number_joined = friendcon_id; + } + + send_peer_query(g_c, friendcon_id, other_groupnum); + return groupnumber; + } + + g->status = GROUPCHAT_STATUS_NONE; + return -6; +} + +/* Set handlers for custom lossy packets. + * + * NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object), const uint8_t *packet, uint16_t length) + */ +void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, int (*function)(void *, int, int, void *, + const uint8_t *, uint16_t)) +{ + g_c->lossy_packethandlers[byte].function = function; +} + +/* Set the callback for group invites. + * + * Function(Group_Chats *g_c, int32_t friendnumber, uint8_t type, uint8_t *data, uint16_t length, void *userdata) + * + * data of length is what needs to be passed to join_groupchat(). + */ +void g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, int, const uint8_t *, + size_t, void *)) +{ + g_c->invite_callback = function; +} + +/* Set the callback for group messages. + * + * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) + */ +void g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, uint32_t, int, const uint8_t *, + size_t, void *)) +{ + g_c->message_callback = function; +} + +/* Set callback function for peer name list changes. + * + * It gets called every time the name list changes(new peer/name, deleted peer) + * Function(Group_Chats *g_c, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata) + */ +void g_callback_group_namelistchange(Group_Chats *g_c, void (*function)(Messenger *m, int, int, uint8_t, void *)) +{ + g_c->group_namelistchange = function; +} + +/* Set callback function for title changes. + * + * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * title, uint8_t length, void *userdata) + * if friendgroupnumber == -1, then author is unknown (e.g. initial joining the group) + */ +void g_callback_group_title(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, uint32_t, const uint8_t *, + size_t, void *)) +{ + g_c->title_callback = function; +} + +/* Set a function to be called when a new peer joins a group chat. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_peer_new(const Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int)) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + g->peer_on_join = function; + return 0; +} + +/* Set a function to be called when a peer leaves a group chat. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object)) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_peer_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int, void *)) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + g->peer_on_leave = function; + return 0; +} + +/* Set a function to be called when the group chat is deleted. + * + * Function(void *group object (set with group_set_object), int groupnumber) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int)) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + g->group_on_delete = function; + return 0; +} + +static int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data, + uint16_t len); + +#define GROUP_MESSAGE_PING_ID 0 +static int group_ping_send(const Group_Chats *g_c, int groupnumber) +{ + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_PING_ID, 0, 0) > 0) { + return 0; + } + + return -1; +} + +#define GROUP_MESSAGE_NEW_PEER_ID 16 +#define GROUP_MESSAGE_NEW_PEER_LENGTH (sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE * 2) +/* send a new_peer message + * return 0 on success + * return -1 on failure + */ +static int group_new_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num, const uint8_t *real_pk, + uint8_t *temp_pk) +{ + uint8_t packet[GROUP_MESSAGE_NEW_PEER_LENGTH]; + + peer_num = net_htons(peer_num); + memcpy(packet, &peer_num, sizeof(uint16_t)); + memcpy(packet + sizeof(uint16_t), real_pk, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE, temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NEW_PEER_ID, packet, sizeof(packet)) > 0) { + return 0; + } + + return -1; +} + +#define GROUP_MESSAGE_KILL_PEER_ID 17 +#define GROUP_MESSAGE_KILL_PEER_LENGTH (sizeof(uint16_t)) + +/* send a kill_peer message + * return 0 on success + * return -1 on failure + */ +static int group_kill_peer_send(const Group_Chats *g_c, int groupnumber, uint16_t peer_num) +{ + uint8_t packet[GROUP_MESSAGE_KILL_PEER_LENGTH]; + + peer_num = net_htons(peer_num); + memcpy(packet, &peer_num, sizeof(uint16_t)); + + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_KILL_PEER_ID, packet, sizeof(packet)) > 0) { + return 0; + } + + return -1; +} + +#define GROUP_MESSAGE_NAME_ID 48 + +/* send a name message + * return 0 on success + * return -1 on failure + */ +static int group_name_send(const Group_Chats *g_c, int groupnumber, const uint8_t *nick, uint16_t nick_len) +{ + if (nick_len > MAX_NAME_LENGTH) { + return -1; + } + + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_NAME_ID, nick, nick_len) > 0) { + return 0; + } + + return -1; +} + +#define GROUP_MESSAGE_TITLE_ID 49 + +/* set the group's title, limited to MAX_NAME_LENGTH + * return 0 on success + * return -1 if groupnumber is invalid. + * return -2 if title is too long or empty. + * return -3 if packet fails to send. + */ +int group_title_send(const Group_Chats *g_c, int groupnumber, const uint8_t *title, uint8_t title_len) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (title_len > MAX_NAME_LENGTH || title_len == 0) { + return -2; + } + + /* same as already set? */ + if (g->title_len == title_len && !memcmp(g->title, title, title_len)) { + return 0; + } + + memcpy(g->title, title, title_len); + g->title_len = title_len; + + if (g->numpeers == 1) { + return 0; + } + + if (send_message_group(g_c, groupnumber, GROUP_MESSAGE_TITLE_ID, title, title_len) > 0) { + return 0; + } + + return -3; +} + +/* return the group's title size. + * return -1 of groupnumber is invalid. + * return -2 if title is too long or empty. + */ +int group_title_get_size(const Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (g->title_len == 0 || g->title_len > MAX_NAME_LENGTH) { + return -2; + } + + return g->title_len; +} + +/* Get group title from groupnumber and put it in title. + * Title needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. + * + * return length of copied title if success. + * return -1 if groupnumber is invalid. + * return -2 if title is too long or empty. + */ +int group_title_get(const Group_Chats *g_c, int groupnumber, uint8_t *title) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (g->title_len == 0 || g->title_len > MAX_NAME_LENGTH) { + return -2; + } + + memcpy(title, g->title, g->title_len); + return g->title_len; +} + +static void handle_friend_invite_packet(Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, + void *userdata) +{ + Group_Chats *g_c = (Group_Chats *)m->conferences_object; + + if (length <= 1) { + return; + } + + const uint8_t *invite_data = data + 1; + uint16_t invite_length = length - 1; + + switch (data[0]) { + case INVITE_ID: { + if (length != INVITE_PACKET_SIZE) { + return; + } + + int groupnumber = get_group_num(g_c, data + 1 + sizeof(uint16_t)); + + if (groupnumber == -1) { + if (g_c->invite_callback) { + g_c->invite_callback(m, friendnumber, *(invite_data + sizeof(uint16_t)), invite_data, invite_length, userdata); + } + + return; + } + + break; + } + + case INVITE_RESPONSE_ID: { + if (length != INVITE_RESPONSE_PACKET_SIZE) { + return; + } + + uint16_t other_groupnum, groupnum; + memcpy(&groupnum, data + 1 + sizeof(uint16_t), sizeof(uint16_t)); + groupnum = net_ntohs(groupnum); + + Group_c *g = get_group_c(g_c, groupnum); + + if (!g) { + return; + } + + if (crypto_memcmp(data + 1 + sizeof(uint16_t) * 2, g->identifier, GROUP_IDENTIFIER_LENGTH) != 0) { + return; + } + + /* TODO(irungentoo): what if two people enter the group at the same time and + are given the same peer_number by different nodes? */ + uint16_t peer_number = rand(); + + unsigned int tries = 0; + + while (get_peer_index(g, peer_number) != -1) { + peer_number = rand(); + ++tries; + + if (tries > 32) { + return; + } + } + + memcpy(&other_groupnum, data + 1, sizeof(uint16_t)); + other_groupnum = net_ntohs(other_groupnum); + + int friendcon_id = getfriendcon_id(m, friendnumber); + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE], temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + get_friendcon_public_keys(real_pk, temp_pk, g_c->fr_c, friendcon_id); + + addpeer(g_c, groupnum, real_pk, temp_pk, peer_number, userdata, true); + int close_index = add_conn_to_groupchat(g_c, friendcon_id, groupnum, 0, 1); + + if (close_index != -1) { + g->close[close_index].group_number = other_groupnum; + g->close[close_index].type = GROUPCHAT_CLOSE_ONLINE; + } + + group_new_peer_send(g_c, groupnum, peer_number, real_pk, temp_pk); + break; + } + + default: + return; + } +} + +/* Find index of friend in the close list; + * + * returns index on success + * returns -1 on failure. + */ +static int friend_in_close(Group_c *g, int friendcon_id) +{ + unsigned int i; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_NONE) { + continue; + } + + if (g->close[i].number != (uint32_t)friendcon_id) { + continue; + } + + return i; + } + + return -1; +} + +/* return number of connected close connections. + */ +static unsigned int count_close_connected(Group_c *g) +{ + unsigned int i, count = 0; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type == GROUPCHAT_CLOSE_ONLINE) { + ++count; + } + } + + return count; +} + +#define ONLINE_PACKET_DATA_SIZE (sizeof(uint16_t) + GROUP_IDENTIFIER_LENGTH) + +static int send_packet_online(Friend_Connections *fr_c, int friendcon_id, uint16_t group_num, uint8_t *identifier) +{ + uint8_t packet[1 + ONLINE_PACKET_DATA_SIZE]; + group_num = net_htons(group_num); + packet[0] = PACKET_ID_ONLINE_PACKET; + memcpy(packet + 1, &group_num, sizeof(uint16_t)); + memcpy(packet + 1 + sizeof(uint16_t), identifier, GROUP_IDENTIFIER_LENGTH); + return write_cryptpacket(fr_c->net_crypto, friend_connection_crypt_connection_id(fr_c, friendcon_id), packet, + sizeof(packet), 0) != -1; +} + +static unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num); + +static int handle_packet_online(Group_Chats *g_c, int friendcon_id, const uint8_t *data, uint16_t length) +{ + if (length != ONLINE_PACKET_DATA_SIZE) { + return -1; + } + + int groupnumber = get_group_num(g_c, data + sizeof(uint16_t)); + uint16_t other_groupnum; + memcpy(&other_groupnum, data, sizeof(uint16_t)); + other_groupnum = net_ntohs(other_groupnum); + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + int index = friend_in_close(g, friendcon_id); + + if (index == -1) { + return -1; + } + + if (g->close[index].type == GROUPCHAT_CLOSE_ONLINE) { + return -1; + } + + if (count_close_connected(g) == 0) { + send_peer_query(g_c, friendcon_id, other_groupnum); + } + + g->close[index].group_number = other_groupnum; + g->close[index].type = GROUPCHAT_CLOSE_ONLINE; + send_packet_online(g_c->fr_c, friendcon_id, groupnumber, g->identifier); + + if (g->number_joined != -1 && count_close_connected(g) >= DESIRED_CLOSE_CONNECTIONS) { + int fr_close_index = friend_in_close(g, g->number_joined); + + if (fr_close_index == -1) { + return -1; + } + + if (!g->close[fr_close_index].closest) { + g->close[fr_close_index].type = GROUPCHAT_CLOSE_NONE; + send_peer_kill(g_c, g->close[fr_close_index].number, g->close[fr_close_index].group_number); + kill_friend_connection(g_c->fr_c, g->close[fr_close_index].number); + g->number_joined = -1; + } + } + + return 0; +} + +#define PEER_KILL_ID 1 +#define PEER_QUERY_ID 8 +#define PEER_RESPONSE_ID 9 +#define PEER_TITLE_ID 10 +// we could send title with invite, but then if it changes between sending and accepting inv, joinee won't see it + +/* return 1 on success. + * return 0 on failure + */ +static unsigned int send_peer_kill(Group_Chats *g_c, int friendcon_id, uint16_t group_num) +{ + uint8_t packet[1]; + packet[0] = PEER_KILL_ID; + return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, sizeof(packet)); +} + + +/* return 1 on success. + * return 0 on failure + */ +static unsigned int send_peer_query(Group_Chats *g_c, int friendcon_id, uint16_t group_num) +{ + uint8_t packet[1]; + packet[0] = PEER_QUERY_ID; + return send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, sizeof(packet)); +} + +/* return number of peers sent on success. + * return 0 on failure. + */ +static unsigned int send_peers(Group_Chats *g_c, int groupnumber, int friendcon_id, uint16_t group_num) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint8_t packet[MAX_CRYPTO_DATA_SIZE - (1 + sizeof(uint16_t))]; + packet[0] = PEER_RESPONSE_ID; + uint8_t *p = packet + 1; + + uint16_t sent = 0; + unsigned int i; + + for (i = 0; i < g->numpeers; ++i) { + if ((p - packet) + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE * 2 + 1 + g->group[i].nick_len > sizeof(packet)) { + if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, (p - packet))) { + sent = i; + } else { + return sent; + } + + p = packet + 1; + } + + uint16_t peer_num = net_htons(g->group[i].peer_number); + memcpy(p, &peer_num, sizeof(peer_num)); + p += sizeof(peer_num); + memcpy(p, g->group[i].real_pk, CRYPTO_PUBLIC_KEY_SIZE); + p += CRYPTO_PUBLIC_KEY_SIZE; + memcpy(p, g->group[i].temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + p += CRYPTO_PUBLIC_KEY_SIZE; + *p = g->group[i].nick_len; + p += 1; + memcpy(p, g->group[i].nick, g->group[i].nick_len); + p += g->group[i].nick_len; + } + + if (sent != i) { + if (send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, packet, (p - packet))) { + sent = i; + } + } + + if (g->title_len) { + VLA(uint8_t, Packet, 1 + g->title_len); + Packet[0] = PEER_TITLE_ID; + memcpy(Packet + 1, g->title, g->title_len); + send_packet_group_peer(g_c->fr_c, friendcon_id, PACKET_ID_DIRECT_CONFERENCE, group_num, Packet, SIZEOF_VLA(Packet)); + } + + return sent; +} + +static int handle_send_peers(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0) { + return -1; + } + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + const uint8_t *d = data; + + while ((unsigned int)(length - (d - data)) >= sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE * 2 + 1) { + uint16_t peer_num; + memcpy(&peer_num, d, sizeof(peer_num)); + peer_num = net_ntohs(peer_num); + d += sizeof(uint16_t); + int peer_index = addpeer(g_c, groupnumber, d, d + CRYPTO_PUBLIC_KEY_SIZE, peer_num, userdata, true); + + if (peer_index == -1) { + return -1; + } + + if (g->status == GROUPCHAT_STATUS_VALID + && public_key_cmp(d, g_c->m->net_crypto->self_public_key) == 0) { + g->peer_number = peer_num; + g->status = GROUPCHAT_STATUS_CONNECTED; + group_name_send(g_c, groupnumber, g_c->m->name, g_c->m->name_length); + } + + d += CRYPTO_PUBLIC_KEY_SIZE * 2; + uint8_t name_length = *d; + d += 1; + + if (name_length > (length - (d - data)) || name_length > MAX_NAME_LENGTH) { + return -1; + } + + setnick(g_c, groupnumber, peer_index, d, name_length, userdata, true); + d += name_length; + } + + return 0; +} + +static void handle_direct_packet(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, + int close_index, void *userdata) +{ + if (length == 0) { + return; + } + + switch (data[0]) { + case PEER_KILL_ID: { + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return; + } + + if (!g->close[close_index].closest) { + g->close[close_index].type = GROUPCHAT_CLOSE_NONE; + kill_friend_connection(g_c->fr_c, g->close[close_index].number); + } + } + + break; + + case PEER_QUERY_ID: { + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return; + } + + send_peers(g_c, groupnumber, g->close[close_index].number, g->close[close_index].group_number); + } + + break; + + case PEER_RESPONSE_ID: { + handle_send_peers(g_c, groupnumber, data + 1, length - 1, userdata); + } + + break; + + case PEER_TITLE_ID: { + settitle(g_c, groupnumber, -1, data + 1, length - 1, userdata); + } + + break; + } +} + +#define MIN_MESSAGE_PACKET_LEN (sizeof(uint16_t) * 2 + sizeof(uint32_t) + 1) + +/* Send message to all close except receiver (if receiver isn't -1) + * NOTE: this function appends the group chat number to the data passed to it. + * + * return number of messages sent. + */ +static unsigned int send_message_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data, + uint16_t length, int receiver) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return 0; + } + + uint16_t i, sent = 0; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE) { + continue; + } + + if ((int)i == receiver) { + continue; + } + + if (send_packet_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_MESSAGE_CONFERENCE, g->close[i].group_number, data, + length)) { + ++sent; + } + } + + return sent; +} + +/* Send lossy message to all close except receiver (if receiver isn't -1) + * NOTE: this function appends the group chat number to the data passed to it. + * + * return number of messages sent. + */ +static unsigned int send_lossy_all_close(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, + int receiver) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return 0; + } + + unsigned int i, sent = 0, num_connected_closest = 0, connected_closest[DESIRED_CLOSE_CONNECTIONS]; + + for (i = 0; i < MAX_GROUP_CONNECTIONS; ++i) { + if (g->close[i].type != GROUPCHAT_CLOSE_ONLINE) { + continue; + } + + if ((int)i == receiver) { + continue; + } + + if (g->close[i].closest) { + connected_closest[num_connected_closest] = i; + ++num_connected_closest; + continue; + } + + if (send_lossy_group_peer(g_c->fr_c, g->close[i].number, PACKET_ID_LOSSY_CONFERENCE, g->close[i].group_number, data, + length)) { + ++sent; + } + } + + if (!num_connected_closest) { + return sent; + } + + unsigned int to_send = 0; + uint64_t comp_val_old = ~0; + + for (i = 0; i < num_connected_closest; ++i) { + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number); + uint64_t comp_val = calculate_comp_value(g->real_pk, real_pk); + + if (comp_val < comp_val_old) { + to_send = connected_closest[i]; + comp_val_old = comp_val; + } + } + + if (send_lossy_group_peer(g_c->fr_c, g->close[to_send].number, PACKET_ID_LOSSY_CONFERENCE, + g->close[to_send].group_number, data, length)) { + ++sent; + } + + unsigned int to_send_other = 0; + comp_val_old = ~0; + + for (i = 0; i < num_connected_closest; ++i) { + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + get_friendcon_public_keys(real_pk, dht_temp_pk, g_c->fr_c, g->close[connected_closest[i]].number); + uint64_t comp_val = calculate_comp_value(real_pk, g->real_pk); + + if (comp_val < comp_val_old) { + to_send_other = connected_closest[i]; + comp_val_old = comp_val; + } + } + + if (to_send_other == to_send) { + return sent; + } + + if (send_lossy_group_peer(g_c->fr_c, g->close[to_send_other].number, PACKET_ID_LOSSY_CONFERENCE, + g->close[to_send_other].group_number, data, length)) { + ++sent; + } + + return sent; +} + +#define MAX_GROUP_MESSAGE_DATA_LEN (MAX_CRYPTO_DATA_SIZE - (1 + MIN_MESSAGE_PACKET_LEN)) + +/* Send data of len with message_id to groupnumber. + * + * return number of peers it was sent to on success. + * return -1 if groupnumber is invalid. + * return -2 if message is too long. + * return -3 if we are not connected to the group. + * reutrn -4 if message failed to send. + */ +static int send_message_group(const Group_Chats *g_c, int groupnumber, uint8_t message_id, const uint8_t *data, + uint16_t len) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (len > MAX_GROUP_MESSAGE_DATA_LEN) { + return -2; + } + + if (g->status != GROUPCHAT_STATUS_CONNECTED) { + return -3; + } + + VLA(uint8_t, packet, sizeof(uint16_t) + sizeof(uint32_t) + 1 + len); + uint16_t peer_num = net_htons(g->peer_number); + memcpy(packet, &peer_num, sizeof(peer_num)); + + ++g->message_number; + + if (!g->message_number) { + ++g->message_number; + } + + uint32_t message_num = net_htonl(g->message_number); + memcpy(packet + sizeof(uint16_t), &message_num, sizeof(message_num)); + + packet[sizeof(uint16_t) + sizeof(uint32_t)] = message_id; + + if (len) { + memcpy(packet + sizeof(uint16_t) + sizeof(uint32_t) + 1, data, len); + } + + unsigned int ret = send_message_all_close(g_c, groupnumber, packet, SIZEOF_VLA(packet), -1); + + return (ret == 0) ? -4 : ret; +} + +/* send a group message + * return 0 on success + * see: send_message_group() for error codes. + */ +int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length) +{ + int ret = send_message_group(g_c, groupnumber, PACKET_ID_MESSAGE, message, length); + + if (ret > 0) { + return 0; + } + + return ret; +} + +/* send a group action + * return 0 on success + * see: send_message_group() for error codes. + */ +int group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length) +{ + int ret = send_message_group(g_c, groupnumber, PACKET_ID_ACTION, action, length); + + if (ret > 0) { + return 0; + } + + return ret; +} + +/* High level function to send custom lossy packets. + * + * return -1 on failure. + * return 0 on success. + */ +int send_group_lossy_packet(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length) +{ + // TODO(irungentoo): length check here? + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + VLA(uint8_t, packet, sizeof(uint16_t) * 2 + length); + uint16_t peer_number = net_htons(g->peer_number); + memcpy(packet, &peer_number, sizeof(uint16_t)); + uint16_t message_num = net_htons(g->lossy_message_number); + memcpy(packet + sizeof(uint16_t), &message_num, sizeof(uint16_t)); + memcpy(packet + sizeof(uint16_t) * 2, data, length); + + if (send_lossy_all_close(g_c, groupnumber, packet, SIZEOF_VLA(packet), -1) == 0) { + return -1; + } + + ++g->lossy_message_number; + return 0; +} + +static void handle_message_packet_group(Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length, + int close_index, void *userdata) +{ + if (length < sizeof(uint16_t) + sizeof(uint32_t) + 1) { + return; + } + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return; + } + + uint16_t peer_number; + memcpy(&peer_number, data, sizeof(uint16_t)); + peer_number = net_ntohs(peer_number); + + int index = get_peer_index(g, peer_number); + + if (index == -1) { + /* We don't know the peer this packet came from so we query the list of peers from that peer. + (They would not have relayed it if they didn't know the peer.) */ + send_peer_query(g_c, g->close[close_index].number, g->close[close_index].group_number); + return; + } + + uint32_t message_number; + memcpy(&message_number, data + sizeof(uint16_t), sizeof(message_number)); + message_number = net_ntohl(message_number); + + if (g->group[index].last_message_number == 0) { + g->group[index].last_message_number = message_number; + } else if (message_number - g->group[index].last_message_number > 64 || + message_number == g->group[index].last_message_number) { + return; + } + + g->group[index].last_message_number = message_number; + + uint8_t message_id = data[sizeof(uint16_t) + sizeof(message_number)]; + const uint8_t *msg_data = data + sizeof(uint16_t) + sizeof(message_number) + 1; + uint16_t msg_data_len = length - (sizeof(uint16_t) + sizeof(message_number) + 1); + + switch (message_id) { + case GROUP_MESSAGE_PING_ID: { + if (msg_data_len != 0) { + return; + } + + g->group[index].last_recv = unix_time(); + } + break; + + case GROUP_MESSAGE_NEW_PEER_ID: { + if (msg_data_len != GROUP_MESSAGE_NEW_PEER_LENGTH) { + return; + } + + uint16_t new_peer_number; + memcpy(&new_peer_number, msg_data, sizeof(uint16_t)); + new_peer_number = net_ntohs(new_peer_number); + addpeer(g_c, groupnumber, msg_data + sizeof(uint16_t), msg_data + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE, + new_peer_number, userdata, true); + } + break; + + case GROUP_MESSAGE_KILL_PEER_ID: { + if (msg_data_len != GROUP_MESSAGE_KILL_PEER_LENGTH) { + return; + } + + uint16_t kill_peer_number; + memcpy(&kill_peer_number, msg_data, sizeof(uint16_t)); + kill_peer_number = net_ntohs(kill_peer_number); + + if (peer_number == kill_peer_number) { + delpeer(g_c, groupnumber, index, userdata); + } else { + return; + // TODO(irungentoo): + } + } + break; + + case GROUP_MESSAGE_NAME_ID: { + if (setnick(g_c, groupnumber, index, msg_data, msg_data_len, userdata, true) == -1) { + return; + } + } + break; + + case GROUP_MESSAGE_TITLE_ID: { + if (settitle(g_c, groupnumber, index, msg_data, msg_data_len, userdata) == -1) { + return; + } + } + break; + + case PACKET_ID_MESSAGE: { + if (msg_data_len == 0) { + return; + } + + VLA(uint8_t, newmsg, msg_data_len + 1); + memcpy(newmsg, msg_data, msg_data_len); + newmsg[msg_data_len] = 0; + + // TODO(irungentoo): + if (g_c->message_callback) { + g_c->message_callback(g_c->m, groupnumber, index, 0, newmsg, msg_data_len, userdata); + } + + break; + } + + case PACKET_ID_ACTION: { + if (msg_data_len == 0) { + return; + } + + VLA(uint8_t, newmsg, msg_data_len + 1); + memcpy(newmsg, msg_data, msg_data_len); + newmsg[msg_data_len] = 0; + + // TODO(irungentoo): + if (g_c->message_callback) { + g_c->message_callback(g_c->m, groupnumber, index, 1, newmsg, msg_data_len, userdata); + } + + break; + } + + default: + return; + } + + send_message_all_close(g_c, groupnumber, data, length, -1/* TODO(irungentoo) close_index */); +} + +static int g_handle_packet(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata) +{ + Group_Chats *g_c = (Group_Chats *)object; + + if (length < 1 + sizeof(uint16_t) + 1) { + return -1; + } + + if (data[0] == PACKET_ID_ONLINE_PACKET) { + return handle_packet_online(g_c, friendcon_id, data + 1, length - 1); + } + + if (data[0] != PACKET_ID_DIRECT_CONFERENCE && data[0] != PACKET_ID_MESSAGE_CONFERENCE) { + return -1; + } + + uint16_t groupnumber; + memcpy(&groupnumber, data + 1, sizeof(uint16_t)); + groupnumber = net_ntohs(groupnumber); + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + int index = friend_in_close(g, friendcon_id); + + if (index == -1) { + return -1; + } + + switch (data[0]) { + case PACKET_ID_DIRECT_CONFERENCE: { + handle_direct_packet(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index, userdata); + break; + } + + case PACKET_ID_MESSAGE_CONFERENCE: { + handle_message_packet_group(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index, + userdata); + break; + } + + default: { + return 0; + } + } + + return 0; +} + +/* Did we already receive the lossy packet or not. + * + * return -1 on failure. + * return 0 if packet was not received. + * return 1 if packet was received. + * + * TODO(irungentoo): test this + */ +static unsigned int lossy_packet_not_received(Group_c *g, int peer_index, uint16_t message_number) +{ + if (peer_index == -1) { + return -1; + } + + if (g->group[peer_index].bottom_lossy_number == g->group[peer_index].top_lossy_number) { + g->group[peer_index].top_lossy_number = message_number; + g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1; + g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; + return 0; + } + + if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) < MAX_LOSSY_COUNT) { + if (g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT]) { + return 1; + } + + g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; + return 0; + } + + if ((uint16_t)(message_number - g->group[peer_index].bottom_lossy_number) > (1 << 15)) { + return -1; + } + + uint16_t top_distance = message_number - g->group[peer_index].top_lossy_number; + + if (top_distance >= MAX_LOSSY_COUNT) { + crypto_memzero(g->group[peer_index].recv_lossy, sizeof(g->group[peer_index].recv_lossy)); + g->group[peer_index].top_lossy_number = message_number; + g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1; + g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; + return 0; + } + + if (top_distance < MAX_LOSSY_COUNT) { + unsigned int i; + + for (i = g->group[peer_index].bottom_lossy_number; i != (g->group[peer_index].bottom_lossy_number + top_distance); + ++i) { + g->group[peer_index].recv_lossy[i % MAX_LOSSY_COUNT] = 0; + } + + g->group[peer_index].top_lossy_number = message_number; + g->group[peer_index].bottom_lossy_number = (message_number - MAX_LOSSY_COUNT) + 1; + g->group[peer_index].recv_lossy[message_number % MAX_LOSSY_COUNT] = 1; + return 0; + } + + return -1; +} + +static int handle_lossy(void *object, int friendcon_id, const uint8_t *data, uint16_t length, void *userdata) +{ + Group_Chats *g_c = (Group_Chats *)object; + + if (length < 1 + sizeof(uint16_t) * 3 + 1) { + return -1; + } + + if (data[0] != PACKET_ID_LOSSY_CONFERENCE) { + return -1; + } + + uint16_t groupnumber, peer_number, message_number; + memcpy(&groupnumber, data + 1, sizeof(uint16_t)); + memcpy(&peer_number, data + 1 + sizeof(uint16_t), sizeof(uint16_t)); + memcpy(&message_number, data + 1 + sizeof(uint16_t) * 2, sizeof(uint16_t)); + groupnumber = net_ntohs(groupnumber); + peer_number = net_ntohs(peer_number); + message_number = net_ntohs(message_number); + + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + int index = friend_in_close(g, friendcon_id); + + if (index == -1) { + return -1; + } + + if (peer_number == g->peer_number) { + return -1; + } + + int peer_index = get_peer_index(g, peer_number); + + if (peer_index == -1) { + return -1; + } + + if (lossy_packet_not_received(g, peer_index, message_number)) { + return -1; + } + + const uint8_t *lossy_data = data + 1 + sizeof(uint16_t) * 3; + uint16_t lossy_length = length - (1 + sizeof(uint16_t) * 3); + uint8_t message_id = lossy_data[0]; + ++lossy_data; + --lossy_length; + + if (g_c->lossy_packethandlers[message_id].function) { + if (g_c->lossy_packethandlers[message_id].function(g->object, groupnumber, peer_index, g->group[peer_index].object, + lossy_data, lossy_length) == -1) { + return -1; + } + } else { + return -1; + } + + send_lossy_all_close(g_c, groupnumber, data + 1 + sizeof(uint16_t), length - (1 + sizeof(uint16_t)), index); + return 0; +} + +/* Set the object that is tied to the group chat. + * + * return 0 on success. + * return -1 on failure + */ +int group_set_object(const Group_Chats *g_c, int groupnumber, void *object) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + g->object = object; + return 0; +} + +/* Set the object that is tied to the group peer. + * + * return 0 on success. + * return -1 on failure + */ +int group_peer_set_object(const Group_Chats *g_c, int groupnumber, int peernumber, void *object) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return -1; + } + + g->group[peernumber].object = object; + return 0; +} + +/* Return the object tide to the group chat previously set by group_set_object. + * + * return NULL on failure. + * return object on success. + */ +void *group_get_object(const Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return NULL; + } + + return g->object; +} + +/* Return the object tide to the group chat peer previously set by group_peer_set_object. + * + * return NULL on failure. + * return object on success. + */ +void *group_peer_get_object(const Group_Chats *g_c, int groupnumber, int peernumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return NULL; + } + + if ((uint32_t)peernumber >= g->numpeers) { + return NULL; + } + + return g->group[peernumber].object; +} + +/* Interval in seconds to send ping messages */ +#define GROUP_PING_INTERVAL 20 + +static int ping_groupchat(Group_Chats *g_c, int groupnumber) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + if (is_timeout(g->last_sent_ping, GROUP_PING_INTERVAL)) { + if (group_ping_send(g_c, groupnumber) != -1) { /* Ping */ + g->last_sent_ping = unix_time(); + } + } + + return 0; +} + +static int groupchat_clear_timedout(Group_Chats *g_c, int groupnumber, void *userdata) +{ + Group_c *g = get_group_c(g_c, groupnumber); + + if (!g) { + return -1; + } + + uint32_t i; + + for (i = 0; i < g->numpeers; ++i) { + if (g->peer_number != g->group[i].peer_number && is_timeout(g->group[i].last_recv, GROUP_PING_INTERVAL * 3)) { + delpeer(g_c, groupnumber, i, userdata); + } + + if (g->group == NULL || i >= g->numpeers) { + break; + } + } + + return 0; +} + +/* Send current name (set in messenger) to all online groups. + */ +void send_name_all_groups(Group_Chats *g_c) +{ + unsigned int i; + + for (i = 0; i < g_c->num_chats; ++i) { + Group_c *g = get_group_c(g_c, i); + + if (!g) { + continue; + } + + if (g->status == GROUPCHAT_STATUS_CONNECTED) { + group_name_send(g_c, i, g_c->m->name, g_c->m->name_length); + } + } +} + +/* Create new groupchat instance. */ +Group_Chats *new_groupchats(Messenger *m) +{ + if (!m) { + return NULL; + } + + Group_Chats *temp = (Group_Chats *)calloc(1, sizeof(Group_Chats)); + + if (temp == NULL) { + return NULL; + } + + temp->m = m; + temp->fr_c = m->fr_c; + m->conferences_object = temp; + m_callback_conference_invite(m, &handle_friend_invite_packet); + + return temp; +} + +/* main groupchats loop. */ +void do_groupchats(Group_Chats *g_c, void *userdata) +{ + unsigned int i; + + for (i = 0; i < g_c->num_chats; ++i) { + Group_c *g = get_group_c(g_c, i); + + if (!g) { + continue; + } + + if (g->status == GROUPCHAT_STATUS_CONNECTED) { + connect_to_closest(g_c, i, userdata); + ping_groupchat(g_c, i); + groupchat_clear_timedout(g_c, i, userdata); + } + } + + // TODO(irungentoo): +} + +/* Free everything related with group chats. */ +void kill_groupchats(Group_Chats *g_c) +{ + unsigned int i; + + for (i = 0; i < g_c->num_chats; ++i) { + del_groupchat(g_c, i); + } + + m_callback_conference_invite(g_c->m, NULL); + g_c->m->conferences_object = NULL; + free(g_c); +} + +/* Return the number of chats in the instance m. + * You should use this to determine how much memory to allocate + * for copy_chatlist. + */ +uint32_t count_chatlist(Group_Chats *g_c) +{ + uint32_t ret = 0; + uint32_t i; + + for (i = 0; i < g_c->num_chats; i++) { + if (g_c->chats[i].status != GROUPCHAT_STATUS_NONE) { + ret++; + } + } + + return ret; +} + +/* Copy a list of valid chat IDs into the array out_list. + * If out_list is NULL, returns 0. + * Otherwise, returns the number of elements copied. + * If the array was too small, the contents + * of out_list will be truncated to list_size. */ +uint32_t copy_chatlist(Group_Chats *g_c, uint32_t *out_list, uint32_t list_size) +{ + if (!out_list) { + return 0; + } + + if (g_c->num_chats == 0) { + return 0; + } + + uint32_t i, ret = 0; + + for (i = 0; i < g_c->num_chats; ++i) { + if (ret >= list_size) { + break; /* Abandon ship */ + } + + if (g_c->chats[i].status > GROUPCHAT_STATUS_NONE) { + out_list[ret] = i; + ret++; + } + } + + return ret; +} diff --git a/libs/libtox/src/toxcore/group.h b/libs/libtox/src/toxcore/group.h new file mode 100644 index 0000000000..2e014da36d --- /dev/null +++ b/libs/libtox/src/toxcore/group.h @@ -0,0 +1,395 @@ +/* + * Slightly better groupchats implementation. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef GROUP_H +#define GROUP_H + +#include "Messenger.h" + +enum { + GROUPCHAT_STATUS_NONE, + GROUPCHAT_STATUS_VALID, + GROUPCHAT_STATUS_CONNECTED +}; + +enum { + GROUPCHAT_TYPE_TEXT, + GROUPCHAT_TYPE_AV +}; + +#define MAX_LOSSY_COUNT 256 + +typedef struct { + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + + uint64_t last_recv; + uint32_t last_message_number; + + uint8_t nick[MAX_NAME_LENGTH]; + uint8_t nick_len; + + uint16_t peer_number; + + uint8_t recv_lossy[MAX_LOSSY_COUNT]; + uint16_t bottom_lossy_number, top_lossy_number; + + void *object; +} Group_Peer; + +#define DESIRED_CLOSE_CONNECTIONS 4 +#define MAX_GROUP_CONNECTIONS 16 +#define GROUP_IDENTIFIER_LENGTH (1 + CRYPTO_SYMMETRIC_KEY_SIZE) /* type + CRYPTO_SYMMETRIC_KEY_SIZE so we can use new_symmetric_key(...) to fill it */ + +enum { + GROUPCHAT_CLOSE_NONE, + GROUPCHAT_CLOSE_CONNECTION, + GROUPCHAT_CLOSE_ONLINE +}; + +typedef struct { + uint8_t status; + + Group_Peer *group; + uint32_t numpeers; + + struct { + uint8_t type; /* GROUPCHAT_CLOSE_* */ + uint8_t closest; + uint32_t number; + uint16_t group_number; + } close[MAX_GROUP_CONNECTIONS]; + + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + struct { + uint8_t entry; + uint8_t real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + } closest_peers[DESIRED_CLOSE_CONNECTIONS]; + uint8_t changed; + + uint8_t identifier[GROUP_IDENTIFIER_LENGTH]; + + uint8_t title[MAX_NAME_LENGTH]; + uint8_t title_len; + + uint32_t message_number; + uint16_t lossy_message_number; + uint16_t peer_number; + + uint64_t last_sent_ping; + + int number_joined; /* friendcon_id of person that invited us to the chat. (-1 means none) */ + + void *object; + + void (*peer_on_join)(void *, int, int); + void (*peer_on_leave)(void *, int, int, void *); + void (*group_on_delete)(void *, int); +} Group_c; + +typedef struct { + Messenger *m; + Friend_Connections *fr_c; + + Group_c *chats; + uint32_t num_chats; + + void (*invite_callback)(Messenger *m, uint32_t, int, const uint8_t *, size_t, void *); + void (*message_callback)(Messenger *m, uint32_t, uint32_t, int, const uint8_t *, size_t, void *); + void (*group_namelistchange)(Messenger *m, int, int, uint8_t, void *); + void (*title_callback)(Messenger *m, uint32_t, uint32_t, const uint8_t *, size_t, void *); + + struct { + int (*function)(void *, int, int, void *, const uint8_t *, uint16_t); + } lossy_packethandlers[256]; +} Group_Chats; + +/* Set the callback for group invites. + * + * Function(Group_Chats *g_c, int32_t friendnumber, uint8_t type, uint8_t *data, uint16_t length, void *userdata) + * + * data of length is what needs to be passed to join_groupchat(). + */ +void g_callback_group_invite(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, int, const uint8_t *, + size_t, void *)); + +/* Set the callback for group messages. + * + * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * message, uint16_t length, void *userdata) + */ +void g_callback_group_message(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, uint32_t, int, const uint8_t *, + size_t, void *)); + + +/* Set callback function for title changes. + * + * Function(Group_Chats *g_c, int groupnumber, int friendgroupnumber, uint8_t * title, uint8_t length, void *userdata) + * if friendgroupnumber == -1, then author is unknown (e.g. initial joining the group) + */ +void g_callback_group_title(Group_Chats *g_c, void (*function)(Messenger *m, uint32_t, uint32_t, const uint8_t *, + size_t, void *)); + +/* Set callback function for peer name list changes. + * + * It gets called every time the name list changes(new peer/name, deleted peer) + * Function(Group_Chats *g_c, int groupnumber, int peernumber, TOX_CHAT_CHANGE change, void *userdata) + */ +enum { + CHAT_CHANGE_PEER_ADD, + CHAT_CHANGE_PEER_DEL, + CHAT_CHANGE_PEER_NAME, +}; +void g_callback_group_namelistchange(Group_Chats *g_c, void (*function)(Messenger *m, int, int, uint8_t, void *)); + +/* Creates a new groupchat and puts it in the chats array. + * + * type is one of GROUPCHAT_TYPE_* + * + * return group number on success. + * return -1 on failure. + */ +int add_groupchat(Group_Chats *g_c, uint8_t type); + +/* Delete a groupchat from the chats array. + * + * return 0 on success. + * return -1 if groupnumber is invalid. + */ +int del_groupchat(Group_Chats *g_c, int groupnumber); + +/* Copy the public key of peernumber who is in groupnumber to pk. + * pk must be CRYPTO_PUBLIC_KEY_SIZE long. + * + * return 0 on success + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peer_pubkey(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *pk); + +/* + * Return the size of peernumber's name. + * + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peername_size(const Group_Chats *g_c, int groupnumber, int peernumber); + +/* Copy the name of peernumber who is in groupnumber to name. + * name must be at least MAX_NAME_LENGTH long. + * + * return length of name if success + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + */ +int group_peername(const Group_Chats *g_c, int groupnumber, int peernumber, uint8_t *name); + +/* invite friendnumber to groupnumber + * + * return 0 on success. + * return -1 if groupnumber is invalid. + * return -2 if invite packet failed to send. + */ +int invite_friend(Group_Chats *g_c, int32_t friendnumber, int groupnumber); + +/* Join a group (you need to have been invited first.) + * + * expected_type is the groupchat type we expect the chat we are joining is. + * + * return group number on success. + * return -1 if data length is invalid. + * return -2 if group is not the expected type. + * return -3 if friendnumber is invalid. + * return -4 if client is already in this group. + * return -5 if group instance failed to initialize. + * return -6 if join packet fails to send. + */ +int join_groupchat(Group_Chats *g_c, int32_t friendnumber, uint8_t expected_type, const uint8_t *data, uint16_t length); + +/* send a group message + * return 0 on success + * see: send_message_group() for error codes. + */ +int group_message_send(const Group_Chats *g_c, int groupnumber, const uint8_t *message, uint16_t length); + +/* send a group action + * return 0 on success + * see: send_message_group() for error codes. + */ +int group_action_send(const Group_Chats *g_c, int groupnumber, const uint8_t *action, uint16_t length); + +/* set the group's title, limited to MAX_NAME_LENGTH + * return 0 on success + * return -1 if groupnumber is invalid. + * return -2 if title is too long or empty. + * return -3 if packet fails to send. + */ +int group_title_send(const Group_Chats *g_c, int groupnumber, const uint8_t *title, uint8_t title_len); + + +/* return the group's title size. + * return -1 of groupnumber is invalid. + * return -2 if title is too long or empty. + */ +int group_title_get_size(const Group_Chats *g_c, int groupnumber); + +/* Get group title from groupnumber and put it in title. + * Title needs to be a valid memory location with a size of at least MAX_NAME_LENGTH (128) bytes. + * + * return length of copied title if success. + * return -1 if groupnumber is invalid. + * return -2 if title is too long or empty. + */ +int group_title_get(const Group_Chats *g_c, int groupnumber, uint8_t *title); + +/* Return the number of peers in the group chat on success. + * return -1 if groupnumber is invalid. + */ +int group_number_peers(const Group_Chats *g_c, int groupnumber); + +/* return 1 if the peernumber corresponds to ours. + * return 0 if the peernumber is not ours. + * return -1 if groupnumber is invalid. + * return -2 if peernumber is invalid. + * return -3 if we are not connected to the group chat. + */ +int group_peernumber_is_ours(const Group_Chats *g_c, int groupnumber, int peernumber); + +/* List all the peers in the group chat. + * + * Copies the names of the peers to the name[length][MAX_NAME_LENGTH] array. + * + * Copies the lengths of the names to lengths[length] + * + * returns the number of peers on success. + * + * return -1 on failure. + */ +int group_names(const Group_Chats *g_c, int groupnumber, uint8_t names[][MAX_NAME_LENGTH], uint16_t lengths[], + uint16_t length); + +/* Set handlers for custom lossy packets. + * + * NOTE: Handler must return 0 if packet is to be relayed, -1 if the packet should not be relayed. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object), const uint8_t *packet, uint16_t length) + */ +void group_lossy_packet_registerhandler(Group_Chats *g_c, uint8_t byte, int (*function)(void *, int, int, void *, + const uint8_t *, uint16_t)); + +/* High level function to send custom lossy packets. + * + * return -1 on failure. + * return 0 on success. + */ +int send_group_lossy_packet(const Group_Chats *g_c, int groupnumber, const uint8_t *data, uint16_t length); + +/* Return the number of chats in the instance m. + * You should use this to determine how much memory to allocate + * for copy_chatlist. + */ +uint32_t count_chatlist(Group_Chats *g_c); + +/* Copy a list of valid chat IDs into the array out_list. + * If out_list is NULL, returns 0. + * Otherwise, returns the number of elements copied. + * If the array was too small, the contents + * of out_list will be truncated to list_size. */ +uint32_t copy_chatlist(Group_Chats *g_c, uint32_t *out_list, uint32_t list_size); + +/* return the type of groupchat (GROUPCHAT_TYPE_) that groupnumber is. + * + * return -1 on failure. + * return type on success. + */ +int group_get_type(const Group_Chats *g_c, int groupnumber); + +/* Send current name (set in messenger) to all online groups. + */ +void send_name_all_groups(Group_Chats *g_c); + +/* Set the object that is tied to the group chat. + * + * return 0 on success. + * return -1 on failure + */ +int group_set_object(const Group_Chats *g_c, int groupnumber, void *object); + +/* Set the object that is tied to the group peer. + * + * return 0 on success. + * return -1 on failure + */ +int group_peer_set_object(const Group_Chats *g_c, int groupnumber, int peernumber, void *object); + +/* Return the object tide to the group chat previously set by group_set_object. + * + * return NULL on failure. + * return object on success. + */ +void *group_get_object(const Group_Chats *g_c, int groupnumber); + +/* Return the object tide to the group chat peer previously set by group_peer_set_object. + * + * return NULL on failure. + * return object on success. + */ +void *group_peer_get_object(const Group_Chats *g_c, int groupnumber, int peernumber); + +/* Set a function to be called when a new peer joins a group chat. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_peer_new(const Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int)); + +/* Set a function to be called when a peer leaves a group chat. + * + * Function(void *group object (set with group_set_object), int groupnumber, int friendgroupnumber, void *group peer object (set with group_peer_set_object)) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_peer_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int, int, void *)); + +/* Set a function to be called when the group chat is deleted. + * + * Function(void *group object (set with group_set_object), int groupnumber) + * + * return 0 on success. + * return -1 on failure. + */ +int callback_groupchat_delete(Group_Chats *g_c, int groupnumber, void (*function)(void *, int)); + +/* Create new groupchat instance. */ +Group_Chats *new_groupchats(Messenger *m); + +/* main groupchats loop. */ +void do_groupchats(Group_Chats *g_c, void *userdata); + +/* Free everything related with group chats. */ +void kill_groupchats(Group_Chats *g_c); + +#endif diff --git a/libs/libtox/src/toxcore/list.c b/libs/libtox/src/toxcore/list.c new file mode 100644 index 0000000000..36d609fbd1 --- /dev/null +++ b/libs/libtox/src/toxcore/list.c @@ -0,0 +1,266 @@ +/* + * Simple struct with functions to create a list which associates ids with data + * -Allows for finding ids associated with data such as IPs or public keys in a short time + * -Should only be used if there are relatively few add/remove calls to the list + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "list.h" + +/* Basically, the elements in the list are placed in order so that they can be searched for easily + * -each element is seen as a big-endian integer when ordering them + * -the ids array is maintained so that each id always matches + * -the search algorithm cuts down the time to find the id associated with a piece of data + * at the cost of slow add/remove functions for large lists + * -Starts at 1/2 of the array, compares the element in the array with the data, + * then moves +/- 1/4 of the array depending on whether the value is greater or lower, + * then +- 1/8, etc, until the value is matched or its position where it should be in the array is found + * -some considerations since the array size is never perfect + */ + +#define INDEX(i) (~i) + +/* Find data in list + * + * return value: + * >= 0 : index of data in array + * < 0 : no match, returns index (return value is INDEX(index)) where + * the data should be inserted + */ +static int find(const BS_LIST *list, const uint8_t *data) +{ + //should work well, but could be improved + if (list->n == 0) { + return INDEX(0); + } + + uint32_t i = list->n / 2; //current position in the array + uint32_t delta = i / 2; //how much we move in the array + + if (!delta) { + delta = 1; + } + + int d = -1; //used to determine if closest match is found + //closest match is found if we move back to where we have already been + + while (1) { + int r = memcmp(data, list->data + list->element_size * i, list->element_size); + + if (r == 0) { + return i; + } + + if (r > 0) { + //data is greater + //move down + i += delta; + + if (d == 0 || i == list->n) { + //reached bottom of list, or closest match + return INDEX(i); + } + + delta = (delta) / 2; + + if (delta == 0) { + delta = 1; + d = 1; + } + } else { + //data is smaller + if (d == 1 || i == 0) { + //reached top or list or closest match + return INDEX(i); + } + + //move up + i -= delta; + + delta = (delta) / 2; + + if (delta == 0) { + delta = 1; + d = 0; + } + } + } +} + +/* Resized the list list + * + * return value: + * 1 : success + * 0 : failure + */ +static int resize(BS_LIST *list, uint32_t new_size) +{ + if (new_size == 0) { + bs_list_free(list); + return 1; + } + + uint8_t *data = (uint8_t *)realloc(list->data, list->element_size * new_size); + + if (!data) { + return 0; + } + + list->data = data; + + int *ids = (int *)realloc(list->ids, sizeof(int) * new_size); + + if (!ids) { + return 0; + } + + list->ids = ids; + + return 1; +} + + +int bs_list_init(BS_LIST *list, uint32_t element_size, uint32_t initial_capacity) +{ + //set initial values + list->n = 0; + list->element_size = element_size; + list->capacity = 0; + list->data = NULL; + list->ids = NULL; + + if (initial_capacity != 0) { + if (!resize(list, initial_capacity)) { + return 0; + } + } + + list->capacity = initial_capacity; + + return 1; +} + +void bs_list_free(BS_LIST *list) +{ + //free both arrays + free(list->data); + list->data = NULL; + + free(list->ids); + list->ids = NULL; +} + +int bs_list_find(const BS_LIST *list, const uint8_t *data) +{ + int r = find(list, data); + + //return only -1 and positive values + if (r < 0) { + return -1; + } + + return list->ids[r]; +} + +int bs_list_add(BS_LIST *list, const uint8_t *data, int id) +{ + //find where the new element should be inserted + //see: return value of find() + int i = find(list, data); + + if (i >= 0) { + //already in list + return 0; + } + + i = ~i; + + //increase the size of the arrays if needed + if (list->n == list->capacity) { + // 1.5 * n + 1 + const uint32_t new_capacity = list->n + list->n / 2 + 1; + + if (!resize(list, new_capacity)) { + return 0; + } + + list->capacity = new_capacity; + } + + //insert data to element array + memmove(list->data + (i + 1) * list->element_size, list->data + i * list->element_size, + (list->n - i) * list->element_size); + memcpy(list->data + i * list->element_size, data, list->element_size); + + //insert id to id array + memmove(&list->ids[i + 1], &list->ids[i], (list->n - i) * sizeof(int)); + list->ids[i] = id; + + //increase n + list->n++; + + return 1; +} + +int bs_list_remove(BS_LIST *list, const uint8_t *data, int id) +{ + int i = find(list, data); + + if (i < 0) { + return 0; + } + + if (list->ids[i] != id) { + //this should never happen + return 0; + } + + //decrease the size of the arrays if needed + if (list->n < list->capacity / 2) { + const uint32_t new_capacity = list->capacity / 2; + + if (resize(list, new_capacity)) { + list->capacity = new_capacity; + } + } + + list->n--; + + memmove(list->data + i * list->element_size, list->data + (i + 1) * list->element_size, + (list->n - i) * list->element_size); + memmove(&list->ids[i], &list->ids[i + 1], (list->n - i) * sizeof(int)); + + return 1; +} + +int bs_list_trim(BS_LIST *list) +{ + if (!resize(list, list->n)) { + return 0; + } + + list->capacity = list->n; + return 1; +} diff --git a/libs/libtox/src/toxcore/list.h b/libs/libtox/src/toxcore/list.h new file mode 100644 index 0000000000..cb3b328c5a --- /dev/null +++ b/libs/libtox/src/toxcore/list.h @@ -0,0 +1,85 @@ +/* + * Simple struct with functions to create a list which associates ids with data + * -Allows for finding ids associated with data such as IPs or public keys in a short time + * -Should only be used if there are relatively few add/remove calls to the list + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef LIST_H +#define LIST_H + +#include +#include +#include + +typedef struct { + uint32_t n; //number of elements + uint32_t capacity; //number of elements memory is allocated for + uint32_t element_size; //size of the elements + uint8_t *data; //array of elements + int *ids; //array of element ids +} BS_LIST; + +/* Initialize a list, element_size is the size of the elements in the list and + * initial_capacity is the number of elements the memory will be initially allocated for + * + * return value: + * 1 : success + * 0 : failure + */ +int bs_list_init(BS_LIST *list, uint32_t element_size, uint32_t initial_capacity); + +/* Free a list initiated with list_init */ +void bs_list_free(BS_LIST *list); + +/* Retrieve the id of an element in the list + * + * return value: + * >= 0 : id associated with data + * -1 : failure + */ +int bs_list_find(const BS_LIST *list, const uint8_t *data); + +/* Add an element with associated id to the list + * + * return value: + * 1 : success + * 0 : failure (data already in list) + */ +int bs_list_add(BS_LIST *list, const uint8_t *data, int id); + +/* Remove element from the list + * + * return value: + * 1 : success + * 0 : failure (element not found or id does not match) + */ +int bs_list_remove(BS_LIST *list, const uint8_t *data, int id); + +/* Removes the memory overhead + * + * return value: + * 1 : success + * 0 : failure + */ +int bs_list_trim(BS_LIST *list); + +#endif diff --git a/libs/libtox/src/toxcore/logger.c b/libs/libtox/src/toxcore/logger.c new file mode 100644 index 0000000000..18b765a385 --- /dev/null +++ b/libs/libtox/src/toxcore/logger.c @@ -0,0 +1,77 @@ +/* + * Text logging abstraction. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013,2015 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "logger.h" + +#include +#include +#include + + +struct Logger { + logger_cb *callback; + void *context; + void *userdata; +}; + + +/** + * Public Functions + */ +Logger *logger_new(void) +{ + return (Logger *)calloc(1, sizeof(Logger)); +} + +void logger_kill(Logger *log) +{ + free(log); +} + +void logger_callback_log(Logger *log, logger_cb *function, void *context, void *userdata) +{ + log->callback = function; + log->context = context; + log->userdata = userdata; +} + +void logger_write(Logger *log, LOGGER_LEVEL level, const char *file, int line, const char *func, const char *format, + ...) +{ + if (!log || !log->callback) { + return; + } + + /* Format message */ + char msg[1024]; + va_list args; + va_start(args, format); + vsnprintf(msg, sizeof msg, format, args); + va_end(args); + + log->callback(log->context, level, file, line, func, msg, log->userdata); +} diff --git a/libs/libtox/src/toxcore/logger.h b/libs/libtox/src/toxcore/logger.h new file mode 100644 index 0000000000..8c8a639bec --- /dev/null +++ b/libs/libtox/src/toxcore/logger.h @@ -0,0 +1,80 @@ +/* + * Logger abstraction backed by callbacks for writing. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef TOXLOGGER_H +#define TOXLOGGER_H + +#include + +#ifndef MIN_LOGGER_LEVEL +#define MIN_LOGGER_LEVEL LOG_INFO +#endif + +typedef enum { + LOG_TRACE, + LOG_DEBUG, + LOG_INFO, + LOG_WARNING, + LOG_ERROR +} LOGGER_LEVEL; + +typedef struct Logger Logger; + +typedef void logger_cb(void *context, LOGGER_LEVEL level, const char *file, int line, + const char *func, const char *message, void *userdata); + +/** + * Creates a new logger with logging disabled (callback is NULL) by default. + */ +Logger *logger_new(void); + +void logger_kill(Logger *log); + +/** + * Sets the logger callback. Disables logging if set to NULL. + * The context parameter is passed to the callback as first argument. + */ +void logger_callback_log(Logger *log, logger_cb *function, void *context, void *userdata); + +/** + * Main write function. If logging disabled does nothing. + */ +void logger_write(Logger *log, LOGGER_LEVEL level, const char *file, int line, const char *func, const char *format, + ...); + + +#define LOGGER_WRITE(log, level, ...) \ + do { \ + if (level >= MIN_LOGGER_LEVEL) { \ + logger_write(log, level, __FILE__, __LINE__, __func__, __VA_ARGS__); \ + } \ + } while (0) + +/* To log with an logger */ +#define LOGGER_TRACE(log, ...) LOGGER_WRITE(log, LOG_TRACE , __VA_ARGS__) +#define LOGGER_DEBUG(log, ...) LOGGER_WRITE(log, LOG_DEBUG , __VA_ARGS__) +#define LOGGER_INFO(log, ...) LOGGER_WRITE(log, LOG_INFO , __VA_ARGS__) +#define LOGGER_WARNING(log, ...) LOGGER_WRITE(log, LOG_WARNING, __VA_ARGS__) +#define LOGGER_ERROR(log, ...) LOGGER_WRITE(log, LOG_ERROR , __VA_ARGS__) + +#endif /* TOXLOGGER_H */ diff --git a/libs/libtox/src/toxcore/net_crypto.c b/libs/libtox/src/toxcore/net_crypto.c new file mode 100644 index 0000000000..37cbab188f --- /dev/null +++ b/libs/libtox/src/toxcore/net_crypto.c @@ -0,0 +1,2908 @@ +/* + * Functions for the core network crypto. + * + * NOTE: This code has to be perfect. We don't mess around with encryption. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "net_crypto.h" + +#include "util.h" + +#include + + +static uint8_t crypt_connection_id_not_valid(const Net_Crypto *c, int crypt_connection_id) +{ + if ((uint32_t)crypt_connection_id >= c->crypto_connections_length) { + return 1; + } + + if (c->crypto_connections == NULL) { + return 1; + } + + if (c->crypto_connections[crypt_connection_id].status == CRYPTO_CONN_NO_CONNECTION) { + return 1; + } + + return 0; +} + +/* cookie timeout in seconds */ +#define COOKIE_TIMEOUT 15 +#define COOKIE_DATA_LENGTH (CRYPTO_PUBLIC_KEY_SIZE * 2) +#define COOKIE_CONTENTS_LENGTH (sizeof(uint64_t) + COOKIE_DATA_LENGTH) +#define COOKIE_LENGTH (CRYPTO_NONCE_SIZE + COOKIE_CONTENTS_LENGTH + CRYPTO_MAC_SIZE) + +#define COOKIE_REQUEST_PLAIN_LENGTH (COOKIE_DATA_LENGTH + sizeof(uint64_t)) +#define COOKIE_REQUEST_LENGTH (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE) +#define COOKIE_RESPONSE_LENGTH (1 + CRYPTO_NONCE_SIZE + COOKIE_LENGTH + sizeof(uint64_t) + CRYPTO_MAC_SIZE) + +/* Create a cookie request packet and put it in packet. + * dht_public_key is the dht public key of the other + * + * packet must be of size COOKIE_REQUEST_LENGTH or bigger. + * + * return -1 on failure. + * return COOKIE_REQUEST_LENGTH on success. + */ +static int create_cookie_request(const Net_Crypto *c, uint8_t *packet, uint8_t *dht_public_key, uint64_t number, + uint8_t *shared_key) +{ + uint8_t plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t padding[CRYPTO_PUBLIC_KEY_SIZE] = {0}; + + memcpy(plain, c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, padding, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + (CRYPTO_PUBLIC_KEY_SIZE * 2), &number, sizeof(uint64_t)); + + DHT_get_shared_key_sent(c->dht, shared_key, dht_public_key); + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + packet[0] = NET_PACKET_COOKIE_REQUEST; + memcpy(packet + 1, c->dht->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); + int len = encrypt_data_symmetric(shared_key, nonce, plain, sizeof(plain), + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if (len != COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE) { + return -1; + } + + return (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + len); +} + +/* Create cookie of length COOKIE_LENGTH from bytes of length COOKIE_DATA_LENGTH using encryption_key + * + * return -1 on failure. + * return 0 on success. + */ +static int create_cookie(uint8_t *cookie, const uint8_t *bytes, const uint8_t *encryption_key) +{ + uint8_t contents[COOKIE_CONTENTS_LENGTH]; + uint64_t temp_time = unix_time(); + memcpy(contents, &temp_time, sizeof(temp_time)); + memcpy(contents + sizeof(temp_time), bytes, COOKIE_DATA_LENGTH); + random_nonce(cookie); + int len = encrypt_data_symmetric(encryption_key, cookie, contents, sizeof(contents), cookie + CRYPTO_NONCE_SIZE); + + if (len != COOKIE_LENGTH - CRYPTO_NONCE_SIZE) { + return -1; + } + + return 0; +} + +/* Open cookie of length COOKIE_LENGTH to bytes of length COOKIE_DATA_LENGTH using encryption_key + * + * return -1 on failure. + * return 0 on success. + */ +static int open_cookie(uint8_t *bytes, const uint8_t *cookie, const uint8_t *encryption_key) +{ + uint8_t contents[COOKIE_CONTENTS_LENGTH]; + int len = decrypt_data_symmetric(encryption_key, cookie, cookie + CRYPTO_NONCE_SIZE, + COOKIE_LENGTH - CRYPTO_NONCE_SIZE, contents); + + if (len != sizeof(contents)) { + return -1; + } + + uint64_t cookie_time; + memcpy(&cookie_time, contents, sizeof(cookie_time)); + uint64_t temp_time = unix_time(); + + if (cookie_time + COOKIE_TIMEOUT < temp_time || temp_time < cookie_time) { + return -1; + } + + memcpy(bytes, contents + sizeof(cookie_time), COOKIE_DATA_LENGTH); + return 0; +} + + +/* Create a cookie response packet and put it in packet. + * request_plain must be COOKIE_REQUEST_PLAIN_LENGTH bytes. + * packet must be of size COOKIE_RESPONSE_LENGTH or bigger. + * + * return -1 on failure. + * return COOKIE_RESPONSE_LENGTH on success. + */ +static int create_cookie_response(const Net_Crypto *c, uint8_t *packet, const uint8_t *request_plain, + const uint8_t *shared_key, const uint8_t *dht_public_key) +{ + uint8_t cookie_plain[COOKIE_DATA_LENGTH]; + memcpy(cookie_plain, request_plain, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); + uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)]; + + if (create_cookie(plain, cookie_plain, c->secret_symmetric_key) != 0) { + return -1; + } + + memcpy(plain + COOKIE_LENGTH, request_plain + COOKIE_DATA_LENGTH, sizeof(uint64_t)); + packet[0] = NET_PACKET_COOKIE_RESPONSE; + random_nonce(packet + 1); + int len = encrypt_data_symmetric(shared_key, packet + 1, plain, sizeof(plain), packet + 1 + CRYPTO_NONCE_SIZE); + + if (len != COOKIE_RESPONSE_LENGTH - (1 + CRYPTO_NONCE_SIZE)) { + return -1; + } + + return COOKIE_RESPONSE_LENGTH; +} + +/* Handle the cookie request packet of length length. + * Put what was in the request in request_plain (must be of size COOKIE_REQUEST_PLAIN_LENGTH) + * Put the key used to decrypt the request into shared_key (of size CRYPTO_SHARED_KEY_SIZE) for use in the response. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_cookie_request(const Net_Crypto *c, uint8_t *request_plain, uint8_t *shared_key, + uint8_t *dht_public_key, const uint8_t *packet, uint16_t length) +{ + if (length != COOKIE_REQUEST_LENGTH) { + return -1; + } + + memcpy(dht_public_key, packet + 1, CRYPTO_PUBLIC_KEY_SIZE); + DHT_get_shared_key_sent(c->dht, shared_key, dht_public_key); + int len = decrypt_data_symmetric(shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE, + request_plain); + + if (len != COOKIE_REQUEST_PLAIN_LENGTH) { + return -1; + } + + return 0; +} + +/* Handle the cookie request packet (for raw UDP) + */ +static int udp_handle_cookie_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Net_Crypto *c = (Net_Crypto *)object; + uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + + if (handle_cookie_request(c, request_plain, shared_key, dht_public_key, packet, length) != 0) { + return 1; + } + + uint8_t data[COOKIE_RESPONSE_LENGTH]; + + if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data)) { + return 1; + } + + if ((uint32_t)sendpacket(c->dht->net, source, data, sizeof(data)) != sizeof(data)) { + return 1; + } + + return 0; +} + +/* Handle the cookie request packet (for TCP) + */ +static int tcp_handle_cookie_request(Net_Crypto *c, int connections_number, const uint8_t *packet, uint16_t length) +{ + uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + + if (handle_cookie_request(c, request_plain, shared_key, dht_public_key, packet, length) != 0) { + return -1; + } + + uint8_t data[COOKIE_RESPONSE_LENGTH]; + + if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data)) { + return -1; + } + + int ret = send_packet_tcp_connection(c->tcp_c, connections_number, data, sizeof(data)); + return ret; +} + +/* Handle the cookie request packet (for TCP oob packets) + */ +static int tcp_oob_handle_cookie_request(const Net_Crypto *c, unsigned int tcp_connections_number, + const uint8_t *dht_public_key, const uint8_t *packet, uint16_t length) +{ + uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + uint8_t dht_public_key_temp[CRYPTO_PUBLIC_KEY_SIZE]; + + if (handle_cookie_request(c, request_plain, shared_key, dht_public_key_temp, packet, length) != 0) { + return -1; + } + + if (public_key_cmp(dht_public_key, dht_public_key_temp) != 0) { + return -1; + } + + uint8_t data[COOKIE_RESPONSE_LENGTH]; + + if (create_cookie_response(c, data, request_plain, shared_key, dht_public_key) != sizeof(data)) { + return -1; + } + + int ret = tcp_send_oob_packet(c->tcp_c, tcp_connections_number, dht_public_key, data, sizeof(data)); + return ret; +} + +/* Handle a cookie response packet of length encrypted with shared_key. + * put the cookie in the response in cookie + * + * cookie must be of length COOKIE_LENGTH. + * + * return -1 on failure. + * return COOKIE_LENGTH on success. + */ +static int handle_cookie_response(uint8_t *cookie, uint64_t *number, const uint8_t *packet, uint16_t length, + const uint8_t *shared_key) +{ + if (length != COOKIE_RESPONSE_LENGTH) { + return -1; + } + + uint8_t plain[COOKIE_LENGTH + sizeof(uint64_t)]; + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + length - (1 + CRYPTO_NONCE_SIZE), plain); + + if (len != sizeof(plain)) { + return -1; + } + + memcpy(cookie, plain, COOKIE_LENGTH); + memcpy(number, plain + COOKIE_LENGTH, sizeof(uint64_t)); + return COOKIE_LENGTH; +} + +#define HANDSHAKE_PACKET_LENGTH (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE + COOKIE_LENGTH + CRYPTO_MAC_SIZE) + +/* Create a handshake packet and put it in packet. + * cookie must be COOKIE_LENGTH bytes. + * packet must be of size HANDSHAKE_PACKET_LENGTH or bigger. + * + * return -1 on failure. + * return HANDSHAKE_PACKET_LENGTH on success. + */ +static int create_crypto_handshake(const Net_Crypto *c, uint8_t *packet, const uint8_t *cookie, const uint8_t *nonce, + const uint8_t *session_pk, const uint8_t *peer_real_pk, const uint8_t *peer_dht_pubkey) +{ + uint8_t plain[CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE + COOKIE_LENGTH]; + memcpy(plain, nonce, CRYPTO_NONCE_SIZE); + memcpy(plain + CRYPTO_NONCE_SIZE, session_pk, CRYPTO_PUBLIC_KEY_SIZE); + crypto_sha512(plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, cookie, COOKIE_LENGTH); + uint8_t cookie_plain[COOKIE_DATA_LENGTH]; + memcpy(cookie_plain, peer_real_pk, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, peer_dht_pubkey, CRYPTO_PUBLIC_KEY_SIZE); + + if (create_cookie(plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE, cookie_plain, + c->secret_symmetric_key) != 0) { + return -1; + } + + random_nonce(packet + 1 + COOKIE_LENGTH); + int len = encrypt_data(peer_real_pk, c->self_secret_key, packet + 1 + COOKIE_LENGTH, plain, sizeof(plain), + packet + 1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE); + + if (len != HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE)) { + return -1; + } + + packet[0] = NET_PACKET_CRYPTO_HS; + memcpy(packet + 1, cookie, COOKIE_LENGTH); + + return HANDSHAKE_PACKET_LENGTH; +} + +/* Handle a crypto handshake packet of length. + * put the nonce contained in the packet in nonce, + * the session public key in session_pk + * the real public key of the peer in peer_real_pk + * the dht public key of the peer in dht_public_key and + * the cookie inside the encrypted part of the packet in cookie. + * + * if expected_real_pk isn't NULL it denotes the real public key + * the packet should be from. + * + * nonce must be at least CRYPTO_NONCE_SIZE + * session_pk must be at least CRYPTO_PUBLIC_KEY_SIZE + * peer_real_pk must be at least CRYPTO_PUBLIC_KEY_SIZE + * cookie must be at least COOKIE_LENGTH + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_crypto_handshake(const Net_Crypto *c, uint8_t *nonce, uint8_t *session_pk, uint8_t *peer_real_pk, + uint8_t *dht_public_key, uint8_t *cookie, const uint8_t *packet, uint16_t length, const uint8_t *expected_real_pk) +{ + if (length != HANDSHAKE_PACKET_LENGTH) { + return -1; + } + + uint8_t cookie_plain[COOKIE_DATA_LENGTH]; + + if (open_cookie(cookie_plain, packet + 1, c->secret_symmetric_key) != 0) { + return -1; + } + + if (expected_real_pk) { + if (public_key_cmp(cookie_plain, expected_real_pk) != 0) { + return -1; + } + } + + uint8_t cookie_hash[CRYPTO_SHA512_SIZE]; + crypto_sha512(cookie_hash, packet + 1, COOKIE_LENGTH); + + uint8_t plain[CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE + COOKIE_LENGTH]; + int len = decrypt_data(cookie_plain, c->self_secret_key, packet + 1 + COOKIE_LENGTH, + packet + 1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE, + HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE), plain); + + if (len != sizeof(plain)) { + return -1; + } + + if (crypto_memcmp(cookie_hash, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + CRYPTO_SHA512_SIZE) != 0) { + return -1; + } + + memcpy(nonce, plain, CRYPTO_NONCE_SIZE); + memcpy(session_pk, plain + CRYPTO_NONCE_SIZE, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(cookie, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA512_SIZE, COOKIE_LENGTH); + memcpy(peer_real_pk, cookie_plain, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(dht_public_key, cookie_plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_PUBLIC_KEY_SIZE); + return 0; +} + + +static Crypto_Connection *get_crypto_connection(const Net_Crypto *c, int crypt_connection_id) +{ + if (crypt_connection_id_not_valid(c, crypt_connection_id)) { + return 0; + } + + return &c->crypto_connections[crypt_connection_id]; +} + + +/* Associate an ip_port to a connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int add_ip_port_connection(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (ip_port.ip.family == TOX_AF_INET) { + if (!ipport_equal(&ip_port, &conn->ip_portv4) && LAN_ip(conn->ip_portv4.ip) != 0) { + if (!bs_list_add(&c->ip_port_list, (uint8_t *)&ip_port, crypt_connection_id)) { + return -1; + } + + bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv4, crypt_connection_id); + conn->ip_portv4 = ip_port; + return 0; + } + } else if (ip_port.ip.family == TOX_AF_INET6) { + if (!ipport_equal(&ip_port, &conn->ip_portv6)) { + if (!bs_list_add(&c->ip_port_list, (uint8_t *)&ip_port, crypt_connection_id)) { + return -1; + } + + bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv6, crypt_connection_id); + conn->ip_portv6 = ip_port; + return 0; + } + } + + return -1; +} + +/* Return the IP_Port that should be used to send packets to the other peer. + * + * return IP_Port with family 0 on failure. + * return IP_Port on success. + */ +static IP_Port return_ip_port_connection(Net_Crypto *c, int crypt_connection_id) +{ + const IP_Port empty = {{0}}; + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return empty; + } + + uint64_t current_time = unix_time(); + bool v6 = 0, v4 = 0; + + if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev4) > current_time) { + v4 = 1; + } + + if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev6) > current_time) { + v6 = 1; + } + + if (v4 && LAN_ip(conn->ip_portv4.ip) == 0) { + return conn->ip_portv4; + } + + if (v6 && conn->ip_portv6.ip.family == TOX_AF_INET6) { + return conn->ip_portv6; + } + + if (conn->ip_portv4.ip.family == TOX_AF_INET) { + return conn->ip_portv4; + } + + return empty; +} + +/* Sends a packet to the peer using the fastest route. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_packet_to(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length) +{ +// TODO(irungentoo): TCP, etc... + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + int direct_send_attempt = 0; + + pthread_mutex_lock(&conn->mutex); + IP_Port ip_port = return_ip_port_connection(c, crypt_connection_id); + + // TODO(irungentoo): on bad networks, direct connections might not last indefinitely. + if (ip_port.ip.family != 0) { + bool direct_connected = 0; + crypto_connection_status(c, crypt_connection_id, &direct_connected, NULL); + + if (direct_connected) { + if ((uint32_t)sendpacket(c->dht->net, ip_port, data, length) == length) { + pthread_mutex_unlock(&conn->mutex); + return 0; + } + + pthread_mutex_unlock(&conn->mutex); + return -1; + } + + // TODO(irungentoo): a better way of sending packets directly to confirm the others ip. + uint64_t current_time = unix_time(); + + if ((((UDP_DIRECT_TIMEOUT / 2) + conn->direct_send_attempt_time) > current_time && length < 96) + || data[0] == NET_PACKET_COOKIE_REQUEST || data[0] == NET_PACKET_CRYPTO_HS) { + if ((uint32_t)sendpacket(c->dht->net, ip_port, data, length) == length) { + direct_send_attempt = 1; + conn->direct_send_attempt_time = unix_time(); + } + } + } + + pthread_mutex_unlock(&conn->mutex); + pthread_mutex_lock(&c->tcp_mutex); + int ret = send_packet_tcp_connection(c->tcp_c, conn->connection_number_tcp, data, length); + pthread_mutex_unlock(&c->tcp_mutex); + + pthread_mutex_lock(&conn->mutex); + + if (ret == 0) { + conn->last_tcp_sent = current_time_monotonic(); + } + + pthread_mutex_unlock(&conn->mutex); + + if (ret == 0 || direct_send_attempt) { + return 0; + } + + return -1; +} + +/** START: Array Related functions **/ + + +/* Return number of packets in array + * Note that holes are counted too. + */ +static uint32_t num_packets_array(const Packets_Array *array) +{ + return array->buffer_end - array->buffer_start; +} + +/* Add data with packet number to array. + * + * return -1 on failure. + * return 0 on success. + */ +static int add_data_to_buffer(Packets_Array *array, uint32_t number, const Packet_Data *data) +{ + if (number - array->buffer_start > CRYPTO_PACKET_BUFFER_SIZE) { + return -1; + } + + uint32_t num = number % CRYPTO_PACKET_BUFFER_SIZE; + + if (array->buffer[num]) { + return -1; + } + + Packet_Data *new_d = (Packet_Data *)malloc(sizeof(Packet_Data)); + + if (new_d == NULL) { + return -1; + } + + memcpy(new_d, data, sizeof(Packet_Data)); + array->buffer[num] = new_d; + + if ((number - array->buffer_start) >= (array->buffer_end - array->buffer_start)) { + array->buffer_end = number + 1; + } + + return 0; +} + +/* Get pointer of data with packet number. + * + * return -1 on failure. + * return 0 if data at number is empty. + * return 1 if data pointer was put in data. + */ +static int get_data_pointer(const Packets_Array *array, Packet_Data **data, uint32_t number) +{ + uint32_t num_spots = array->buffer_end - array->buffer_start; + + if (array->buffer_end - number > num_spots || number - array->buffer_start >= num_spots) { + return -1; + } + + uint32_t num = number % CRYPTO_PACKET_BUFFER_SIZE; + + if (!array->buffer[num]) { + return 0; + } + + *data = array->buffer[num]; + return 1; +} + +/* Add data to end of array. + * + * return -1 on failure. + * return packet number on success. + */ +static int64_t add_data_end_of_buffer(Packets_Array *array, const Packet_Data *data) +{ + if (num_packets_array(array) >= CRYPTO_PACKET_BUFFER_SIZE) { + return -1; + } + + Packet_Data *new_d = (Packet_Data *)malloc(sizeof(Packet_Data)); + + if (new_d == NULL) { + return -1; + } + + memcpy(new_d, data, sizeof(Packet_Data)); + uint32_t id = array->buffer_end; + array->buffer[id % CRYPTO_PACKET_BUFFER_SIZE] = new_d; + ++array->buffer_end; + return id; +} + +/* Read data from begginning of array. + * + * return -1 on failure. + * return packet number on success. + */ +static int64_t read_data_beg_buffer(Packets_Array *array, Packet_Data *data) +{ + if (array->buffer_end == array->buffer_start) { + return -1; + } + + uint32_t num = array->buffer_start % CRYPTO_PACKET_BUFFER_SIZE; + + if (!array->buffer[num]) { + return -1; + } + + memcpy(data, array->buffer[num], sizeof(Packet_Data)); + uint32_t id = array->buffer_start; + ++array->buffer_start; + free(array->buffer[num]); + array->buffer[num] = NULL; + return id; +} + +/* Delete all packets in array before number (but not number) + * + * return -1 on failure. + * return 0 on success + */ +static int clear_buffer_until(Packets_Array *array, uint32_t number) +{ + uint32_t num_spots = array->buffer_end - array->buffer_start; + + if (array->buffer_end - number >= num_spots || number - array->buffer_start > num_spots) { + return -1; + } + + uint32_t i; + + for (i = array->buffer_start; i != number; ++i) { + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (array->buffer[num]) { + free(array->buffer[num]); + array->buffer[num] = NULL; + } + } + + array->buffer_start = i; + return 0; +} + +static int clear_buffer(Packets_Array *array) +{ + uint32_t i; + + for (i = array->buffer_start; i != array->buffer_end; ++i) { + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (array->buffer[num]) { + free(array->buffer[num]); + array->buffer[num] = NULL; + } + } + + array->buffer_start = i; + return 0; +} + +/* Set array buffer end to number. + * + * return -1 on failure. + * return 0 on success. + */ +static int set_buffer_end(Packets_Array *array, uint32_t number) +{ + if ((number - array->buffer_start) > CRYPTO_PACKET_BUFFER_SIZE) { + return -1; + } + + if ((number - array->buffer_end) > CRYPTO_PACKET_BUFFER_SIZE) { + return -1; + } + + array->buffer_end = number; + return 0; +} + +/* Create a packet request packet from recv_array and send_buffer_end into + * data of length. + * + * return -1 on failure. + * return length of packet on success. + */ +static int generate_request_packet(uint8_t *data, uint16_t length, const Packets_Array *recv_array) +{ + if (length == 0) { + return -1; + } + + data[0] = PACKET_ID_REQUEST; + + uint16_t cur_len = 1; + + if (recv_array->buffer_start == recv_array->buffer_end) { + return cur_len; + } + + if (length <= cur_len) { + return cur_len; + } + + uint32_t i, n = 1; + + for (i = recv_array->buffer_start; i != recv_array->buffer_end; ++i) { + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (!recv_array->buffer[num]) { + data[cur_len] = n; + n = 0; + ++cur_len; + + if (length <= cur_len) { + return cur_len; + } + } else if (n == 255) { + data[cur_len] = 0; + n = 0; + ++cur_len; + + if (length <= cur_len) { + return cur_len; + } + } + + ++n; + } + + return cur_len; +} + +/* Handle a request data packet. + * Remove all the packets the other received from the array. + * + * return -1 on failure. + * return number of requested packets on success. + */ +static int handle_request_packet(Packets_Array *send_array, const uint8_t *data, uint16_t length, + uint64_t *latest_send_time, uint64_t rtt_time) +{ + if (length < 1) { + return -1; + } + + if (data[0] != PACKET_ID_REQUEST) { + return -1; + } + + if (length == 1) { + return 0; + } + + ++data; + --length; + + uint32_t i, n = 1; + uint32_t requested = 0; + + uint64_t temp_time = current_time_monotonic(); + uint64_t l_sent_time = ~0; + + for (i = send_array->buffer_start; i != send_array->buffer_end; ++i) { + if (length == 0) { + break; + } + + uint32_t num = i % CRYPTO_PACKET_BUFFER_SIZE; + + if (n == data[0]) { + if (send_array->buffer[num]) { + uint64_t sent_time = send_array->buffer[num]->sent_time; + + if ((sent_time + rtt_time) < temp_time) { + send_array->buffer[num]->sent_time = 0; + } + } + + ++data; + --length; + n = 0; + ++requested; + } else { + if (send_array->buffer[num]) { + uint64_t sent_time = send_array->buffer[num]->sent_time; + + if (l_sent_time < sent_time) { + l_sent_time = sent_time; + } + + free(send_array->buffer[num]); + send_array->buffer[num] = NULL; + } + } + + if (n == 255) { + n = 1; + + if (data[0] != 0) { + return -1; + } + + ++data; + --length; + } else { + ++n; + } + } + + if (*latest_send_time < l_sent_time) { + *latest_send_time = l_sent_time; + } + + return requested; +} + +/** END: Array Related functions **/ + +#define MAX_DATA_DATA_PACKET_SIZE (MAX_CRYPTO_PACKET_SIZE - (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE)) + +/* Creates and sends a data packet to the peer using the fastest route. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_data_packet(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length) +{ + if (length == 0 || length + (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE) > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + pthread_mutex_lock(&conn->mutex); + VLA(uint8_t, packet, 1 + sizeof(uint16_t) + length + CRYPTO_MAC_SIZE); + packet[0] = NET_PACKET_CRYPTO_DATA; + memcpy(packet + 1, conn->sent_nonce + (CRYPTO_NONCE_SIZE - sizeof(uint16_t)), sizeof(uint16_t)); + int len = encrypt_data_symmetric(conn->shared_key, conn->sent_nonce, data, length, packet + 1 + sizeof(uint16_t)); + + if (len + 1 + sizeof(uint16_t) != SIZEOF_VLA(packet)) { + pthread_mutex_unlock(&conn->mutex); + return -1; + } + + increment_nonce(conn->sent_nonce); + pthread_mutex_unlock(&conn->mutex); + + return send_packet_to(c, crypt_connection_id, packet, SIZEOF_VLA(packet)); +} + +/* Creates and sends a data packet with buffer_start and num to the peer using the fastest route. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_data_packet_helper(Net_Crypto *c, int crypt_connection_id, uint32_t buffer_start, uint32_t num, + const uint8_t *data, uint16_t length) +{ + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -1; + } + + num = net_htonl(num); + buffer_start = net_htonl(buffer_start); + uint16_t padding_length = (MAX_CRYPTO_DATA_SIZE - length) % CRYPTO_MAX_PADDING; + VLA(uint8_t, packet, sizeof(uint32_t) + sizeof(uint32_t) + padding_length + length); + memcpy(packet, &buffer_start, sizeof(uint32_t)); + memcpy(packet + sizeof(uint32_t), &num, sizeof(uint32_t)); + memset(packet + (sizeof(uint32_t) * 2), PACKET_ID_PADDING, padding_length); + memcpy(packet + (sizeof(uint32_t) * 2) + padding_length, data, length); + + return send_data_packet(c, crypt_connection_id, packet, SIZEOF_VLA(packet)); +} + +static int reset_max_speed_reached(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + /* If last packet send failed, try to send packet again. + If sending it fails we won't be able to send the new packet. */ + if (conn->maximum_speed_reached) { + Packet_Data *dt = NULL; + uint32_t packet_num = conn->send_array.buffer_end - 1; + int ret = get_data_pointer(&conn->send_array, &dt, packet_num); + + uint8_t send_failed = 0; + + if (ret == 1) { + if (!dt->sent_time) { + if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, dt->data, + dt->length) != 0) { + send_failed = 1; + } else { + dt->sent_time = current_time_monotonic(); + } + } + } + + if (!send_failed) { + conn->maximum_speed_reached = 0; + } else { + return -1; + } + } + + return 0; +} + +/* return -1 if data could not be put in packet queue. + * return positive packet number if data was put into the queue. + */ +static int64_t send_lossless_packet(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length, + uint8_t congestion_control) +{ + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + /* If last packet send failed, try to send packet again. + If sending it fails we won't be able to send the new packet. */ + reset_max_speed_reached(c, crypt_connection_id); + + if (conn->maximum_speed_reached && congestion_control) { + return -1; + } + + Packet_Data dt; + dt.sent_time = 0; + dt.length = length; + memcpy(dt.data, data, length); + pthread_mutex_lock(&conn->mutex); + int64_t packet_num = add_data_end_of_buffer(&conn->send_array, &dt); + pthread_mutex_unlock(&conn->mutex); + + if (packet_num == -1) { + return -1; + } + + if (!congestion_control && conn->maximum_speed_reached) { + return packet_num; + } + + if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, data, length) == 0) { + Packet_Data *dt1 = NULL; + + if (get_data_pointer(&conn->send_array, &dt1, packet_num) == 1) { + dt1->sent_time = current_time_monotonic(); + } + } else { + conn->maximum_speed_reached = 1; + LOGGER_ERROR(c->log, "send_data_packet failed\n"); + } + + return packet_num; +} + +/* Get the lowest 2 bytes from the nonce and convert + * them to host byte format before returning them. + */ +static uint16_t get_nonce_uint16(const uint8_t *nonce) +{ + uint16_t num; + memcpy(&num, nonce + (CRYPTO_NONCE_SIZE - sizeof(uint16_t)), sizeof(uint16_t)); + return net_ntohs(num); +} + +#define DATA_NUM_THRESHOLD 21845 + +/* Handle a data packet. + * Decrypt packet of length and put it into data. + * data must be at least MAX_DATA_DATA_PACKET_SIZE big. + * + * return -1 on failure. + * return length of data on success. + */ +static int handle_data_packet(const Net_Crypto *c, int crypt_connection_id, uint8_t *data, const uint8_t *packet, + uint16_t length) +{ + if (length <= (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE) || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + memcpy(nonce, conn->recv_nonce, CRYPTO_NONCE_SIZE); + uint16_t num_cur_nonce = get_nonce_uint16(nonce); + uint16_t num; + memcpy(&num, packet + 1, sizeof(uint16_t)); + num = net_ntohs(num); + uint16_t diff = num - num_cur_nonce; + increment_nonce_number(nonce, diff); + int len = decrypt_data_symmetric(conn->shared_key, nonce, packet + 1 + sizeof(uint16_t), + length - (1 + sizeof(uint16_t)), data); + + if ((unsigned int)len != length - (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE)) { + return -1; + } + + if (diff > DATA_NUM_THRESHOLD * 2) { + increment_nonce_number(conn->recv_nonce, DATA_NUM_THRESHOLD); + } + + return len; +} + +/* Send a request packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_request_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t data[MAX_CRYPTO_DATA_SIZE]; + int len = generate_request_packet(data, sizeof(data), &conn->recv_array); + + if (len == -1) { + return -1; + } + + return send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, conn->send_array.buffer_end, data, + len); +} + +/* Send up to max num previously requested data packets. + * + * return -1 on failure. + * return number of packets sent on success. + */ +static int send_requested_packets(Net_Crypto *c, int crypt_connection_id, uint32_t max_num) +{ + if (max_num == 0) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint64_t temp_time = current_time_monotonic(); + uint32_t i, num_sent = 0, array_size = num_packets_array(&conn->send_array); + + for (i = 0; i < array_size; ++i) { + Packet_Data *dt; + uint32_t packet_num = (i + conn->send_array.buffer_start); + int ret = get_data_pointer(&conn->send_array, &dt, packet_num); + + if (ret == -1) { + return -1; + } + + if (ret == 0) { + continue; + } + + if (dt->sent_time) { + continue; + } + + if (send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, packet_num, dt->data, + dt->length) == 0) { + dt->sent_time = temp_time; + ++num_sent; + } + + if (num_sent >= max_num) { + break; + } + } + + return num_sent; +} + + +/* Add a new temp packet to send repeatedly. + * + * return -1 on failure. + * return 0 on success. + */ +static int new_temp_packet(const Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t *temp_packet = (uint8_t *)malloc(length); + + if (temp_packet == 0) { + return -1; + } + + if (conn->temp_packet) { + free(conn->temp_packet); + } + + memcpy(temp_packet, packet, length); + conn->temp_packet = temp_packet; + conn->temp_packet_length = length; + conn->temp_packet_sent_time = 0; + conn->temp_packet_num_sent = 0; + return 0; +} + +/* Clear the temp packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int clear_temp_packet(const Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (conn->temp_packet) { + free(conn->temp_packet); + } + + conn->temp_packet = 0; + conn->temp_packet_length = 0; + conn->temp_packet_sent_time = 0; + conn->temp_packet_num_sent = 0; + return 0; +} + + +/* Send the temp packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_temp_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (!conn->temp_packet) { + return -1; + } + + if (send_packet_to(c, crypt_connection_id, conn->temp_packet, conn->temp_packet_length) != 0) { + return -1; + } + + conn->temp_packet_sent_time = current_time_monotonic(); + ++conn->temp_packet_num_sent; + return 0; +} + +/* Create a handshake packet and set it as a temp packet. + * cookie must be COOKIE_LENGTH. + * + * return -1 on failure. + * return 0 on success. + */ +static int create_send_handshake(Net_Crypto *c, int crypt_connection_id, const uint8_t *cookie, + const uint8_t *dht_public_key) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t handshake_packet[HANDSHAKE_PACKET_LENGTH]; + + if (create_crypto_handshake(c, handshake_packet, cookie, conn->sent_nonce, conn->sessionpublic_key, + conn->public_key, dht_public_key) != sizeof(handshake_packet)) { + return -1; + } + + if (new_temp_packet(c, crypt_connection_id, handshake_packet, sizeof(handshake_packet)) != 0) { + return -1; + } + + send_temp_packet(c, crypt_connection_id); + return 0; +} + +/* Send a kill packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_kill_packet(Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t kill_packet = PACKET_ID_KILL; + return send_data_packet_helper(c, crypt_connection_id, conn->recv_array.buffer_start, conn->send_array.buffer_end, + &kill_packet, sizeof(kill_packet)); +} + +static void connection_kill(Net_Crypto *c, int crypt_connection_id, void *userdata) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return; + } + + if (conn->connection_status_callback) { + conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 0, + userdata); + } + + crypto_kill(c, crypt_connection_id); +} + +/* Handle a received data packet. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_data_packet_core(Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length, + bool udp, void *userdata) +{ + if (length > MAX_CRYPTO_PACKET_SIZE || length <= CRYPTO_DATA_PACKET_MIN_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint8_t data[MAX_DATA_DATA_PACKET_SIZE]; + int len = handle_data_packet(c, crypt_connection_id, data, packet, length); + + if (len <= (int)(sizeof(uint32_t) * 2)) { + return -1; + } + + uint32_t buffer_start, num; + memcpy(&buffer_start, data, sizeof(uint32_t)); + memcpy(&num, data + sizeof(uint32_t), sizeof(uint32_t)); + buffer_start = net_ntohl(buffer_start); + num = net_ntohl(num); + + uint64_t rtt_calc_time = 0; + + if (buffer_start != conn->send_array.buffer_start) { + Packet_Data *packet_time; + + if (get_data_pointer(&conn->send_array, &packet_time, conn->send_array.buffer_start) == 1) { + rtt_calc_time = packet_time->sent_time; + } + + if (clear_buffer_until(&conn->send_array, buffer_start) != 0) { + return -1; + } + } + + uint8_t *real_data = data + (sizeof(uint32_t) * 2); + uint16_t real_length = len - (sizeof(uint32_t) * 2); + + while (real_data[0] == PACKET_ID_PADDING) { /* Remove Padding */ + ++real_data; + --real_length; + + if (real_length == 0) { + return -1; + } + } + + if (real_data[0] == PACKET_ID_KILL) { + connection_kill(c, crypt_connection_id, userdata); + return 0; + } + + if (conn->status == CRYPTO_CONN_NOT_CONFIRMED) { + clear_temp_packet(c, crypt_connection_id); + conn->status = CRYPTO_CONN_ESTABLISHED; + + if (conn->connection_status_callback) { + conn->connection_status_callback(conn->connection_status_callback_object, conn->connection_status_callback_id, 1, + userdata); + } + } + + if (real_data[0] == PACKET_ID_REQUEST) { + uint64_t rtt_time; + + if (udp) { + rtt_time = conn->rtt_time; + } else { + rtt_time = DEFAULT_TCP_PING_CONNECTION; + } + + int requested = handle_request_packet(&conn->send_array, real_data, real_length, &rtt_calc_time, rtt_time); + + if (requested == -1) { + return -1; + } + + // else { /* TODO(irungentoo): ? */ } + + set_buffer_end(&conn->recv_array, num); + } else if (real_data[0] >= CRYPTO_RESERVED_PACKETS && real_data[0] < PACKET_ID_LOSSY_RANGE_START) { + Packet_Data dt; + dt.length = real_length; + memcpy(dt.data, real_data, real_length); + + if (add_data_to_buffer(&conn->recv_array, num, &dt) != 0) { + return -1; + } + + while (1) { + pthread_mutex_lock(&conn->mutex); + int ret = read_data_beg_buffer(&conn->recv_array, &dt); + pthread_mutex_unlock(&conn->mutex); + + if (ret == -1) { + break; + } + + if (conn->connection_data_callback) { + conn->connection_data_callback(conn->connection_data_callback_object, conn->connection_data_callback_id, dt.data, + dt.length, userdata); + } + + /* conn might get killed in callback. */ + conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + } + + /* Packet counter. */ + ++conn->packet_counter; + } else if (real_data[0] >= PACKET_ID_LOSSY_RANGE_START && + real_data[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE)) { + + set_buffer_end(&conn->recv_array, num); + + if (conn->connection_lossy_data_callback) { + conn->connection_lossy_data_callback(conn->connection_lossy_data_callback_object, + conn->connection_lossy_data_callback_id, real_data, real_length, userdata); + } + } else { + return -1; + } + + if (rtt_calc_time != 0) { + uint64_t rtt_time = current_time_monotonic() - rtt_calc_time; + + if (rtt_time < conn->rtt_time) { + conn->rtt_time = rtt_time; + } + } + + return 0; +} + +/* Handle a packet that was received for the connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_packet_connection(Net_Crypto *c, int crypt_connection_id, const uint8_t *packet, uint16_t length, + bool udp, void *userdata) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + switch (packet[0]) { + case NET_PACKET_COOKIE_RESPONSE: { + if (conn->status != CRYPTO_CONN_COOKIE_REQUESTING) { + return -1; + } + + uint8_t cookie[COOKIE_LENGTH]; + uint64_t number; + + if (handle_cookie_response(cookie, &number, packet, length, conn->shared_key) != sizeof(cookie)) { + return -1; + } + + if (number != conn->cookie_request_number) { + return -1; + } + + if (create_send_handshake(c, crypt_connection_id, cookie, conn->dht_public_key) != 0) { + return -1; + } + + conn->status = CRYPTO_CONN_HANDSHAKE_SENT; + return 0; + } + + case NET_PACKET_CRYPTO_HS: { + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT + || conn->status == CRYPTO_CONN_NOT_CONFIRMED) { + uint8_t peer_real_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t cookie[COOKIE_LENGTH]; + + if (handle_crypto_handshake(c, conn->recv_nonce, conn->peersessionpublic_key, peer_real_pk, dht_public_key, cookie, + packet, length, conn->public_key) != 0) { + return -1; + } + + if (public_key_cmp(dht_public_key, conn->dht_public_key) == 0) { + encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key); + + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING) { + if (create_send_handshake(c, crypt_connection_id, cookie, dht_public_key) != 0) { + return -1; + } + } + + conn->status = CRYPTO_CONN_NOT_CONFIRMED; + } else { + if (conn->dht_pk_callback) { + conn->dht_pk_callback(conn->dht_pk_callback_object, conn->dht_pk_callback_number, dht_public_key, userdata); + } + } + } else { + return -1; + } + + return 0; + } + + case NET_PACKET_CRYPTO_DATA: { + if (conn->status == CRYPTO_CONN_NOT_CONFIRMED || conn->status == CRYPTO_CONN_ESTABLISHED) { + return handle_data_packet_core(c, crypt_connection_id, packet, length, udp, userdata); + } + + return -1; + } + + default: { + return -1; + } + } +} + +/* Set the size of the friend list to numfriends. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_cryptoconnection(Net_Crypto *c, uint32_t num) +{ + if (num == 0) { + free(c->crypto_connections); + c->crypto_connections = NULL; + return 0; + } + + Crypto_Connection *newcrypto_connections = (Crypto_Connection *)realloc(c->crypto_connections, + num * sizeof(Crypto_Connection)); + + if (newcrypto_connections == NULL) { + return -1; + } + + c->crypto_connections = newcrypto_connections; + return 0; +} + + +/* Create a new empty crypto connection. + * + * return -1 on failure. + * return connection id on success. + */ +static int create_crypto_connection(Net_Crypto *c) +{ + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + if (c->crypto_connections[i].status == CRYPTO_CONN_NO_CONNECTION) { + return i; + } + } + + while (1) { /* TODO(irungentoo): is this really the best way to do this? */ + pthread_mutex_lock(&c->connections_mutex); + + if (!c->connection_use_counter) { + break; + } + + pthread_mutex_unlock(&c->connections_mutex); + } + + int id = -1; + + if (realloc_cryptoconnection(c, c->crypto_connections_length + 1) == 0) { + id = c->crypto_connections_length; + ++c->crypto_connections_length; + memset(&(c->crypto_connections[id]), 0, sizeof(Crypto_Connection)); + // Memsetting float/double to 0 is non-portable, so we explicitly set them to 0 + c->crypto_connections[id].packet_recv_rate = 0; + c->crypto_connections[id].packet_send_rate = 0; + c->crypto_connections[id].last_packets_left_rem = 0; + c->crypto_connections[id].packet_send_rate_requested = 0; + c->crypto_connections[id].last_packets_left_requested_rem = 0; + + if (pthread_mutex_init(&c->crypto_connections[id].mutex, NULL) != 0) { + pthread_mutex_unlock(&c->connections_mutex); + return -1; + } + } + + pthread_mutex_unlock(&c->connections_mutex); + return id; +} + +/* Wipe a crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +static int wipe_crypto_connection(Net_Crypto *c, int crypt_connection_id) +{ + if (crypt_connection_id_not_valid(c, crypt_connection_id)) { + return -1; + } + + uint32_t i; + + /* Keep mutex, only destroy it when connection is realloced out. */ + pthread_mutex_t mutex = c->crypto_connections[crypt_connection_id].mutex; + crypto_memzero(&(c->crypto_connections[crypt_connection_id]), sizeof(Crypto_Connection)); + c->crypto_connections[crypt_connection_id].mutex = mutex; + + for (i = c->crypto_connections_length; i != 0; --i) { + if (c->crypto_connections[i - 1].status == CRYPTO_CONN_NO_CONNECTION) { + pthread_mutex_destroy(&c->crypto_connections[i - 1].mutex); + } else { + break; + } + } + + if (c->crypto_connections_length != i) { + c->crypto_connections_length = i; + realloc_cryptoconnection(c, c->crypto_connections_length); + } + + return 0; +} + +/* Get crypto connection id from public key of peer. + * + * return -1 if there are no connections like we are looking for. + * return id if it found it. + */ +static int getcryptconnection_id(const Net_Crypto *c, const uint8_t *public_key) +{ + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + if (c->crypto_connections[i].status != CRYPTO_CONN_NO_CONNECTION) { + if (public_key_cmp(public_key, c->crypto_connections[i].public_key) == 0) { + return i; + } + } + } + + return -1; +} + +/* Add a source to the crypto connection. + * This is to be used only when we have received a packet from that source. + * + * return -1 on failure. + * return positive number on success. + * 0 if source was a direct UDP connection. + */ +static int crypto_connection_add_source(Net_Crypto *c, int crypt_connection_id, IP_Port source) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (source.ip.family == TOX_AF_INET || source.ip.family == TOX_AF_INET6) { + if (add_ip_port_connection(c, crypt_connection_id, source) != 0) { + return -1; + } + + if (source.ip.family == TOX_AF_INET) { + conn->direct_lastrecv_timev4 = unix_time(); + } else { + conn->direct_lastrecv_timev6 = unix_time(); + } + + return 0; + } + + if (source.ip.family == TCP_FAMILY) { + if (add_tcp_number_relay_connection(c->tcp_c, conn->connection_number_tcp, source.ip.ip6.uint32[0]) == 0) { + return 1; + } + } + + return -1; +} + + +/* Set function to be called when someone requests a new connection to us. + * + * The set function should return -1 on failure and 0 on success. + * + * n_c is only valid for the duration of the function call. + */ +void new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *object, New_Connection *n_c), + void *object) +{ + c->new_connection_callback = new_connection_callback; + c->new_connection_callback_object = object; +} + +/* Handle a handshake packet by someone who wants to initiate a new connection with us. + * This calls the callback set by new_connection_handler() if the handshake is ok. + * + * return -1 on failure. + * return 0 on success. + */ +static int handle_new_connection_handshake(Net_Crypto *c, IP_Port source, const uint8_t *data, uint16_t length, + void *userdata) +{ + New_Connection n_c; + n_c.cookie = (uint8_t *)malloc(COOKIE_LENGTH); + + if (n_c.cookie == NULL) { + return -1; + } + + n_c.source = source; + n_c.cookie_length = COOKIE_LENGTH; + + if (handle_crypto_handshake(c, n_c.recv_nonce, n_c.peersessionpublic_key, n_c.public_key, n_c.dht_public_key, + n_c.cookie, data, length, 0) != 0) { + free(n_c.cookie); + return -1; + } + + int crypt_connection_id = getcryptconnection_id(c, n_c.public_key); + + if (crypt_connection_id != -1) { + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (public_key_cmp(n_c.dht_public_key, conn->dht_public_key) != 0) { + connection_kill(c, crypt_connection_id, userdata); + } else { + int ret = -1; + + if (conn && (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT)) { + memcpy(conn->recv_nonce, n_c.recv_nonce, CRYPTO_NONCE_SIZE); + memcpy(conn->peersessionpublic_key, n_c.peersessionpublic_key, CRYPTO_PUBLIC_KEY_SIZE); + encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key); + + crypto_connection_add_source(c, crypt_connection_id, source); + + if (create_send_handshake(c, crypt_connection_id, n_c.cookie, n_c.dht_public_key) == 0) { + conn->status = CRYPTO_CONN_NOT_CONFIRMED; + ret = 0; + } + } + + free(n_c.cookie); + return ret; + } + } + + int ret = c->new_connection_callback(c->new_connection_callback_object, &n_c); + free(n_c.cookie); + return ret; +} + +/* Accept a crypto connection. + * + * return -1 on failure. + * return connection id on success. + */ +int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c) +{ + if (getcryptconnection_id(c, n_c->public_key) != -1) { + return -1; + } + + int crypt_connection_id = create_crypto_connection(c); + + if (crypt_connection_id == -1) { + return -1; + } + + Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id]; + + if (n_c->cookie_length != COOKIE_LENGTH) { + return -1; + } + + pthread_mutex_lock(&c->tcp_mutex); + int connection_number_tcp = new_tcp_connection_to(c->tcp_c, n_c->dht_public_key, crypt_connection_id); + pthread_mutex_unlock(&c->tcp_mutex); + + if (connection_number_tcp == -1) { + return -1; + } + + conn->connection_number_tcp = connection_number_tcp; + memcpy(conn->public_key, n_c->public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(conn->recv_nonce, n_c->recv_nonce, CRYPTO_NONCE_SIZE); + memcpy(conn->peersessionpublic_key, n_c->peersessionpublic_key, CRYPTO_PUBLIC_KEY_SIZE); + random_nonce(conn->sent_nonce); + crypto_new_keypair(conn->sessionpublic_key, conn->sessionsecret_key); + encrypt_precompute(conn->peersessionpublic_key, conn->sessionsecret_key, conn->shared_key); + conn->status = CRYPTO_CONN_NOT_CONFIRMED; + + if (create_send_handshake(c, crypt_connection_id, n_c->cookie, n_c->dht_public_key) != 0) { + pthread_mutex_lock(&c->tcp_mutex); + kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); + pthread_mutex_unlock(&c->tcp_mutex); + conn->status = CRYPTO_CONN_NO_CONNECTION; + return -1; + } + + memcpy(conn->dht_public_key, n_c->dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); + conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; + conn->packet_send_rate_requested = CRYPTO_PACKET_MIN_RATE; + conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; + conn->rtt_time = DEFAULT_PING_CONNECTION; + crypto_connection_add_source(c, crypt_connection_id, n_c->source); + return crypt_connection_id; +} + +/* Create a crypto connection. + * If one to that real public key already exists, return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const uint8_t *dht_public_key) +{ + int crypt_connection_id = getcryptconnection_id(c, real_public_key); + + if (crypt_connection_id != -1) { + return crypt_connection_id; + } + + crypt_connection_id = create_crypto_connection(c); + + if (crypt_connection_id == -1) { + return -1; + } + + Crypto_Connection *conn = &c->crypto_connections[crypt_connection_id]; + + if (conn == 0) { + return -1; + } + + pthread_mutex_lock(&c->tcp_mutex); + int connection_number_tcp = new_tcp_connection_to(c->tcp_c, dht_public_key, crypt_connection_id); + pthread_mutex_unlock(&c->tcp_mutex); + + if (connection_number_tcp == -1) { + return -1; + } + + conn->connection_number_tcp = connection_number_tcp; + memcpy(conn->public_key, real_public_key, CRYPTO_PUBLIC_KEY_SIZE); + random_nonce(conn->sent_nonce); + crypto_new_keypair(conn->sessionpublic_key, conn->sessionsecret_key); + conn->status = CRYPTO_CONN_COOKIE_REQUESTING; + conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; + conn->packet_send_rate_requested = CRYPTO_PACKET_MIN_RATE; + conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; + conn->rtt_time = DEFAULT_PING_CONNECTION; + memcpy(conn->dht_public_key, dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + conn->cookie_request_number = random_64b(); + uint8_t cookie_request[COOKIE_REQUEST_LENGTH]; + + if (create_cookie_request(c, cookie_request, conn->dht_public_key, conn->cookie_request_number, + conn->shared_key) != sizeof(cookie_request) + || new_temp_packet(c, crypt_connection_id, cookie_request, sizeof(cookie_request)) != 0) { + pthread_mutex_lock(&c->tcp_mutex); + kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); + pthread_mutex_unlock(&c->tcp_mutex); + conn->status = CRYPTO_CONN_NO_CONNECTION; + return -1; + } + + return crypt_connection_id; +} + +/* Set the direct ip of the crypto connection. + * + * Connected is 0 if we are not sure we are connected to that person, 1 if we are sure. + * + * return -1 on failure. + * return 0 on success. + */ +int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, bool connected) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (add_ip_port_connection(c, crypt_connection_id, ip_port) == 0) { + if (connected) { + if (ip_port.ip.family == TOX_AF_INET) { + conn->direct_lastrecv_timev4 = unix_time(); + } else { + conn->direct_lastrecv_timev6 = unix_time(); + } + } else { + if (ip_port.ip.family == TOX_AF_INET) { + conn->direct_lastrecv_timev4 = 0; + } else { + conn->direct_lastrecv_timev6 = 0; + } + } + + return 0; + } + + return -1; +} + + +static int tcp_data_callback(void *object, int id, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Net_Crypto *c = (Net_Crypto *)object; + + Crypto_Connection *conn = get_crypto_connection(c, id); + + if (conn == 0) { + return -1; + } + + if (data[0] == NET_PACKET_COOKIE_REQUEST) { + return tcp_handle_cookie_request(c, conn->connection_number_tcp, data, length); + } + + // This unlocks the mutex that at this point is locked by do_tcp before + // calling do_tcp_connections. + pthread_mutex_unlock(&c->tcp_mutex); + int ret = handle_packet_connection(c, id, data, length, 0, userdata); + pthread_mutex_lock(&c->tcp_mutex); + + if (ret != 0) { + return -1; + } + + // TODO(irungentoo): detect and kill bad TCP connections. + return 0; +} + +static int tcp_oob_callback(void *object, const uint8_t *public_key, unsigned int tcp_connections_number, + const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0 || length > MAX_CRYPTO_PACKET_SIZE) { + return -1; + } + + Net_Crypto *c = (Net_Crypto *)object; + + if (data[0] == NET_PACKET_COOKIE_REQUEST) { + return tcp_oob_handle_cookie_request(c, tcp_connections_number, public_key, data, length); + } + + if (data[0] == NET_PACKET_CRYPTO_HS) { + IP_Port source; + source.port = 0; + source.ip.family = TCP_FAMILY; + source.ip.ip6.uint32[0] = tcp_connections_number; + + if (handle_new_connection_handshake(c, source, data, length, userdata) != 0) { + return -1; + } + + return 0; + } + + return -1; +} + +/* Add a tcp relay, associating it to a crypt_connection_id. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, const uint8_t *public_key) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + pthread_mutex_lock(&c->tcp_mutex); + int ret = add_tcp_relay_connection(c->tcp_c, conn->connection_number_tcp, ip_port, public_key); + pthread_mutex_unlock(&c->tcp_mutex); + return ret; +} + +/* Add a tcp relay to the array. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key) +{ + pthread_mutex_lock(&c->tcp_mutex); + int ret = add_tcp_relay_global(c->tcp_c, ip_port, public_key); + pthread_mutex_unlock(&c->tcp_mutex); + return ret; +} + +/* Return a random TCP connection number for use in send_tcp_onion_request. + * + * TODO(irungentoo): This number is just the index of an array that the elements can + * change without warning. + * + * return TCP connection number on success. + * return -1 on failure. + */ +int get_random_tcp_con_number(Net_Crypto *c) +{ + pthread_mutex_lock(&c->tcp_mutex); + int ret = get_random_tcp_onion_conn_number(c->tcp_c); + pthread_mutex_unlock(&c->tcp_mutex); + + return ret; +} + +/* Send an onion packet via the TCP relay corresponding to tcp_connections_number. + * + * return 0 on success. + * return -1 on failure. + */ +int send_tcp_onion_request(Net_Crypto *c, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length) +{ + pthread_mutex_lock(&c->tcp_mutex); + int ret = tcp_send_onion_request(c->tcp_c, tcp_connections_number, data, length); + pthread_mutex_unlock(&c->tcp_mutex); + + return ret; +} + +/* Copy a maximum of num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. + * + * return number of relays copied to tcp_relays on success. + * return 0 on failure. + */ +unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num) +{ + if (num == 0) { + return 0; + } + + pthread_mutex_lock(&c->tcp_mutex); + unsigned int ret = tcp_copy_connected_relays(c->tcp_c, tcp_relays, num); + pthread_mutex_unlock(&c->tcp_mutex); + + return ret; +} + +static void do_tcp(Net_Crypto *c, void *userdata) +{ + pthread_mutex_lock(&c->tcp_mutex); + do_tcp_connections(c->tcp_c, userdata); + pthread_mutex_unlock(&c->tcp_mutex); + + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + Crypto_Connection *conn = get_crypto_connection(c, i); + + if (conn == 0) { + return; + } + + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + bool direct_connected = 0; + crypto_connection_status(c, i, &direct_connected, NULL); + + if (direct_connected) { + pthread_mutex_lock(&c->tcp_mutex); + set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 0); + pthread_mutex_unlock(&c->tcp_mutex); + } else { + pthread_mutex_lock(&c->tcp_mutex); + set_tcp_connection_to_status(c->tcp_c, conn->connection_number_tcp, 1); + pthread_mutex_unlock(&c->tcp_mutex); + } + } + } +} + +/* Set function to be called when connection with crypt_connection_id goes connects/disconnects. + * + * The set function should return -1 on failure and 0 on success. + * Note that if this function is set, the connection will clear itself on disconnect. + * Object and id will be passed to this function untouched. + * status is 1 if the connection is going online, 0 if it is going offline. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_status_handler(const Net_Crypto *c, int crypt_connection_id, + int (*connection_status_callback)(void *object, int id, uint8_t status, void *userdata), void *object, int id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + conn->connection_status_callback = connection_status_callback; + conn->connection_status_callback_object = object; + conn->connection_status_callback_id = id; + return 0; +} + +/* Set function to be called when connection with crypt_connection_id receives a data packet of length. + * + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_data_handler(const Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object, + int id, const uint8_t *data, uint16_t length, void *userdata), void *object, int id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + conn->connection_data_callback = connection_data_callback; + conn->connection_data_callback_object = object; + conn->connection_data_callback_id = id; + return 0; +} + +/* Set function to be called when connection with crypt_connection_id receives a lossy data packet of length. + * + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id, + int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata), + void *object, int id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + conn->connection_lossy_data_callback = connection_lossy_data_callback; + conn->connection_lossy_data_callback_object = object; + conn->connection_lossy_data_callback_id = id; + return 0; +} + + +/* Set the function for this friend that will be callbacked with object and number if + * the friend sends us a different dht public key than we have associated to him. + * + * If this function is called, the connection should be recreated with the new public key. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number, + const uint8_t *dht_public_key, void *userdata), void *object, uint32_t number) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + conn->dht_pk_callback = function; + conn->dht_pk_callback_object = object; + conn->dht_pk_callback_number = number; + return 0; +} + +/* Get the crypto connection id from the ip_port. + * + * return -1 on failure. + * return connection id on success. + */ +static int crypto_id_ip_port(const Net_Crypto *c, IP_Port ip_port) +{ + return bs_list_find(&c->ip_port_list, (uint8_t *)&ip_port); +} + +#define CRYPTO_MIN_PACKET_SIZE (1 + sizeof(uint16_t) + CRYPTO_MAC_SIZE) + +/* Handle raw UDP packets coming directly from the socket. + * + * Handles: + * Cookie response packets. + * Crypto handshake packets. + * Crypto data packets. + * + */ +static int udp_handle_packet(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + if (length <= CRYPTO_MIN_PACKET_SIZE || length > MAX_CRYPTO_PACKET_SIZE) { + return 1; + } + + Net_Crypto *c = (Net_Crypto *)object; + int crypt_connection_id = crypto_id_ip_port(c, source); + + if (crypt_connection_id == -1) { + if (packet[0] != NET_PACKET_CRYPTO_HS) { + return 1; + } + + if (handle_new_connection_handshake(c, source, packet, length, userdata) != 0) { + return 1; + } + + return 0; + } + + if (handle_packet_connection(c, crypt_connection_id, packet, length, 1, userdata) != 0) { + return 1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + pthread_mutex_lock(&conn->mutex); + + if (source.ip.family == TOX_AF_INET) { + conn->direct_lastrecv_timev4 = unix_time(); + } else { + conn->direct_lastrecv_timev6 = unix_time(); + } + + pthread_mutex_unlock(&conn->mutex); + return 0; +} + +/* The dT for the average packet receiving rate calculations. + Also used as the */ +#define PACKET_COUNTER_AVERAGE_INTERVAL 50 + +/* Ratio of recv queue size / recv packet rate (in seconds) times + * the number of ms between request packets to send at that ratio + */ +#define REQUEST_PACKETS_COMPARE_CONSTANT (0.125 * 100.0) + +/* Timeout for increasing speed after congestion event (in ms). */ +#define CONGESTION_EVENT_TIMEOUT 1000 + +/* If the send queue is SEND_QUEUE_RATIO times larger than the + * calculated link speed the packet send speed will be reduced + * by a value depending on this number. + */ +#define SEND_QUEUE_RATIO 2.0 + +static void send_crypto_packets(Net_Crypto *c) +{ + uint32_t i; + uint64_t temp_time = current_time_monotonic(); + double total_send_rate = 0; + uint32_t peak_request_packet_interval = ~0; + + for (i = 0; i < c->crypto_connections_length; ++i) { + Crypto_Connection *conn = get_crypto_connection(c, i); + + if (conn == 0) { + return; + } + + if (CRYPTO_SEND_PACKET_INTERVAL + conn->temp_packet_sent_time < temp_time) { + send_temp_packet(c, i); + } + + if ((conn->status == CRYPTO_CONN_NOT_CONFIRMED || conn->status == CRYPTO_CONN_ESTABLISHED) + && ((CRYPTO_SEND_PACKET_INTERVAL) + conn->last_request_packet_sent) < temp_time) { + if (send_request_packet(c, i) == 0) { + conn->last_request_packet_sent = temp_time; + } + } + + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + if (conn->packet_recv_rate > CRYPTO_PACKET_MIN_RATE) { + double request_packet_interval = (REQUEST_PACKETS_COMPARE_CONSTANT / ((num_packets_array( + &conn->recv_array) + 1.0) / (conn->packet_recv_rate + 1.0))); + + double request_packet_interval2 = ((CRYPTO_PACKET_MIN_RATE / conn->packet_recv_rate) * + (double)CRYPTO_SEND_PACKET_INTERVAL) + (double)PACKET_COUNTER_AVERAGE_INTERVAL; + + if (request_packet_interval2 < request_packet_interval) { + request_packet_interval = request_packet_interval2; + } + + if (request_packet_interval < PACKET_COUNTER_AVERAGE_INTERVAL) { + request_packet_interval = PACKET_COUNTER_AVERAGE_INTERVAL; + } + + if (request_packet_interval > CRYPTO_SEND_PACKET_INTERVAL) { + request_packet_interval = CRYPTO_SEND_PACKET_INTERVAL; + } + + if (temp_time - conn->last_request_packet_sent > (uint64_t)request_packet_interval) { + if (send_request_packet(c, i) == 0) { + conn->last_request_packet_sent = temp_time; + } + } + + if (request_packet_interval < peak_request_packet_interval) { + peak_request_packet_interval = request_packet_interval; + } + } + + if ((PACKET_COUNTER_AVERAGE_INTERVAL + conn->packet_counter_set) < temp_time) { + + double dt = temp_time - conn->packet_counter_set; + + conn->packet_recv_rate = (double)conn->packet_counter / (dt / 1000.0); + conn->packet_counter = 0; + conn->packet_counter_set = temp_time; + + uint32_t packets_sent = conn->packets_sent; + conn->packets_sent = 0; + + uint32_t packets_resent = conn->packets_resent; + conn->packets_resent = 0; + + /* conjestion control + calculate a new value of conn->packet_send_rate based on some data + */ + + unsigned int pos = conn->last_sendqueue_counter % CONGESTION_QUEUE_ARRAY_SIZE; + conn->last_sendqueue_size[pos] = num_packets_array(&conn->send_array); + ++conn->last_sendqueue_counter; + + unsigned int j; + long signed int sum = 0; + sum = (long signed int)conn->last_sendqueue_size[(pos) % CONGESTION_QUEUE_ARRAY_SIZE] - + (long signed int)conn->last_sendqueue_size[(pos - (CONGESTION_QUEUE_ARRAY_SIZE - 1)) % CONGESTION_QUEUE_ARRAY_SIZE]; + + unsigned int n_p_pos = conn->last_sendqueue_counter % CONGESTION_LAST_SENT_ARRAY_SIZE; + conn->last_num_packets_sent[n_p_pos] = packets_sent; + conn->last_num_packets_resent[n_p_pos] = packets_resent; + + bool direct_connected = 0; + crypto_connection_status(c, i, &direct_connected, NULL); + + if (direct_connected && conn->last_tcp_sent + CONGESTION_EVENT_TIMEOUT > temp_time) { + /* When switching from TCP to UDP, don't change the packet send rate for CONGESTION_EVENT_TIMEOUT ms. */ + } else { + long signed int total_sent = 0, total_resent = 0; + + // TODO(irungentoo): use real delay + unsigned int delay = (unsigned int)((conn->rtt_time / PACKET_COUNTER_AVERAGE_INTERVAL) + 0.5); + unsigned int packets_set_rem_array = (CONGESTION_LAST_SENT_ARRAY_SIZE - CONGESTION_QUEUE_ARRAY_SIZE); + + if (delay > packets_set_rem_array) { + delay = packets_set_rem_array; + } + + for (j = 0; j < CONGESTION_QUEUE_ARRAY_SIZE; ++j) { + unsigned int ind = (j + (packets_set_rem_array - delay) + n_p_pos) % CONGESTION_LAST_SENT_ARRAY_SIZE; + total_sent += conn->last_num_packets_sent[ind]; + total_resent += conn->last_num_packets_resent[ind]; + } + + if (sum > 0) { + total_sent -= sum; + } else { + if (total_resent > -sum) { + total_resent = -sum; + } + } + + /* if queue is too big only allow resending packets. */ + uint32_t npackets = num_packets_array(&conn->send_array); + double min_speed = 1000.0 * (((double)(total_sent)) / ((double)(CONGESTION_QUEUE_ARRAY_SIZE) * + PACKET_COUNTER_AVERAGE_INTERVAL)); + + double min_speed_request = 1000.0 * (((double)(total_sent + total_resent)) / ((double)( + CONGESTION_QUEUE_ARRAY_SIZE) * PACKET_COUNTER_AVERAGE_INTERVAL)); + + if (min_speed < CRYPTO_PACKET_MIN_RATE) { + min_speed = CRYPTO_PACKET_MIN_RATE; + } + + double send_array_ratio = (((double)npackets) / min_speed); + + // TODO(irungentoo): Improve formula? + if (send_array_ratio > SEND_QUEUE_RATIO && CRYPTO_MIN_QUEUE_LENGTH < npackets) { + conn->packet_send_rate = min_speed * (1.0 / (send_array_ratio / SEND_QUEUE_RATIO)); + } else if (conn->last_congestion_event + CONGESTION_EVENT_TIMEOUT < temp_time) { + conn->packet_send_rate = min_speed * 1.2; + } else { + conn->packet_send_rate = min_speed * 0.9; + } + + conn->packet_send_rate_requested = min_speed_request * 1.2; + + if (conn->packet_send_rate < CRYPTO_PACKET_MIN_RATE) { + conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE; + } + + if (conn->packet_send_rate_requested < conn->packet_send_rate) { + conn->packet_send_rate_requested = conn->packet_send_rate; + } + } + } + + if (conn->last_packets_left_set == 0 || conn->last_packets_left_requested_set == 0) { + conn->last_packets_left_requested_set = conn->last_packets_left_set = temp_time; + conn->packets_left_requested = conn->packets_left = CRYPTO_MIN_QUEUE_LENGTH; + } else { + if (((uint64_t)((1000.0 / conn->packet_send_rate) + 0.5) + conn->last_packets_left_set) <= temp_time) { + double n_packets = conn->packet_send_rate * (((double)(temp_time - conn->last_packets_left_set)) / 1000.0); + n_packets += conn->last_packets_left_rem; + + uint32_t num_packets = n_packets; + double rem = n_packets - (double)num_packets; + + if (conn->packets_left > num_packets * 4 + CRYPTO_MIN_QUEUE_LENGTH) { + conn->packets_left = num_packets * 4 + CRYPTO_MIN_QUEUE_LENGTH; + } else { + conn->packets_left += num_packets; + } + + conn->last_packets_left_set = temp_time; + conn->last_packets_left_rem = rem; + } + + if (((uint64_t)((1000.0 / conn->packet_send_rate_requested) + 0.5) + conn->last_packets_left_requested_set) <= + temp_time) { + double n_packets = conn->packet_send_rate_requested * (((double)(temp_time - conn->last_packets_left_requested_set)) / + 1000.0); + n_packets += conn->last_packets_left_requested_rem; + + uint32_t num_packets = n_packets; + double rem = n_packets - (double)num_packets; + conn->packets_left_requested = num_packets; + + conn->last_packets_left_requested_set = temp_time; + conn->last_packets_left_requested_rem = rem; + } + + if (conn->packets_left > conn->packets_left_requested) { + conn->packets_left_requested = conn->packets_left; + } + } + + int ret = send_requested_packets(c, i, conn->packets_left_requested); + + if (ret != -1) { + conn->packets_left_requested -= ret; + conn->packets_resent += ret; + + if ((unsigned int)ret < conn->packets_left) { + conn->packets_left -= ret; + } else { + conn->last_congestion_event = temp_time; + conn->packets_left = 0; + } + } + + if (conn->packet_send_rate > CRYPTO_PACKET_MIN_RATE * 1.5) { + total_send_rate += conn->packet_send_rate; + } + } + } + + c->current_sleep_time = ~0; + uint32_t sleep_time = peak_request_packet_interval; + + if (c->current_sleep_time > sleep_time) { + c->current_sleep_time = sleep_time; + } + + if (total_send_rate > CRYPTO_PACKET_MIN_RATE) { + sleep_time = (1000.0 / total_send_rate); + + if (c->current_sleep_time > sleep_time) { + c->current_sleep_time = sleep_time + 1; + } + } + + sleep_time = CRYPTO_SEND_PACKET_INTERVAL; + + if (c->current_sleep_time > sleep_time) { + c->current_sleep_time = sleep_time; + } +} + +/* Return 1 if max speed was reached for this connection (no more data can be physically through the pipe). + * Return 0 if it wasn't reached. + */ +bool max_speed_reached(Net_Crypto *c, int crypt_connection_id) +{ + return reset_max_speed_reached(c, crypt_connection_id) != 0; +} + +/* returns the number of packet slots left in the sendbuffer. + * return 0 if failure. + */ +uint32_t crypto_num_free_sendqueue_slots(const Net_Crypto *c, int crypt_connection_id) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return 0; + } + + uint32_t max_packets = CRYPTO_PACKET_BUFFER_SIZE - num_packets_array(&conn->send_array); + + if (conn->packets_left < max_packets) { + return conn->packets_left; + } + + return max_packets; +} + +/* Sends a lossless cryptopacket. + * + * return -1 if data could not be put in packet queue. + * return positive packet number if data was put into the queue. + * + * congestion_control: should congestion control apply to this packet? + */ +int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length, + uint8_t congestion_control) +{ + if (length == 0) { + return -1; + } + + if (data[0] < CRYPTO_RESERVED_PACKETS) { + return -1; + } + + if (data[0] >= PACKET_ID_LOSSY_RANGE_START) { + return -1; + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + if (conn->status != CRYPTO_CONN_ESTABLISHED) { + return -1; + } + + if (congestion_control && conn->packets_left == 0) { + return -1; + } + + int64_t ret = send_lossless_packet(c, crypt_connection_id, data, length, congestion_control); + + if (ret == -1) { + return -1; + } + + if (congestion_control) { + --conn->packets_left; + --conn->packets_left_requested; + conn->packets_sent++; + } + + return ret; +} + +/* Check if packet_number was received by the other side. + * + * packet_number must be a valid packet number of a packet sent on this connection. + * + * return -1 on failure. + * return 0 on success. + */ +int cryptpacket_received(Net_Crypto *c, int crypt_connection_id, uint32_t packet_number) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return -1; + } + + uint32_t num = conn->send_array.buffer_end - conn->send_array.buffer_start; + uint32_t num1 = packet_number - conn->send_array.buffer_start; + + if (num < num1) { + return 0; + } + + return -1; +} + +/* return -1 on failure. + * return 0 on success. + * + * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*) + */ +int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length) +{ + if (length == 0 || length > MAX_CRYPTO_DATA_SIZE) { + return -1; + } + + if (data[0] < PACKET_ID_LOSSY_RANGE_START) { + return -1; + } + + if (data[0] >= (PACKET_ID_LOSSY_RANGE_START + PACKET_ID_LOSSY_RANGE_SIZE)) { + return -1; + } + + pthread_mutex_lock(&c->connections_mutex); + ++c->connection_use_counter; + pthread_mutex_unlock(&c->connections_mutex); + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + int ret = -1; + + if (conn) { + pthread_mutex_lock(&conn->mutex); + uint32_t buffer_start = conn->recv_array.buffer_start; + uint32_t buffer_end = conn->send_array.buffer_end; + pthread_mutex_unlock(&conn->mutex); + ret = send_data_packet_helper(c, crypt_connection_id, buffer_start, buffer_end, data, length); + } + + pthread_mutex_lock(&c->connections_mutex); + --c->connection_use_counter; + pthread_mutex_unlock(&c->connections_mutex); + + return ret; +} + +/* Kill a crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +int crypto_kill(Net_Crypto *c, int crypt_connection_id) +{ + while (1) { /* TODO(irungentoo): is this really the best way to do this? */ + pthread_mutex_lock(&c->connections_mutex); + + if (!c->connection_use_counter) { + break; + } + + pthread_mutex_unlock(&c->connections_mutex); + } + + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + int ret = -1; + + if (conn) { + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + send_kill_packet(c, crypt_connection_id); + } + + pthread_mutex_lock(&c->tcp_mutex); + kill_tcp_connection_to(c->tcp_c, conn->connection_number_tcp); + pthread_mutex_unlock(&c->tcp_mutex); + + bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv4, crypt_connection_id); + bs_list_remove(&c->ip_port_list, (uint8_t *)&conn->ip_portv6, crypt_connection_id); + clear_temp_packet(c, crypt_connection_id); + clear_buffer(&conn->send_array); + clear_buffer(&conn->recv_array); + ret = wipe_crypto_connection(c, crypt_connection_id); + } + + pthread_mutex_unlock(&c->connections_mutex); + + return ret; +} + +/* return one of CRYPTO_CONN_* values indicating the state of the connection. + * + * sets direct_connected to 1 if connection connects directly to other, 0 if it isn't. + * sets online_tcp_relays to the number of connected tcp relays this connection has. + */ +unsigned int crypto_connection_status(const Net_Crypto *c, int crypt_connection_id, bool *direct_connected, + unsigned int *online_tcp_relays) +{ + Crypto_Connection *conn = get_crypto_connection(c, crypt_connection_id); + + if (conn == 0) { + return CRYPTO_CONN_NO_CONNECTION; + } + + if (direct_connected) { + *direct_connected = 0; + + uint64_t current_time = unix_time(); + + if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev4) > current_time) { + *direct_connected = 1; + } + + if ((UDP_DIRECT_TIMEOUT + conn->direct_lastrecv_timev6) > current_time) { + *direct_connected = 1; + } + } + + if (online_tcp_relays) { + *online_tcp_relays = tcp_connection_to_online_tcp_relays(c->tcp_c, conn->connection_number_tcp); + } + + return conn->status; +} + +void new_keys(Net_Crypto *c) +{ + crypto_new_keypair(c->self_public_key, c->self_secret_key); +} + +/* Save the public and private keys to the keys array. + * Length must be CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE. + * + * TODO(irungentoo): Save only secret key. + */ +void save_keys(const Net_Crypto *c, uint8_t *keys) +{ + memcpy(keys, c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(keys + CRYPTO_PUBLIC_KEY_SIZE, c->self_secret_key, CRYPTO_SECRET_KEY_SIZE); +} + +/* Load the secret key. + * Length must be CRYPTO_SECRET_KEY_SIZE. + */ +void load_secret_key(Net_Crypto *c, const uint8_t *sk) +{ + memcpy(c->self_secret_key, sk, CRYPTO_SECRET_KEY_SIZE); + crypto_derive_public_key(c->self_public_key, c->self_secret_key); +} + +/* Run this to (re)initialize net_crypto. + * Sets all the global connection variables to their default values. + */ +Net_Crypto *new_net_crypto(Logger *log, DHT *dht, TCP_Proxy_Info *proxy_info) +{ + unix_time_update(); + + if (dht == NULL) { + return NULL; + } + + Net_Crypto *temp = (Net_Crypto *)calloc(1, sizeof(Net_Crypto)); + + if (temp == NULL) { + return NULL; + } + + temp->log = log; + + temp->tcp_c = new_tcp_connections(dht->self_secret_key, proxy_info); + + if (temp->tcp_c == NULL) { + free(temp); + return NULL; + } + + set_packet_tcp_connection_callback(temp->tcp_c, &tcp_data_callback, temp); + set_oob_packet_tcp_connection_callback(temp->tcp_c, &tcp_oob_callback, temp); + + /*if (create_recursive_mutex(&temp->tcp_mutex) != 0 || + pthread_mutex_init(&temp->connections_mutex, NULL) != 0) { + kill_tcp_connections(temp->tcp_c); + free(temp); + return NULL; + }*/ + + temp->dht = dht; + + new_keys(temp); + new_symmetric_key(temp->secret_symmetric_key); + + temp->current_sleep_time = CRYPTO_SEND_PACKET_INTERVAL; + + networking_registerhandler(dht->net, NET_PACKET_COOKIE_REQUEST, &udp_handle_cookie_request, temp); + networking_registerhandler(dht->net, NET_PACKET_COOKIE_RESPONSE, &udp_handle_packet, temp); + networking_registerhandler(dht->net, NET_PACKET_CRYPTO_HS, &udp_handle_packet, temp); + networking_registerhandler(dht->net, NET_PACKET_CRYPTO_DATA, &udp_handle_packet, temp); + + bs_list_init(&temp->ip_port_list, sizeof(IP_Port), 8); + + return temp; +} + +static void kill_timedout(Net_Crypto *c, void *userdata) +{ + uint32_t i; + //uint64_t temp_time = current_time_monotonic(); + + for (i = 0; i < c->crypto_connections_length; ++i) { + Crypto_Connection *conn = get_crypto_connection(c, i); + + if (conn == 0) { + return; + } + + if (conn->status == CRYPTO_CONN_NO_CONNECTION) { + continue; + } + + if (conn->status == CRYPTO_CONN_COOKIE_REQUESTING || conn->status == CRYPTO_CONN_HANDSHAKE_SENT + || conn->status == CRYPTO_CONN_NOT_CONFIRMED) { + if (conn->temp_packet_num_sent < MAX_NUM_SENDPACKET_TRIES) { + continue; + } + + connection_kill(c, i, userdata); + } + +#if 0 + + if (conn->status == CRYPTO_CONN_ESTABLISHED) { + // TODO(irungentoo): add a timeout here? + } + +#endif + } +} + +/* return the optimal interval in ms for running do_net_crypto. + */ +uint32_t crypto_run_interval(const Net_Crypto *c) +{ + return c->current_sleep_time; +} + +/* Main loop. */ +void do_net_crypto(Net_Crypto *c, void *userdata) +{ + unix_time_update(); + kill_timedout(c, userdata); + do_tcp(c, userdata); + send_crypto_packets(c); +} + +void kill_net_crypto(Net_Crypto *c) +{ + uint32_t i; + + for (i = 0; i < c->crypto_connections_length; ++i) { + crypto_kill(c, i); + } + + pthread_mutex_destroy(&c->tcp_mutex); + pthread_mutex_destroy(&c->connections_mutex); + + kill_tcp_connections(c->tcp_c); + bs_list_free(&c->ip_port_list); + networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_REQUEST, NULL, NULL); + networking_registerhandler(c->dht->net, NET_PACKET_COOKIE_RESPONSE, NULL, NULL); + networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_HS, NULL, NULL); + networking_registerhandler(c->dht->net, NET_PACKET_CRYPTO_DATA, NULL, NULL); + crypto_memzero(c, sizeof(Net_Crypto)); + free(c); +} diff --git a/libs/libtox/src/toxcore/net_crypto.h b/libs/libtox/src/toxcore/net_crypto.h new file mode 100644 index 0000000000..5ec5ca94fb --- /dev/null +++ b/libs/libtox/src/toxcore/net_crypto.h @@ -0,0 +1,428 @@ +/* + * Functions for the core network crypto. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef NET_CRYPTO_H +#define NET_CRYPTO_H + +#include "DHT.h" +#include "LAN_discovery.h" +#include "TCP_connection.h" +#include "logger.h" + +#include + +#define CRYPTO_CONN_NO_CONNECTION 0 +#define CRYPTO_CONN_COOKIE_REQUESTING 1 //send cookie request packets +#define CRYPTO_CONN_HANDSHAKE_SENT 2 //send handshake packets +#define CRYPTO_CONN_NOT_CONFIRMED 3 //send handshake packets, we have received one from the other +#define CRYPTO_CONN_ESTABLISHED 4 + +/* Maximum size of receiving and sending packet buffers. */ +#define CRYPTO_PACKET_BUFFER_SIZE 32768 /* Must be a power of 2 */ + +/* Minimum packet rate per second. */ +#define CRYPTO_PACKET_MIN_RATE 4.0 + +/* Minimum packet queue max length. */ +#define CRYPTO_MIN_QUEUE_LENGTH 64 + +/* Maximum total size of packets that net_crypto sends. */ +#define MAX_CRYPTO_PACKET_SIZE 1400 + +#define CRYPTO_DATA_PACKET_MIN_SIZE (1 + sizeof(uint16_t) + (sizeof(uint32_t) + sizeof(uint32_t)) + CRYPTO_MAC_SIZE) + +/* Max size of data in packets */ +#define MAX_CRYPTO_DATA_SIZE (MAX_CRYPTO_PACKET_SIZE - CRYPTO_DATA_PACKET_MIN_SIZE) + +/* Interval in ms between sending cookie request/handshake packets. */ +#define CRYPTO_SEND_PACKET_INTERVAL 1000 + +/* The maximum number of times we try to send the cookie request and handshake + before giving up. */ +#define MAX_NUM_SENDPACKET_TRIES 8 + +/* The timeout of no received UDP packets before the direct UDP connection is considered dead. */ +#define UDP_DIRECT_TIMEOUT ((MAX_NUM_SENDPACKET_TRIES * CRYPTO_SEND_PACKET_INTERVAL) / 1000) + +#define PACKET_ID_PADDING 0 /* Denotes padding */ +#define PACKET_ID_REQUEST 1 /* Used to request unreceived packets */ +#define PACKET_ID_KILL 2 /* Used to kill connection */ + +/* Packet ids 0 to CRYPTO_RESERVED_PACKETS - 1 are reserved for use by net_crypto. */ +#define CRYPTO_RESERVED_PACKETS 16 + +#define MAX_TCP_CONNECTIONS 64 +#define MAX_TCP_RELAYS_PEER 4 + +/* All packets starting with a byte in this range are considered lossy packets. */ +#define PACKET_ID_LOSSY_RANGE_START 192 +#define PACKET_ID_LOSSY_RANGE_SIZE 63 + +#define CRYPTO_MAX_PADDING 8 /* All packets will be padded a number of bytes based on this number. */ + +/* Base current transfer speed on last CONGESTION_QUEUE_ARRAY_SIZE number of points taken + at the dT defined in net_crypto.c */ +#define CONGESTION_QUEUE_ARRAY_SIZE 12 +#define CONGESTION_LAST_SENT_ARRAY_SIZE (CONGESTION_QUEUE_ARRAY_SIZE * 2) + +/* Default connection ping in ms. */ +#define DEFAULT_PING_CONNECTION 1000 +#define DEFAULT_TCP_PING_CONNECTION 500 + +typedef struct { + uint64_t sent_time; + uint16_t length; + uint8_t data[MAX_CRYPTO_DATA_SIZE]; +} Packet_Data; + +typedef struct { + Packet_Data *buffer[CRYPTO_PACKET_BUFFER_SIZE]; + uint32_t buffer_start; + uint32_t buffer_end; /* packet numbers in array: {buffer_start, buffer_end) */ +} Packets_Array; + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The real public key of the peer. */ + uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ + uint8_t sent_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of sent packets. */ + uint8_t sessionpublic_key[CRYPTO_PUBLIC_KEY_SIZE]; /* Our public key for this session. */ + uint8_t sessionsecret_key[CRYPTO_SECRET_KEY_SIZE]; /* Our private key for this session. */ + uint8_t peersessionpublic_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The public key of the peer. */ + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; /* The precomputed shared key from encrypt_precompute. */ + uint8_t status; /* 0 if no connection, 1 we are sending cookie request packets, + * 2 if we are sending handshake packets + * 3 if connection is not confirmed yet (we have received a handshake but no data packets yet), + * 4 if the connection is established. + */ + uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */ + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer */ + + uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */ + uint16_t temp_packet_length; + uint64_t temp_packet_sent_time; /* The time at which the last temp_packet was sent in ms. */ + uint32_t temp_packet_num_sent; + + IP_Port ip_portv4; /* The ip and port to contact this guy directly.*/ + IP_Port ip_portv6; + uint64_t direct_lastrecv_timev4; /* The Time at which we last received a direct packet in ms. */ + uint64_t direct_lastrecv_timev6; + + uint64_t last_tcp_sent; /* Time the last TCP packet was sent. */ + + Packets_Array send_array; + Packets_Array recv_array; + + int (*connection_status_callback)(void *object, int id, uint8_t status, void *userdata); + void *connection_status_callback_object; + int connection_status_callback_id; + + int (*connection_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + void *connection_data_callback_object; + int connection_data_callback_id; + + int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata); + void *connection_lossy_data_callback_object; + int connection_lossy_data_callback_id; + + uint64_t last_request_packet_sent; + uint64_t direct_send_attempt_time; + + uint32_t packet_counter; + double packet_recv_rate; + uint64_t packet_counter_set; + + double packet_send_rate; + uint32_t packets_left; + uint64_t last_packets_left_set; + double last_packets_left_rem; + + double packet_send_rate_requested; + uint32_t packets_left_requested; + uint64_t last_packets_left_requested_set; + double last_packets_left_requested_rem; + + uint32_t last_sendqueue_size[CONGESTION_QUEUE_ARRAY_SIZE], last_sendqueue_counter; + long signed int last_num_packets_sent[CONGESTION_LAST_SENT_ARRAY_SIZE], + last_num_packets_resent[CONGESTION_LAST_SENT_ARRAY_SIZE]; + uint32_t packets_sent, packets_resent; + uint64_t last_congestion_event; + uint64_t rtt_time; + + /* TCP_connection connection_number */ + unsigned int connection_number_tcp; + + uint8_t maximum_speed_reached; + + pthread_mutex_t mutex; + + void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key, void *userdata); + void *dht_pk_callback_object; + uint32_t dht_pk_callback_number; +} Crypto_Connection; + +typedef struct { + IP_Port source; + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The real public key of the peer. */ + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer. */ + uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ + uint8_t peersessionpublic_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The public key of the peer. */ + uint8_t *cookie; + uint8_t cookie_length; +} New_Connection; + +typedef struct { + Logger *log; + + DHT *dht; + TCP_Connections *tcp_c; + + Crypto_Connection *crypto_connections; + pthread_mutex_t tcp_mutex; + + pthread_mutex_t connections_mutex; + unsigned int connection_use_counter; + + uint32_t crypto_connections_length; /* Length of connections array. */ + + /* Our public and secret keys. */ + uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + /* The secret key used for cookies */ + uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + + int (*new_connection_callback)(void *object, New_Connection *n_c); + void *new_connection_callback_object; + + /* The current optimal sleep time */ + uint32_t current_sleep_time; + + BS_LIST ip_port_list; +} Net_Crypto; + + +/* Set function to be called when someone requests a new connection to us. + * + * The set function should return -1 on failure and 0 on success. + * + * n_c is only valid for the duration of the function call. + */ +void new_connection_handler(Net_Crypto *c, int (*new_connection_callback)(void *object, New_Connection *n_c), + void *object); + +/* Accept a crypto connection. + * + * return -1 on failure. + * return connection id on success. + */ +int accept_crypto_connection(Net_Crypto *c, New_Connection *n_c); + +/* Create a crypto connection. + * If one to that real public key already exists, return it. + * + * return -1 on failure. + * return connection id on success. + */ +int new_crypto_connection(Net_Crypto *c, const uint8_t *real_public_key, const uint8_t *dht_public_key); + +/* Set the direct ip of the crypto connection. + * + * Connected is 0 if we are not sure we are connected to that person, 1 if we are sure. + * + * return -1 on failure. + * return 0 on success. + */ +int set_direct_ip_port(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, bool connected); + +/* Set function to be called when connection with crypt_connection_id goes connects/disconnects. + * + * The set function should return -1 on failure and 0 on success. + * Note that if this function is set, the connection will clear itself on disconnect. + * Object and id will be passed to this function untouched. + * status is 1 if the connection is going online, 0 if it is going offline. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_status_handler(const Net_Crypto *c, int crypt_connection_id, + int (*connection_status_callback)(void *object, int id, uint8_t status, void *userdata), void *object, int id); + +/* Set function to be called when connection with crypt_connection_id receives a lossless data packet of length. + * + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_data_handler(const Net_Crypto *c, int crypt_connection_id, int (*connection_data_callback)(void *object, + int id, const uint8_t *data, uint16_t length, void *userdata), void *object, int id); + + +/* Set function to be called when connection with crypt_connection_id receives a lossy data packet of length. + * + * The set function should return -1 on failure and 0 on success. + * Object and id will be passed to this function untouched. + * + * return -1 on failure. + * return 0 on success. + */ +int connection_lossy_data_handler(Net_Crypto *c, int crypt_connection_id, + int (*connection_lossy_data_callback)(void *object, int id, const uint8_t *data, uint16_t length, void *userdata), + void *object, + int id); + +/* Set the function for this friend that will be callbacked with object and number if + * the friend sends us a different dht public key than we have associated to him. + * + * If this function is called, the connection should be recreated with the new public key. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int nc_dht_pk_callback(Net_Crypto *c, int crypt_connection_id, void (*function)(void *data, int32_t number, + const uint8_t *dht_public_key, void *userdata), void *object, uint32_t number); + +/* returns the number of packet slots left in the sendbuffer. + * return 0 if failure. + */ +uint32_t crypto_num_free_sendqueue_slots(const Net_Crypto *c, int crypt_connection_id); + +/* Return 1 if max speed was reached for this connection (no more data can be physically through the pipe). + * Return 0 if it wasn't reached. + */ +bool max_speed_reached(Net_Crypto *c, int crypt_connection_id); + +/* Sends a lossless cryptopacket. + * + * return -1 if data could not be put in packet queue. + * return positive packet number if data was put into the queue. + * + * The first byte of data must be in the CRYPTO_RESERVED_PACKETS to PACKET_ID_LOSSY_RANGE_START range. + * + * congestion_control: should congestion control apply to this packet? + */ +int64_t write_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length, + uint8_t congestion_control); + +/* Check if packet_number was received by the other side. + * + * packet_number must be a valid packet number of a packet sent on this connection. + * + * return -1 on failure. + * return 0 on success. + */ +int cryptpacket_received(Net_Crypto *c, int crypt_connection_id, uint32_t packet_number); + +/* return -1 on failure. + * return 0 on success. + * + * Sends a lossy cryptopacket. (first byte must in the PACKET_ID_LOSSY_RANGE_*) + */ +int send_lossy_cryptpacket(Net_Crypto *c, int crypt_connection_id, const uint8_t *data, uint16_t length); + +/* Add a tcp relay, associating it to a crypt_connection_id. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay_peer(Net_Crypto *c, int crypt_connection_id, IP_Port ip_port, const uint8_t *public_key); + +/* Add a tcp relay to the array. + * + * return 0 if it was added. + * return -1 if it wasn't. + */ +int add_tcp_relay(Net_Crypto *c, IP_Port ip_port, const uint8_t *public_key); + +/* Return a random TCP connection number for use in send_tcp_onion_request. + * + * return TCP connection number on success. + * return -1 on failure. + */ +int get_random_tcp_con_number(Net_Crypto *c); + +/* Send an onion packet via the TCP relay corresponding to TCP_conn_number. + * + * return 0 on success. + * return -1 on failure. + */ +int send_tcp_onion_request(Net_Crypto *c, unsigned int tcp_connections_number, const uint8_t *data, uint16_t length); + +/* Copy a maximum of num TCP relays we are connected to to tcp_relays. + * NOTE that the family of the copied ip ports will be set to TCP_INET or TCP_INET6. + * + * return number of relays copied to tcp_relays on success. + * return 0 on failure. + */ +unsigned int copy_connected_tcp_relays(Net_Crypto *c, Node_format *tcp_relays, uint16_t num); + +/* Kill a crypto connection. + * + * return -1 on failure. + * return 0 on success. + */ +int crypto_kill(Net_Crypto *c, int crypt_connection_id); + +/* return one of CRYPTO_CONN_* values indicating the state of the connection. + * + * sets direct_connected to 1 if connection connects directly to other, 0 if it isn't. + * sets online_tcp_relays to the number of connected tcp relays this connection has. + */ +unsigned int crypto_connection_status(const Net_Crypto *c, int crypt_connection_id, bool *direct_connected, + unsigned int *online_tcp_relays); + +/* Generate our public and private keys. + * Only call this function the first time the program starts. + */ +void new_keys(Net_Crypto *c); + +/* Save the public and private keys to the keys array. + * Length must be CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SECRET_KEY_SIZE. + */ +void save_keys(const Net_Crypto *c, uint8_t *keys); + +/* Load the secret key. + * Length must be CRYPTO_SECRET_KEY_SIZE. + */ +void load_secret_key(Net_Crypto *c, const uint8_t *sk); + +/* Create new instance of Net_Crypto. + * Sets all the global connection variables to their default values. + */ +Net_Crypto *new_net_crypto(Logger *log, DHT *dht, TCP_Proxy_Info *proxy_info); + +/* return the optimal interval in ms for running do_net_crypto. + */ +uint32_t crypto_run_interval(const Net_Crypto *c); + +/* Main loop. */ +void do_net_crypto(Net_Crypto *c, void *userdata); + +void kill_net_crypto(Net_Crypto *c); + + + +#endif diff --git a/libs/libtox/src/toxcore/network.c b/libs/libtox/src/toxcore/network.c new file mode 100644 index 0000000000..5c43bf5779 --- /dev/null +++ b/libs/libtox/src/toxcore/network.c @@ -0,0 +1,1446 @@ +/* + * Functions for the core networking. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _DARWIN_C_SOURCE +#define _XOPEN_SOURCE 600 + +#if defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_WINXP +#define _WIN32_WINNT 0x501 +#endif + +#include "network.h" + +#include "logger.h" +#include "util.h" + +#include +#ifdef __APPLE__ +#include +#include +#endif + +#ifndef IPV6_ADD_MEMBERSHIP +#ifdef IPV6_JOIN_GROUP +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif +#endif + +#if !(defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) + +#include +#include +#include +#include +#include + +#else + +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif + +#ifndef EWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK +#endif + +static const char *inet_ntop(Family family, const void *addr, char *buf, size_t bufsize) +{ + if (family == TOX_AF_INET) { + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + + saddr.sin_family = AF_INET; + saddr.sin_addr = *(const struct in_addr *)addr; + + DWORD len = bufsize; + + if (WSAAddressToString((LPSOCKADDR)&saddr, sizeof(saddr), NULL, buf, &len)) { + return NULL; + } + + return buf; + } else if (family == TOX_AF_INET6) { + struct sockaddr_in6 saddr; + memset(&saddr, 0, sizeof(saddr)); + + saddr.sin6_family = AF_INET6; + saddr.sin6_addr = *(const struct in6_addr *)addr; + + DWORD len = bufsize; + + if (WSAAddressToString((LPSOCKADDR)&saddr, sizeof(saddr), NULL, buf, &len)) { + return NULL; + } + + return buf; + } + + return NULL; +} + +static int inet_pton(Family family, const char *addrString, void *addrbuf) +{ + if (family == TOX_AF_INET) { + struct sockaddr_in saddr; + memset(&saddr, 0, sizeof(saddr)); + + INT len = sizeof(saddr); + + if (WSAStringToAddress((LPTSTR)addrString, AF_INET, NULL, (LPSOCKADDR)&saddr, &len)) { + return 0; + } + + *(struct in_addr *)addrbuf = saddr.sin_addr; + + return 1; + } else if (family == TOX_AF_INET6) { + struct sockaddr_in6 saddr; + memset(&saddr, 0, sizeof(saddr)); + + INT len = sizeof(saddr); + + if (WSAStringToAddress((LPTSTR)addrString, AF_INET6, NULL, (LPSOCKADDR)&saddr, &len)) { + return 0; + } + + *(struct in6_addr *)addrbuf = saddr.sin6_addr; + + return 1; + } + + return 0; +} + +#endif + +#if TOX_INET6_ADDRSTRLEN < INET6_ADDRSTRLEN +#error TOX_INET6_ADDRSTRLEN should be greater or equal to INET6_ADDRSTRLEN (#INET6_ADDRSTRLEN) +#endif + +#if TOX_INET_ADDRSTRLEN < INET_ADDRSTRLEN +#error TOX_INET_ADDRSTRLEN should be greater or equal to INET_ADDRSTRLEN (#INET_ADDRSTRLEN) +#endif + +static int make_proto(int proto); +static int make_socktype(int type); +static int make_family(int tox_family); +static int make_tox_family(int family); + +static void get_ip4(IP4 *result, const struct in_addr *addr) +{ + result->uint32 = addr->s_addr; +} + +static void get_ip6(IP6 *result, const struct in6_addr *addr) +{ + assert(sizeof(result->uint8) == sizeof(addr->s6_addr)); + memcpy(result->uint8, addr->s6_addr, sizeof(result->uint8)); +} + +static void fill_addr4(IP4 ip, struct in_addr *addr) +{ + addr->s_addr = ip.uint32; +} + +static void fill_addr6(IP6 ip, struct in6_addr *addr) +{ + assert(sizeof(ip.uint8) == sizeof(addr->s6_addr)); + memcpy(addr->s6_addr, ip.uint8, sizeof(ip.uint8)); +} + +#if !defined(INADDR_LOOPBACK) +#define INADDR_LOOPBACK 0x7f000001 +#endif + +const IP4 IP4_BROADCAST = { INADDR_BROADCAST }; +const IP6 IP6_BROADCAST = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } +}; + +IP4 get_ip4_loopback() +{ + IP4 loopback; + loopback.uint32 = htonl(INADDR_LOOPBACK); + return loopback; +} + +IP6 get_ip6_loopback() +{ + IP6 loopback; + get_ip6(&loopback, &in6addr_loopback); + return loopback; +} + +/* Check if socket is valid. + * + * return 1 if valid + * return 0 if not valid + */ +int sock_valid(Socket sock) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + + if (sock == INVALID_SOCKET) { +#else + + if (sock < 0) { +#endif + return 0; + } + + return 1; +} + +/* Close the socket. + */ +void kill_sock(Socket sock) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + closesocket(sock); +#else + close(sock); +#endif +} + +/* Set socket as nonblocking + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nonblock(Socket sock) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + u_long mode = 1; + return (ioctlsocket(sock, FIONBIO, &mode) == 0); +#else + return (fcntl(sock, F_SETFL, O_NONBLOCK, 1) == 0); +#endif +} + +/* Set socket to not emit SIGPIPE + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nosigpipe(Socket sock) +{ +#if defined(__MACH__) + int set = 1; + return (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (const char *)&set, sizeof(int)) == 0); +#else + return 1; +#endif +} + +/* Enable SO_REUSEADDR on socket. + * + * return 1 on success + * return 0 on failure + */ +int set_socket_reuseaddr(Socket sock) +{ + int set = 1; + return (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&set, sizeof(set)) == 0); +} + +/* Set socket to dual (IPv4 + IPv6 socket) + * + * return 1 on success + * return 0 on failure + */ +int set_socket_dualstack(Socket sock) +{ + int ipv6only = 0; + socklen_t optsize = sizeof(ipv6only); + int res = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&ipv6only, &optsize); + + if ((res == 0) && (ipv6only == 0)) { + return 1; + } + + ipv6only = 0; + return (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&ipv6only, sizeof(ipv6only)) == 0); +} + + +/* return current UNIX time in microseconds (us). */ +static uint64_t current_time_actual(void) +{ + uint64_t time; +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + /* This probably works fine */ + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + time = ft.dwHighDateTime; + time <<= 32; + time |= ft.dwLowDateTime; + time -= 116444736000000000ULL; + return time / 10; +#else + struct timeval a; + gettimeofday(&a, NULL); + time = 1000000ULL * a.tv_sec + a.tv_usec; + return time; +#endif +} + + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) +static uint64_t last_monotime; +static uint64_t add_monotime; +#endif + +/* return current monotonic time in milliseconds (ms). */ +uint64_t current_time_monotonic(void) +{ + uint64_t time; +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + uint64_t old_add_monotime = add_monotime; + time = (uint64_t)GetTickCount() + add_monotime; + + /* Check if time has decreased because of 32 bit wrap from GetTickCount(), while avoiding false positives from race + * conditions when multiple threads call this function at once */ + if (time + 0x10000 < last_monotime) { + uint32_t add = ~0; + /* use old_add_monotime rather than simply incrementing add_monotime, to handle the case that many threads + * simultaneously detect an overflow */ + add_monotime = old_add_monotime + add; + time += add; + } + + last_monotime = time; +#else + struct timespec monotime; +#if defined(__linux__) && defined(CLOCK_MONOTONIC_RAW) + clock_gettime(CLOCK_MONOTONIC_RAW, &monotime); +#elif defined(__APPLE__) + clock_serv_t muhclock; + mach_timespec_t machtime; + + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &muhclock); + clock_get_time(muhclock, &machtime); + mach_port_deallocate(mach_task_self(), muhclock); + + monotime.tv_sec = machtime.tv_sec; + monotime.tv_nsec = machtime.tv_nsec; +#else + clock_gettime(CLOCK_MONOTONIC, &monotime); +#endif + time = 1000ULL * monotime.tv_sec + (monotime.tv_nsec / 1000000ULL); +#endif + return time; +} + +static uint32_t data_0(uint16_t buflen, const uint8_t *buffer) +{ + return buflen > 4 ? net_ntohl(*(const uint32_t *)&buffer[1]) : 0; +} +static uint32_t data_1(uint16_t buflen, const uint8_t *buffer) +{ + return buflen > 7 ? net_ntohl(*(const uint32_t *)&buffer[5]) : 0; +} + +static void loglogdata(Logger *log, const char *message, const uint8_t *buffer, + uint16_t buflen, IP_Port ip_port, int res) +{ + char ip_str[IP_NTOA_LEN]; + + if (res < 0) { /* Windows doesn't necessarily know %zu */ + LOGGER_TRACE(log, "[%2u] %s %3hu%c %s:%hu (%u: %s) | %04x%04x", + buffer[0], message, (buflen < 999 ? (uint16_t)buflen : 999), 'E', + ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), errno, + strerror(errno), data_0(buflen, buffer), data_1(buflen, buffer)); + } else if ((res > 0) && ((size_t)res <= buflen)) { + LOGGER_TRACE(log, "[%2u] %s %3zu%c %s:%hu (%u: %s) | %04x%04x", + buffer[0], message, (res < 999 ? (size_t)res : 999), ((size_t)res < buflen ? '<' : '='), + ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), 0, "OK", + data_0(buflen, buffer), data_1(buflen, buffer)); + } else { /* empty or overwrite */ + LOGGER_TRACE(log, "[%2u] %s %zu%c%zu %s:%hu (%u: %s) | %04x%04x", + buffer[0], message, (size_t)res, (!res ? '!' : '>'), buflen, + ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), 0, "OK", + data_0(buflen, buffer), data_1(buflen, buffer)); + } +} + +/* Basic network functions: + * Function to send packet(data) of length length to ip_port. + */ +int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint16_t length) +{ + if (net->family == 0) { /* Socket not initialized */ + return -1; + } + + /* socket TOX_AF_INET, but target IP NOT: can't send */ + if ((net->family == TOX_AF_INET) && (ip_port.ip.family != TOX_AF_INET)) { + return -1; + } + + struct sockaddr_storage addr; + + size_t addrsize = 0; + + if (ip_port.ip.family == TOX_AF_INET) { + if (net->family == TOX_AF_INET6) { + /* must convert to IPV4-in-IPV6 address */ + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = ip_port.port; + + /* there should be a macro for this in a standards compliant + * environment, not found */ + IP6 ip6; + + ip6.uint32[0] = 0; + ip6.uint32[1] = 0; + ip6.uint32[2] = net_htonl(0xFFFF); + ip6.uint32[3] = ip_port.ip.ip4.uint32; + fill_addr6(ip6, &addr6->sin6_addr); + + addr6->sin6_flowinfo = 0; + addr6->sin6_scope_id = 0; + } else { + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + + addrsize = sizeof(struct sockaddr_in); + addr4->sin_family = AF_INET; + fill_addr4(ip_port.ip.ip4, &addr4->sin_addr); + addr4->sin_port = ip_port.port; + } + } else if (ip_port.ip.family == TOX_AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = ip_port.port; + fill_addr6(ip_port.ip.ip6, &addr6->sin6_addr); + + addr6->sin6_flowinfo = 0; + addr6->sin6_scope_id = 0; + } else { + /* unknown address type*/ + return -1; + } + + int res = sendto(net->sock, (const char *) data, length, 0, (struct sockaddr *)&addr, addrsize); + + loglogdata(net->log, "O=>", data, length, ip_port, res); + + return res; +} + +/* Function to receive data + * ip and port of sender is put into ip_port. + * Packet data is put into data. + * Packet length is put into length. + */ +static int receivepacket(Logger *log, Socket sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) +{ + memset(ip_port, 0, sizeof(IP_Port)); + struct sockaddr_storage addr; +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + int addrlen = sizeof(addr); +#else + socklen_t addrlen = sizeof(addr); +#endif + *length = 0; + int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); + + if (fail_or_len < 0) { + + if (fail_or_len < 0 && errno != EWOULDBLOCK) { + LOGGER_ERROR(log, "Unexpected error reading from socket: %u, %s\n", errno, strerror(errno)); + } + + return -1; /* Nothing received. */ + } + + *length = (uint32_t)fail_or_len; + + if (addr.ss_family == AF_INET) { + struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; + + ip_port->ip.family = make_tox_family(addr_in->sin_family); + get_ip4(&ip_port->ip.ip4, &addr_in->sin_addr); + ip_port->port = addr_in->sin_port; + } else if (addr.ss_family == AF_INET6) { + struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&addr; + ip_port->ip.family = make_tox_family(addr_in6->sin6_family); + get_ip6(&ip_port->ip.ip6, &addr_in6->sin6_addr); + ip_port->port = addr_in6->sin6_port; + + if (IPV6_IPV4_IN_V6(ip_port->ip.ip6)) { + ip_port->ip.family = TOX_AF_INET; + ip_port->ip.ip4.uint32 = ip_port->ip.ip6.uint32[3]; + } + } else { + return -1; + } + + loglogdata(log, "=>O", data, MAX_UDP_PACKET_SIZE, *ip_port, *length); + + return 0; +} + +void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object) +{ + net->packethandlers[byte].function = cb; + net->packethandlers[byte].object = object; +} + +void networking_poll(Networking_Core *net, void *userdata) +{ + if (net->family == 0) { /* Socket not initialized */ + return; + } + + unix_time_update(); + + IP_Port ip_port; + uint8_t data[MAX_UDP_PACKET_SIZE]; + uint32_t length; + + while (receivepacket(net->log, net->sock, &ip_port, data, &length) != -1) { + if (length < 1) { + continue; + } + + if (!(net->packethandlers[data[0]].function)) { + LOGGER_WARNING(net->log, "[%02u] -- Packet has no handler", data[0]); + continue; + } + + net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length, userdata); + } +} + +#ifndef VANILLA_NACL +/* Used for sodium_init() */ +#include +#endif + +static uint8_t at_startup_ran = 0; +int networking_at_startup(void) +{ + if (at_startup_ran != 0) { + return 0; + } + +#ifndef VANILLA_NACL + +#ifdef USE_RANDOMBYTES_STIR + randombytes_stir(); +#else + + if (sodium_init() == -1) { + return -1; + } + +#endif /*USE_RANDOMBYTES_STIR*/ + +#endif/*VANILLA_NACL*/ + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + WSADATA wsaData; + + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) { + return -1; + } + +#endif + srand((uint32_t)current_time_actual()); + at_startup_ran = 1; + return 0; +} + +/* TODO(irungentoo): Put this somewhere */ +#if 0 +static void at_shutdown(void) +{ +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) + WSACleanup(); +#endif +} +#endif + +/* Initialize networking. + * Added for reverse compatibility with old new_networking calls. + */ +Networking_Core *new_networking(Logger *log, IP ip, uint16_t port) +{ + return new_networking_ex(log, ip, port, port + (TOX_PORTRANGE_TO - TOX_PORTRANGE_FROM), 0); +} + +/* Initialize networking. + * Bind to ip and port. + * ip must be in network order EX: 127.0.0.1 = (7F000001). + * port is in host byte order (this means don't worry about it). + * + * return Networking_Core object if no problems + * return NULL if there are problems. + * + * If error is non NULL it is set to 0 if no issues, 1 if socket related error, 2 if other. + */ +Networking_Core *new_networking_ex(Logger *log, IP ip, uint16_t port_from, uint16_t port_to, unsigned int *error) +{ + /* If both from and to are 0, use default port range + * If one is 0 and the other is non-0, use the non-0 value as only port + * If from > to, swap + */ + if (port_from == 0 && port_to == 0) { + port_from = TOX_PORTRANGE_FROM; + port_to = TOX_PORTRANGE_TO; + } else if (port_from == 0 && port_to != 0) { + port_from = port_to; + } else if (port_from != 0 && port_to == 0) { + port_to = port_from; + } else if (port_from > port_to) { + uint16_t temp = port_from; + port_from = port_to; + port_to = temp; + } + + if (error) { + *error = 2; + } + + /* maybe check for invalid IPs like 224+.x.y.z? if there is any IP set ever */ + if (ip.family != TOX_AF_INET && ip.family != TOX_AF_INET6) { + LOGGER_ERROR(log, "Invalid address family: %u\n", ip.family); + return NULL; + } + + if (networking_at_startup() != 0) { + return NULL; + } + + Networking_Core *temp = (Networking_Core *)calloc(1, sizeof(Networking_Core)); + + if (temp == NULL) { + return NULL; + } + + temp->log = log; + temp->family = ip.family; + temp->port = 0; + + /* Initialize our socket. */ + /* add log message what we're creating */ + temp->sock = net_socket(temp->family, TOX_SOCK_DGRAM, TOX_PROTO_UDP); + + /* Check for socket error. */ + if (!sock_valid(temp->sock)) { + LOGGER_ERROR(log, "Failed to get a socket?! %u, %s\n", errno, strerror(errno)); + free(temp); + + if (error) { + *error = 1; + } + + return NULL; + } + + /* Functions to increase the size of the send and receive UDP buffers. + */ + int n = 1024 * 1024 * 2; + setsockopt(temp->sock, SOL_SOCKET, SO_RCVBUF, (const char *)&n, sizeof(n)); + setsockopt(temp->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof(n)); + + /* Enable broadcast on socket */ + int broadcast = 1; + setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(broadcast)); + + /* iOS UDP sockets are weird and apparently can SIGPIPE */ + if (!set_socket_nosigpipe(temp->sock)) { + kill_networking(temp); + + if (error) { + *error = 1; + } + + return NULL; + } + + /* Set socket nonblocking. */ + if (!set_socket_nonblock(temp->sock)) { + kill_networking(temp); + + if (error) { + *error = 1; + } + + return NULL; + } + + /* Bind our socket to port PORT and the given IP address (usually 0.0.0.0 or ::) */ + uint16_t *portptr = NULL; + struct sockaddr_storage addr; + size_t addrsize; + + memset(&addr, 0, sizeof(struct sockaddr_storage)); + + if (temp->family == TOX_AF_INET) { + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + + addrsize = sizeof(struct sockaddr_in); + addr4->sin_family = AF_INET; + addr4->sin_port = 0; + fill_addr4(ip.ip4, &addr4->sin_addr); + + portptr = &addr4->sin_port; + } else if (temp->family == TOX_AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = 0; + fill_addr6(ip.ip6, &addr6->sin6_addr); + + addr6->sin6_flowinfo = 0; + addr6->sin6_scope_id = 0; + + portptr = &addr6->sin6_port; + } else { + free(temp); + return NULL; + } + + if (ip.family == TOX_AF_INET6) { + int is_dualstack = set_socket_dualstack(temp->sock); + LOGGER_DEBUG(log, "Dual-stack socket: %s", + is_dualstack ? "enabled" : "Failed to enable, won't be able to receive from/send to IPv4 addresses"); + /* multicast local nodes */ + struct ipv6_mreq mreq; + memset(&mreq, 0, sizeof(mreq)); + mreq.ipv6mr_multiaddr.s6_addr[ 0] = 0xFF; + mreq.ipv6mr_multiaddr.s6_addr[ 1] = 0x02; + mreq.ipv6mr_multiaddr.s6_addr[15] = 0x01; + mreq.ipv6mr_interface = 0; + int res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq)); + + LOGGER_DEBUG(log, res < 0 ? "Failed to activate local multicast membership. (%u, %s)" : + "Local multicast group FF02::1 joined successfully", errno, strerror(errno)); + } + + /* a hanging program or a different user might block the standard port; + * as long as it isn't a parameter coming from the commandline, + * try a few ports after it, to see if we can find a "free" one + * + * if we go on without binding, the first sendto() automatically binds to + * a free port chosen by the system (i.e. anything from 1024 to 65535) + * + * returning NULL after bind fails has both advantages and disadvantages: + * advantage: + * we can rely on getting the port in the range 33445..33450, which + * enables us to tell joe user to open their firewall to a small range + * + * disadvantage: + * some clients might not test return of tox_new(), blindly assuming that + * it worked ok (which it did previously without a successful bind) + */ + uint16_t port_to_try = port_from; + *portptr = net_htons(port_to_try); + int tries; + + for (tries = port_from; tries <= port_to; tries++) { + int res = bind(temp->sock, (struct sockaddr *)&addr, addrsize); + + if (!res) { + temp->port = *portptr; + + char ip_str[IP_NTOA_LEN]; + LOGGER_DEBUG(log, "Bound successfully to %s:%u", ip_ntoa(&ip, ip_str, sizeof(ip_str)), + net_ntohs(temp->port)); + + /* errno isn't reset on success, only set on failure, the failed + * binds with parallel clients yield a -EPERM to the outside if + * errno isn't cleared here */ + if (tries > 0) { + errno = 0; + } + + if (error) { + *error = 0; + } + + return temp; + } + + port_to_try++; + + if (port_to_try > port_to) { + port_to_try = port_from; + } + + *portptr = net_htons(port_to_try); + } + + char ip_str[IP_NTOA_LEN]; + LOGGER_ERROR(log, "Failed to bind socket: %u, %s IP: %s port_from: %u port_to: %u", errno, strerror(errno), + ip_ntoa(&ip, ip_str, sizeof(ip_str)), port_from, port_to); + + kill_networking(temp); + + if (error) { + *error = 1; + } + + return NULL; +} + +/* Function to cleanup networking stuff. */ +void kill_networking(Networking_Core *net) +{ + if (!net) { + return; + } + + if (net->family != 0) { /* Socket not initialized */ + kill_sock(net->sock); + } + + free(net); +} + + +/* ip_equal + * compares two IPAny structures + * unset means unequal + * + * returns 0 when not equal or when uninitialized + */ +int ip_equal(const IP *a, const IP *b) +{ + if (!a || !b) { + return 0; + } + + /* same family */ + if (a->family == b->family) { + if (a->family == TOX_AF_INET || a->family == TCP_INET) { + struct in_addr addr_a; + struct in_addr addr_b; + fill_addr4(a->ip4, &addr_a); + fill_addr4(b->ip4, &addr_b); + return addr_a.s_addr == addr_b.s_addr; + } + + if (a->family == TOX_AF_INET6 || a->family == TCP_INET6) { + return a->ip6.uint64[0] == b->ip6.uint64[0] && + a->ip6.uint64[1] == b->ip6.uint64[1]; + } + + return 0; + } + + /* different family: check on the IPv6 one if it is the IPv4 one embedded */ + if ((a->family == TOX_AF_INET) && (b->family == TOX_AF_INET6)) { + if (IPV6_IPV4_IN_V6(b->ip6)) { + struct in_addr addr_a; + fill_addr4(a->ip4, &addr_a); + return addr_a.s_addr == b->ip6.uint32[3]; + } + } else if ((a->family == TOX_AF_INET6) && (b->family == TOX_AF_INET)) { + if (IPV6_IPV4_IN_V6(a->ip6)) { + struct in_addr addr_b; + fill_addr4(b->ip4, &addr_b); + return a->ip6.uint32[3] == addr_b.s_addr; + } + } + + return 0; +} + +/* ipport_equal + * compares two IPAny_Port structures + * unset means unequal + * + * returns 0 when not equal or when uninitialized + */ +int ipport_equal(const IP_Port *a, const IP_Port *b) +{ + if (!a || !b) { + return 0; + } + + if (!a->port || (a->port != b->port)) { + return 0; + } + + return ip_equal(&a->ip, &b->ip); +} + +/* nulls out ip */ +void ip_reset(IP *ip) +{ + if (!ip) { + return; + } + + memset(ip, 0, sizeof(IP)); +} + +/* nulls out ip, sets family according to flag */ +void ip_init(IP *ip, uint8_t ipv6enabled) +{ + if (!ip) { + return; + } + + memset(ip, 0, sizeof(IP)); + ip->family = ipv6enabled ? TOX_AF_INET6 : TOX_AF_INET; +} + +/* checks if ip is valid */ +int ip_isset(const IP *ip) +{ + if (!ip) { + return 0; + } + + return (ip->family != 0); +} + +/* checks if ip is valid */ +int ipport_isset(const IP_Port *ipport) +{ + if (!ipport) { + return 0; + } + + if (!ipport->port) { + return 0; + } + + return ip_isset(&ipport->ip); +} + +/* copies an ip structure (careful about direction!) */ +void ip_copy(IP *target, const IP *source) +{ + if (!source || !target) { + return; + } + + memcpy(target, source, sizeof(IP)); +} + +/* copies an ip_port structure (careful about direction!) */ +void ipport_copy(IP_Port *target, const IP_Port *source) +{ + if (!source || !target) { + return; + } + + memcpy(target, source, sizeof(IP_Port)); +} + +/* ip_ntoa + * converts ip into a string + * ip_str must be of length at least IP_NTOA_LEN + * + * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" + * writes error message into the buffer on error + * + * returns ip_str + */ +const char *ip_ntoa(const IP *ip, char *ip_str, size_t length) +{ + if (length < IP_NTOA_LEN) { + snprintf(ip_str, length, "Bad buf length"); + return ip_str; + } + + if (ip) { + const int family = make_family(ip->family); + + if (ip->family == TOX_AF_INET) { + /* returns standard quad-dotted notation */ + struct in_addr addr; + fill_addr4(ip->ip4, &addr); + + ip_str[0] = 0; + inet_ntop(family, &addr, ip_str, length); + } else if (ip->family == TOX_AF_INET6) { + /* returns hex-groups enclosed into square brackets */ + struct in6_addr addr; + fill_addr6(ip->ip6, &addr); + + ip_str[0] = '['; + inet_ntop(family, &addr, &ip_str[1], length - 3); + size_t len = strlen(ip_str); + ip_str[len] = ']'; + ip_str[len + 1] = 0; + } else { + snprintf(ip_str, length, "(IP invalid, family %u)", ip->family); + } + } else { + snprintf(ip_str, length, "(IP invalid: NULL)"); + } + + /* brute force protection against lacking termination */ + ip_str[length - 1] = 0; + return ip_str; +} + +/* + * ip_parse_addr + * parses IP structure into an address string + * + * input + * ip: ip of TOX_AF_INET or TOX_AF_INET6 families + * length: length of the address buffer + * Must be at least INET_ADDRSTRLEN for TOX_AF_INET + * and INET6_ADDRSTRLEN for TOX_AF_INET6 + * + * output + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * returns 1 on success, 0 on failure + */ +int ip_parse_addr(const IP *ip, char *address, size_t length) +{ + if (!address || !ip) { + return 0; + } + + if (ip->family == TOX_AF_INET) { + const struct in_addr *addr = (const struct in_addr *)&ip->ip4; + return inet_ntop(ip->family, addr, address, length) != NULL; + } + + if (ip->family == TOX_AF_INET6) { + const struct in6_addr *addr = (const struct in6_addr *)&ip->ip6; + return inet_ntop(ip->family, addr, address, length) != NULL; + } + + return 0; +} + +/* + * addr_parse_ip + * directly parses the input into an IP structure + * tries IPv4 first, then IPv6 + * + * input + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * output + * IP: family and the value is set on success + * + * returns 1 on success, 0 on failure + */ +int addr_parse_ip(const char *address, IP *to) +{ + if (!address || !to) { + return 0; + } + + struct in_addr addr4; + + if (inet_pton(AF_INET, address, &addr4) == 1) { + to->family = TOX_AF_INET; + get_ip4(&to->ip4, &addr4); + return 1; + } + + struct in6_addr addr6; + + if (inet_pton(AF_INET6, address, &addr6) == 1) { + to->family = TOX_AF_INET6; + get_ip6(&to->ip6, &addr6); + return 1; + } + + return 0; +} + +/* + * addr_resolve(): + * uses getaddrinfo to resolve an address into an IP address + * uses the first IPv4/IPv6 addresses returned by getaddrinfo + * + * input + * address: a hostname (or something parseable to an IP address) + * to: to.family MUST be initialized, either set to a specific IP version + * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both + * IP versions are acceptable + * extra can be NULL and is only set in special circumstances, see returns + * + * returns in *to a valid IPAny (v4/v6), + * prefers v6 if ip.family was AF_UNSPEC and both available + * returns in *extra an IPv4 address, if family was AF_UNSPEC and *to is TOX_AF_INET6 + * returns 0 on failure, TOX_ADDR_RESOLVE_* on success. + */ +int addr_resolve(const char *address, IP *to, IP *extra) +{ + if (!address || !to) { + return 0; + } + + Family tox_family = to->family; + Family family = make_family(tox_family); + + struct addrinfo *server = NULL; + struct addrinfo *walker = NULL; + struct addrinfo hints; + int rc; + int result = 0; + int done = 0; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_DGRAM; // type of socket Tox uses. + + if (networking_at_startup() != 0) { + return 0; + } + + rc = getaddrinfo(address, NULL, &hints, &server); + + // Lookup failed. + if (rc != 0) { + return 0; + } + + IP ip4; + ip_init(&ip4, 0); // ipv6enabled = 0 + IP ip6; + ip_init(&ip6, 1); // ipv6enabled = 1 + + for (walker = server; (walker != NULL) && !done; walker = walker->ai_next) { + switch (walker->ai_family) { + case AF_INET: + if (walker->ai_family == family) { /* AF_INET requested, done */ + struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr; + get_ip4(&to->ip4, &addr->sin_addr); + result = TOX_ADDR_RESOLVE_INET; + done = 1; + } else if (!(result & TOX_ADDR_RESOLVE_INET)) { /* AF_UNSPEC requested, store away */ + struct sockaddr_in *addr = (struct sockaddr_in *)walker->ai_addr; + get_ip4(&ip4.ip4, &addr->sin_addr); + result |= TOX_ADDR_RESOLVE_INET; + } + + break; /* switch */ + + case AF_INET6: + if (walker->ai_family == family) { /* AF_INET6 requested, done */ + if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr; + get_ip6(&to->ip6, &addr->sin6_addr); + result = TOX_ADDR_RESOLVE_INET6; + done = 1; + } + } else if (!(result & TOX_ADDR_RESOLVE_INET6)) { /* AF_UNSPEC requested, store away */ + if (walker->ai_addrlen == sizeof(struct sockaddr_in6)) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)walker->ai_addr; + get_ip6(&ip6.ip6, &addr->sin6_addr); + result |= TOX_ADDR_RESOLVE_INET6; + } + } + + break; /* switch */ + } + } + + if (family == AF_UNSPEC) { + if (result & TOX_ADDR_RESOLVE_INET6) { + ip_copy(to, &ip6); + + if ((result & TOX_ADDR_RESOLVE_INET) && (extra != NULL)) { + ip_copy(extra, &ip4); + } + } else if (result & TOX_ADDR_RESOLVE_INET) { + ip_copy(to, &ip4); + } else { + result = 0; + } + } + + freeaddrinfo(server); + return result; +} + +/* + * addr_resolve_or_parse_ip + * resolves string into an IP address + * + * address: a hostname (or something parseable to an IP address) + * to: to.family MUST be initialized, either set to a specific IP version + * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified AF_UNSPEC (= 0), if both + * IP versions are acceptable + * extra can be NULL and is only set in special circumstances, see returns + * + * returns in *tro a matching address (IPv6 or IPv4) + * returns in *extra, if not NULL, an IPv4 address, if to->family was AF_UNSPEC + * returns 1 on success + * returns 0 on failure + */ +int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra) +{ + if (!addr_resolve(address, to, extra)) { + if (!addr_parse_ip(address, to)) { + return 0; + } + } + + return 1; +} + +int net_connect(Socket sock, IP_Port ip_port) +{ + struct sockaddr_storage addr = {0}; + size_t addrsize; + + if (ip_port.ip.family == TOX_AF_INET) { + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + + addrsize = sizeof(struct sockaddr_in); + addr4->sin_family = AF_INET; + fill_addr4(ip_port.ip.ip4, &addr4->sin_addr); + addr4->sin_port = ip_port.port; + } else if (ip_port.ip.family == TOX_AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + fill_addr6(ip_port.ip.ip6, &addr6->sin6_addr); + addr6->sin6_port = ip_port.port; + } else { + return 0; + } + + return connect(sock, (struct sockaddr *)&addr, addrsize); +} + +int32_t net_getipport(const char *node, IP_Port **res, int tox_type) +{ + struct addrinfo *infos; + int ret = getaddrinfo(node, NULL, NULL, &infos); + *res = NULL; + + if (ret != 0) { + return -1; + } + + // Used to avoid malloc parameter overflow + const size_t MAX_COUNT = MIN(SIZE_MAX, INT32_MAX) / sizeof(IP_Port); + int type = make_socktype(tox_type); + struct addrinfo *cur; + int32_t count = 0; + + for (cur = infos; count < MAX_COUNT && cur != NULL; cur = cur->ai_next) { + if (cur->ai_socktype && type > 0 && cur->ai_socktype != type) { + continue; + } + + if (cur->ai_family != AF_INET && cur->ai_family != AF_INET6) { + continue; + } + + count++; + } + + assert(count <= MAX_COUNT); + + if (count == 0) { + return 0; + } + + *res = (IP_Port *)malloc(sizeof(IP_Port) * count); + + if (*res == NULL) { + return -1; + } + + IP_Port *ip_port = *res; + + for (cur = infos; cur != NULL; cur = cur->ai_next) { + if (cur->ai_socktype && type > 0 && cur->ai_socktype != type) { + continue; + } + + if (cur->ai_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)cur->ai_addr; + memcpy(&ip_port->ip.ip4, &addr->sin_addr, sizeof(IP4)); + } else if (cur->ai_family == AF_INET6) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)cur->ai_addr; + memcpy(&ip_port->ip.ip6, &addr->sin6_addr, sizeof(IP6)); + } else { + continue; + } + + ip_port->ip.family = make_tox_family(cur->ai_family); + + ip_port++; + } + + freeaddrinfo(infos); + + return count; +} + +void net_freeipport(IP_Port *ip_ports) +{ + free(ip_ports); +} + +/* return 1 on success + * return 0 on failure + */ +int bind_to_port(Socket sock, int family, uint16_t port) +{ + struct sockaddr_storage addr = {0}; + size_t addrsize; + + if (family == TOX_AF_INET) { + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + + addrsize = sizeof(struct sockaddr_in); + addr4->sin_family = AF_INET; + addr4->sin_port = net_htons(port); + } else if (family == TOX_AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; + + addrsize = sizeof(struct sockaddr_in6); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = net_htons(port); + } else { + return 0; + } + + return (bind(sock, (struct sockaddr *)&addr, addrsize) == 0); +} + +static int make_tox_family(int family) +{ + switch (family) { + case AF_INET: + return TOX_AF_INET; + + case AF_INET6: + return TOX_AF_INET6; + + case AF_UNSPEC: + return TOX_AF_UNSPEC; + + default: + return family; + } +} + +static int make_family(int tox_family) +{ + switch (tox_family) { + case TOX_AF_INET: + return AF_INET; + + case TOX_AF_INET6: + return AF_INET6; + + case TOX_AF_UNSPEC: + return AF_UNSPEC; + + default: + return tox_family; + } +} + +static int make_socktype(int type) +{ + switch (type) { + case TOX_SOCK_STREAM: + return SOCK_STREAM; + + case TOX_SOCK_DGRAM: + return SOCK_DGRAM; + + default: + return type; + } +} + +static int make_proto(int proto) +{ + switch (proto) { + case TOX_PROTO_TCP: + return IPPROTO_TCP; + + case TOX_PROTO_UDP: + return IPPROTO_UDP; + + default: + return proto; + } +} + +Socket net_socket(int domain, int type, int protocol) +{ + int platform_domain = make_family(domain); + int platform_type = make_socktype(type); + int platform_prot = make_proto(protocol); + return socket(platform_domain, platform_type, platform_prot); +} + +/* TODO: Remove, when tox DNS support will be removed. + * Used only by dns3_test.c + */ +size_t net_sendto_ip4(Socket sock, const char *buf, size_t n, IP_Port ip_port) +{ + struct sockaddr_in target; + size_t addrsize = sizeof(target); + target.sin_family = make_family(ip_port.ip.family); + target.sin_port = net_htons(ip_port.port); + fill_addr4(ip_port.ip.ip4, &target.sin_addr); + + return (size_t)sendto(sock, buf, n, 0, (struct sockaddr *)&target, addrsize); +} + +uint32_t net_htonl(uint32_t hostlong) +{ + return htonl(hostlong); +} + +uint16_t net_htons(uint16_t hostshort) +{ + return htons(hostshort); +} + +uint32_t net_ntohl(uint32_t hostlong) +{ + return ntohl(hostlong); +} + +uint16_t net_ntohs(uint16_t hostshort) +{ + return ntohs(hostshort); +} diff --git a/libs/libtox/src/toxcore/network.h b/libs/libtox/src/toxcore/network.h new file mode 100644 index 0000000000..0b9da5a40f --- /dev/null +++ b/libs/libtox/src/toxcore/network.h @@ -0,0 +1,424 @@ +/* + * Datatypes, functions and includes for the core networking. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef NETWORK_H +#define NETWORK_H + +#ifdef PLAN9 +#include // Plan 9 requires this is imported first +// Comment line here to avoid reordering by source code formatters. +#include +#endif + +#include "ccompat.h" +#include "logger.h" + +#include +#include +#include +#include +#include + +#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32) /* Put win32 includes here */ +#ifndef WINVER +//Windows XP +#define WINVER 0x0501 +#endif + +// The mingw32/64 Windows library warns about including winsock2.h after +// windows.h even though with the above it's a valid thing to do. So, to make +// mingw32 headers happy, we include winsock2.h first. +#include + +#include +#include + +#else // UNIX includes + +#include +#include +#include +#include +#include + +#endif + +typedef short Family; + +typedef int Socket; +Socket net_socket(int domain, int type, int protocol); + +#define MAX_UDP_PACKET_SIZE 2048 + +typedef enum NET_PACKET_TYPE { + NET_PACKET_PING_REQUEST = 0x00, /* Ping request packet ID. */ + NET_PACKET_PING_RESPONSE = 0x01, /* Ping response packet ID. */ + NET_PACKET_GET_NODES = 0x02, /* Get nodes request packet ID. */ + NET_PACKET_SEND_NODES_IPV6 = 0x04, /* Send nodes response packet ID for other addresses. */ + NET_PACKET_COOKIE_REQUEST = 0x18, /* Cookie request packet */ + NET_PACKET_COOKIE_RESPONSE = 0x19, /* Cookie response packet */ + NET_PACKET_CRYPTO_HS = 0x1a, /* Crypto handshake packet */ + NET_PACKET_CRYPTO_DATA = 0x1b, /* Crypto data packet */ + NET_PACKET_CRYPTO = 0x20, /* Encrypted data packet ID. */ + NET_PACKET_LAN_DISCOVERY = 0x21, /* LAN discovery packet ID. */ + + /* See: docs/Prevent_Tracking.txt and onion.{c,h} */ + NET_PACKET_ONION_SEND_INITIAL = 0x80, + NET_PACKET_ONION_SEND_1 = 0x81, + NET_PACKET_ONION_SEND_2 = 0x82, + + NET_PACKET_ANNOUNCE_REQUEST = 0x83, + NET_PACKET_ANNOUNCE_RESPONSE = 0x84, + NET_PACKET_ONION_DATA_REQUEST = 0x85, + NET_PACKET_ONION_DATA_RESPONSE = 0x86, + + NET_PACKET_ONION_RECV_3 = 0x8c, + NET_PACKET_ONION_RECV_2 = 0x8d, + NET_PACKET_ONION_RECV_1 = 0x8e, + + BOOTSTRAP_INFO_PACKET_ID = 0xf0, /* Only used for bootstrap nodes */ + + NET_PACKET_MAX = 0xff, /* This type must remain within a single uint8. */ +} NET_PACKET_TYPE; + + +#define TOX_PORTRANGE_FROM 33445 +#define TOX_PORTRANGE_TO 33545 +#define TOX_PORT_DEFAULT TOX_PORTRANGE_FROM + +/* Redefinitions of variables for safe transfer over wire. */ +#define TOX_AF_UNSPEC 0 +#define TOX_AF_INET 2 +#define TOX_AF_INET6 10 +#define TOX_TCP_INET 130 +#define TOX_TCP_INET6 138 + +#define TOX_SOCK_STREAM 1 +#define TOX_SOCK_DGRAM 2 + +#define TOX_PROTO_TCP 1 +#define TOX_PROTO_UDP 2 + +/* TCP related */ +#define TCP_ONION_FAMILY (TOX_AF_INET6 + 1) +#define TCP_INET (TOX_AF_INET6 + 2) +#define TCP_INET6 (TOX_AF_INET6 + 3) +#define TCP_FAMILY (TOX_AF_INET6 + 4) + +typedef union { + uint32_t uint32; + uint16_t uint16[2]; + uint8_t uint8[4]; +} +IP4; + +IP4 get_ip4_loopback(void); +extern const IP4 IP4_BROADCAST; + +typedef union { + uint8_t uint8[16]; + uint16_t uint16[8]; + uint32_t uint32[4]; + uint64_t uint64[2]; +} +IP6; + +IP6 get_ip6_loopback(void); +extern const IP6 IP6_BROADCAST; + +typedef struct { + uint8_t family; + GNU_EXTENSION union { + IP4 ip4; + IP6 ip6; + }; +} +IP; + +typedef struct { + IP ip; + uint16_t port; +} +IP_Port; + +/* Convert values between host and network byte order. + */ +uint32_t net_htonl(uint32_t hostlong); +uint16_t net_htons(uint16_t hostshort); +uint32_t net_ntohl(uint32_t hostlong); +uint16_t net_ntohs(uint16_t hostshort); + +/* Does the IP6 struct a contain an IPv4 address in an IPv6 one? */ +#define IPV6_IPV4_IN_V6(a) ((a.uint64[0] == 0) && (a.uint32[2] == net_htonl (0xffff))) + +#define SIZE_IP4 4 +#define SIZE_IP6 16 +#define SIZE_IP (1 + SIZE_IP6) +#define SIZE_PORT 2 +#define SIZE_IPPORT (SIZE_IP + SIZE_PORT) + +#define TOX_ENABLE_IPV6_DEFAULT 1 + +/* addr_resolve return values */ +#define TOX_ADDR_RESOLVE_INET 1 +#define TOX_ADDR_RESOLVE_INET6 2 + +#define TOX_INET6_ADDRSTRLEN 66 +#define TOX_INET_ADDRSTRLEN 22 + +/* ip_ntoa + * converts ip into a string + * ip_str must be of length at least IP_NTOA_LEN + * + * IPv6 addresses are enclosed into square brackets, i.e. "[IPv6]" + * writes error message into the buffer on error + * + * returns ip_str + */ +/* this would be TOX_INET6_ADDRSTRLEN, but it might be too short for the error message */ +#define IP_NTOA_LEN 96 // TODO(irungentoo): magic number. Why not INET6_ADDRSTRLEN ? +const char *ip_ntoa(const IP *ip, char *ip_str, size_t length); + +/* + * ip_parse_addr + * parses IP structure into an address string + * + * input + * ip: ip of TOX_AF_INET or TOX_AF_INET6 families + * length: length of the address buffer + * Must be at least TOX_INET_ADDRSTRLEN for TOX_AF_INET + * and TOX_INET6_ADDRSTRLEN for TOX_AF_INET6 + * + * output + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * returns 1 on success, 0 on failure + */ +int ip_parse_addr(const IP *ip, char *address, size_t length); + +/* + * addr_parse_ip + * directly parses the input into an IP structure + * tries IPv4 first, then IPv6 + * + * input + * address: dotted notation (IPv4: quad, IPv6: 16) or colon notation (IPv6) + * + * output + * IP: family and the value is set on success + * + * returns 1 on success, 0 on failure + */ +int addr_parse_ip(const char *address, IP *to); + +/* ip_equal + * compares two IPAny structures + * unset means unequal + * + * returns 0 when not equal or when uninitialized + */ +int ip_equal(const IP *a, const IP *b); + +/* ipport_equal + * compares two IPAny_Port structures + * unset means unequal + * + * returns 0 when not equal or when uninitialized + */ +int ipport_equal(const IP_Port *a, const IP_Port *b); + +/* nulls out ip */ +void ip_reset(IP *ip); +/* nulls out ip, sets family according to flag */ +void ip_init(IP *ip, uint8_t ipv6enabled); +/* checks if ip is valid */ +int ip_isset(const IP *ip); +/* checks if ip is valid */ +int ipport_isset(const IP_Port *ipport); +/* copies an ip structure */ +void ip_copy(IP *target, const IP *source); +/* copies an ip_port structure */ +void ipport_copy(IP_Port *target, const IP_Port *source); + +/* + * addr_resolve(): + * uses getaddrinfo to resolve an address into an IP address + * uses the first IPv4/IPv6 addresses returned by getaddrinfo + * + * input + * address: a hostname (or something parseable to an IP address) + * to: to.family MUST be initialized, either set to a specific IP version + * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified TOX_AF_UNSPEC (= 0), if both + * IP versions are acceptable + * extra can be NULL and is only set in special circumstances, see returns + * + * returns in *to a valid IPAny (v4/v6), + * prefers v6 if ip.family was TOX_AF_UNSPEC and both available + * returns in *extra an IPv4 address, if family was TOX_AF_UNSPEC and *to is TOX_AF_INET6 + * returns 0 on failure + */ +int addr_resolve(const char *address, IP *to, IP *extra); + +/* + * addr_resolve_or_parse_ip + * resolves string into an IP address + * + * address: a hostname (or something parseable to an IP address) + * to: to.family MUST be initialized, either set to a specific IP version + * (TOX_AF_INET/TOX_AF_INET6) or to the unspecified TOX_AF_UNSPEC (= 0), if both + * IP versions are acceptable + * extra can be NULL and is only set in special circumstances, see returns + * + * returns in *tro a matching address (IPv6 or IPv4) + * returns in *extra, if not NULL, an IPv4 address, if to->family was TOX_AF_UNSPEC + * returns 1 on success + * returns 0 on failure + */ +int addr_resolve_or_parse_ip(const char *address, IP *to, IP *extra); + +/* Function to receive data, ip and port of sender is put into ip_port. + * Packet data is put into data. + * Packet length is put into length. + */ +typedef int (*packet_handler_callback)(void *object, IP_Port ip_port, const uint8_t *data, uint16_t len, + void *userdata); + +typedef struct { + packet_handler_callback function; + void *object; +} Packet_Handles; + +typedef struct { + Logger *log; + Packet_Handles packethandlers[256]; + + Family family; + uint16_t port; + /* Our UDP socket. */ + Socket sock; +} Networking_Core; + +/* Run this before creating sockets. + * + * return 0 on success + * return -1 on failure + */ +int networking_at_startup(void); + +/* Check if socket is valid. + * + * return 1 if valid + * return 0 if not valid + */ +int sock_valid(Socket sock); + +/* Close the socket. + */ +void kill_sock(Socket sock); + +/* Set socket as nonblocking + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nonblock(Socket sock); + +/* Set socket to not emit SIGPIPE + * + * return 1 on success + * return 0 on failure + */ +int set_socket_nosigpipe(Socket sock); + +/* Enable SO_REUSEADDR on socket. + * + * return 1 on success + * return 0 on failure + */ +int set_socket_reuseaddr(Socket sock); + +/* Set socket to dual (IPv4 + IPv6 socket) + * + * return 1 on success + * return 0 on failure + */ +int set_socket_dualstack(Socket sock); + +/* return current monotonic time in milliseconds (ms). */ +uint64_t current_time_monotonic(void); + +/* Basic network functions: */ + +/* Function to send packet(data) of length length to ip_port. */ +int sendpacket(Networking_Core *net, IP_Port ip_port, const uint8_t *data, uint16_t length); + +/* Function to call when packet beginning with byte is received. */ +void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object); + +/* Call this several times a second. */ +void networking_poll(Networking_Core *net, void *userdata); + +/* Connect a socket to the address specified by the ip_port. */ +int net_connect(Socket sock, IP_Port ip_port); + +/* High-level getaddrinfo implementation. + * Given node, which identifies an Internet host, net_getipport() fills an array + * with one or more IP_Port structures, each of which contains an Internet + * address that can be specified by calling net_connect(), the port is ignored. + * + * Skip all addresses with socktype != type (use type = -1 to get all addresses) + * To correctly deallocate array memory use net_freeipport() + * + * return number of elements in res array + * and -1 on error. + */ +int32_t net_getipport(const char *node, IP_Port **res, int tox_type); + +/* Deallocates memory allocated by net_getipport + */ +void net_freeipport(IP_Port *ip_ports); + +/* return 1 on success + * return 0 on failure + */ +int bind_to_port(Socket sock, int family, uint16_t port); + +size_t net_sendto_ip4(Socket sock, const char *buf, size_t n, IP_Port ip_port); + +/* Initialize networking. + * bind to ip and port. + * ip must be in network order EX: 127.0.0.1 = (7F000001). + * port is in host byte order (this means don't worry about it). + * + * return Networking_Core object if no problems + * return NULL if there are problems. + * + * If error is non NULL it is set to 0 if no issues, 1 if socket related error, 2 if other. + */ +Networking_Core *new_networking(Logger *log, IP ip, uint16_t port); +Networking_Core *new_networking_ex(Logger *log, IP ip, uint16_t port_from, uint16_t port_to, unsigned int *error); + +/* Function to cleanup networking stuff (doesn't do much right now). */ +void kill_networking(Networking_Core *net); + +#endif diff --git a/libs/libtox/src/toxcore/onion.c b/libs/libtox/src/toxcore/onion.c new file mode 100644 index 0000000000..fbaf7205d9 --- /dev/null +++ b/libs/libtox/src/toxcore/onion.c @@ -0,0 +1,679 @@ +/* + * Implementation of the onion part of docs/Prevent_Tracking.txt + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "onion.h" + +#include "util.h" + +#define RETURN_1 ONION_RETURN_1 +#define RETURN_2 ONION_RETURN_2 +#define RETURN_3 ONION_RETURN_3 + +#define SEND_BASE ONION_SEND_BASE +#define SEND_3 ONION_SEND_3 +#define SEND_2 ONION_SEND_2 +#define SEND_1 ONION_SEND_1 + +/* Change symmetric keys every 2 hours to make paths expire eventually. */ +#define KEY_REFRESH_INTERVAL (2 * 60 * 60) +static void change_symmetric_key(Onion *onion) +{ + if (is_timeout(onion->timestamp, KEY_REFRESH_INTERVAL)) { + new_symmetric_key(onion->secret_symmetric_key); + onion->timestamp = unix_time(); + } +} + +/* packing and unpacking functions */ +static void ip_pack(uint8_t *data, IP source) +{ + data[0] = source.family; + + if (source.family == TOX_AF_INET || source.family == TOX_TCP_INET) { + memset(data + 1, 0, SIZE_IP6); + memcpy(data + 1, source.ip4.uint8, SIZE_IP4); + } else { + memcpy(data + 1, source.ip6.uint8, SIZE_IP6); + } +} + +/* return 0 on success, -1 on failure. */ +static int ip_unpack(IP *target, const uint8_t *data, unsigned int data_size, bool disable_family_check) +{ + if (data_size < (1 + SIZE_IP6)) { + return -1; + } + + target->family = data[0]; + + if (target->family == TOX_AF_INET || target->family == TOX_TCP_INET) { + memcpy(target->ip4.uint8, data + 1, SIZE_IP4); + } else { + memcpy(target->ip6.uint8, data + 1, SIZE_IP6); + } + + bool valid = disable_family_check || + target->family == TOX_AF_INET || + target->family == TOX_AF_INET6; + + return valid ? 0 : -1; +} + +static void ipport_pack(uint8_t *data, const IP_Port *source) +{ + ip_pack(data, source->ip); + memcpy(data + SIZE_IP, &source->port, SIZE_PORT); +} + +/* return 0 on success, -1 on failure. */ +static int ipport_unpack(IP_Port *target, const uint8_t *data, unsigned int data_size, bool disable_family_check) +{ + if (data_size < (SIZE_IP + SIZE_PORT)) { + return -1; + } + + if (ip_unpack(&target->ip, data, data_size, disable_family_check) == -1) { + return -1; + } + + memcpy(&target->port, data + SIZE_IP, SIZE_PORT); + return 0; +} + + +/* Create a new onion path. + * + * Create a new onion path out of nodes (nodes is a list of ONION_PATH_LENGTH nodes) + * + * new_path must be an empty memory location of atleast Onion_Path size. + * + * return -1 on failure. + * return 0 on success. + */ +int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes) +{ + if (!new_path || !nodes) { + return -1; + } + + encrypt_precompute(nodes[0].public_key, dht->self_secret_key, new_path->shared_key1); + memcpy(new_path->public_key1, dht->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + uint8_t random_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t random_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + crypto_new_keypair(random_public_key, random_secret_key); + encrypt_precompute(nodes[1].public_key, random_secret_key, new_path->shared_key2); + memcpy(new_path->public_key2, random_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + crypto_new_keypair(random_public_key, random_secret_key); + encrypt_precompute(nodes[2].public_key, random_secret_key, new_path->shared_key3); + memcpy(new_path->public_key3, random_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + new_path->ip_port1 = nodes[0].ip_port; + new_path->ip_port2 = nodes[1].ip_port; + new_path->ip_port3 = nodes[2].ip_port; + + memcpy(new_path->node_public_key1, nodes[0].public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(new_path->node_public_key2, nodes[1].public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(new_path->node_public_key3, nodes[2].public_key, CRYPTO_PUBLIC_KEY_SIZE); + + return 0; +} + +/* Dump nodes in onion path to nodes of length num_nodes; + * + * return -1 on failure. + * return 0 on success. + */ +int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_Path *path) +{ + if (num_nodes < ONION_PATH_LENGTH) { + return -1; + } + + nodes[0].ip_port = path->ip_port1; + nodes[1].ip_port = path->ip_port2; + nodes[2].ip_port = path->ip_port3; + + memcpy(nodes[0].public_key, path->node_public_key1, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(nodes[1].public_key, path->node_public_key2, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(nodes[2].public_key, path->node_public_key3, CRYPTO_PUBLIC_KEY_SIZE); + return 0; +} + +/* Create a onion packet. + * + * Use Onion_Path path to create packet for data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * packet should be at least ONION_MAX_PACKET_SIZE big. + * + * return -1 on failure. + * return length of created packet on success. + */ +int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length) +{ + if (1 + length + SEND_1 > max_packet_length || length == 0) { + return -1; + } + + VLA(uint8_t, step1, SIZE_IPPORT + length); + + ipport_pack(step1, &dest); + memcpy(step1 + SIZE_IPPORT, data, length); + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + VLA(uint8_t, step2, SIZE_IPPORT + SEND_BASE + length); + ipport_pack(step2, &path->ip_port3); + memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE); + + int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, SIZEOF_VLA(step1), + step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) { + return -1; + } + + VLA(uint8_t, step3, SIZE_IPPORT + SEND_BASE * 2 + length); + ipport_pack(step3, &path->ip_port2); + memcpy(step3 + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE); + len = encrypt_data_symmetric(path->shared_key2, nonce, step2, SIZEOF_VLA(step2), + step3 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) { + return -1; + } + + packet[0] = NET_PACKET_ONION_SEND_INITIAL; + memcpy(packet + 1, nonce, CRYPTO_NONCE_SIZE); + memcpy(packet + 1 + CRYPTO_NONCE_SIZE, path->public_key1, CRYPTO_PUBLIC_KEY_SIZE); + + len = encrypt_data_symmetric(path->shared_key1, nonce, step3, SIZEOF_VLA(step3), + packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + SEND_BASE * 2 + length + CRYPTO_MAC_SIZE) { + return -1; + } + + return 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + len; +} + +/* Create a onion packet to be sent over tcp. + * + * Use Onion_Path path to create packet for data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * packet should be at least ONION_MAX_PACKET_SIZE big. + * + * return -1 on failure. + * return length of created packet on success. + */ +int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length) +{ + if (CRYPTO_NONCE_SIZE + SIZE_IPPORT + SEND_BASE * 2 + length > max_packet_length || length == 0) { + return -1; + } + + VLA(uint8_t, step1, SIZE_IPPORT + length); + + ipport_pack(step1, &dest); + memcpy(step1 + SIZE_IPPORT, data, length); + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + VLA(uint8_t, step2, SIZE_IPPORT + SEND_BASE + length); + ipport_pack(step2, &path->ip_port3); + memcpy(step2 + SIZE_IPPORT, path->public_key3, CRYPTO_PUBLIC_KEY_SIZE); + + int len = encrypt_data_symmetric(path->shared_key3, nonce, step1, SIZEOF_VLA(step1), + step2 + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + length + CRYPTO_MAC_SIZE) { + return -1; + } + + ipport_pack(packet + CRYPTO_NONCE_SIZE, &path->ip_port2); + memcpy(packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT, path->public_key2, CRYPTO_PUBLIC_KEY_SIZE); + len = encrypt_data_symmetric(path->shared_key2, nonce, step2, SIZEOF_VLA(step2), + packet + CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE); + + if (len != SIZE_IPPORT + SEND_BASE + length + CRYPTO_MAC_SIZE) { + return -1; + } + + memcpy(packet, nonce, CRYPTO_NONCE_SIZE); + + return CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_PUBLIC_KEY_SIZE + len; +} + +/* Create and send a onion packet. + * + * Use Onion_Path path to send data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length) +{ + uint8_t packet[ONION_MAX_PACKET_SIZE]; + int len = create_onion_packet(packet, sizeof(packet), path, dest, data, length); + + if (len == -1) { + return -1; + } + + if (sendpacket(net, path->ip_port1, packet, len) != len) { + return -1; + } + + return 0; +} + +/* Create and send a onion response sent initially to dest with. + * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint16_t length, const uint8_t *ret) +{ + if (length > ONION_RESPONSE_MAX_DATA_SIZE || length == 0) { + return -1; + } + + VLA(uint8_t, packet, 1 + RETURN_3 + length); + packet[0] = NET_PACKET_ONION_RECV_3; + memcpy(packet + 1, ret, RETURN_3); + memcpy(packet + 1 + RETURN_3, data, length); + + if ((uint32_t)sendpacket(net, dest, packet, SIZEOF_VLA(packet)) != SIZEOF_VLA(packet)) { + return -1; + } + + return 0; +} + +static int handle_send_initial(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + SEND_1) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[ONION_MAX_PACKET_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + get_shared_key(&onion->shared_keys_1, shared_key, onion->dht->self_secret_key, packet + 1 + CRYPTO_NONCE_SIZE); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), plain); + + if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE)) { + return 1; + } + + return onion_send_1(onion, plain, len, source, packet + 1); +} + +int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, IP_Port source, const uint8_t *nonce) +{ + if (len > ONION_MAX_PACKET_SIZE + SIZE_IPPORT - (1 + CRYPTO_NONCE_SIZE + ONION_RETURN_1)) { + return 1; + } + + if (len <= SIZE_IPPORT + SEND_BASE * 2) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t ip_port[SIZE_IPPORT]; + ipport_pack(ip_port, &source); + + uint8_t data[ONION_MAX_PACKET_SIZE]; + data[0] = NET_PACKET_ONION_SEND_1; + memcpy(data + 1, nonce, CRYPTO_NONCE_SIZE); + memcpy(data + 1 + CRYPTO_NONCE_SIZE, plain + SIZE_IPPORT, len - SIZE_IPPORT); + uint16_t data_len = 1 + CRYPTO_NONCE_SIZE + (len - SIZE_IPPORT); + uint8_t *ret_part = data + data_len; + random_nonce(ret_part); + len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ip_port, SIZE_IPPORT, + ret_part + CRYPTO_NONCE_SIZE); + + if (len != SIZE_IPPORT + CRYPTO_MAC_SIZE) { + return 1; + } + + data_len += CRYPTO_NONCE_SIZE + len; + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + +static int handle_send_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + SEND_2) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[ONION_MAX_PACKET_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + get_shared_key(&onion->shared_keys_2, shared_key, onion->dht->self_secret_key, packet + 1 + CRYPTO_NONCE_SIZE); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1), plain); + + if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_1 + CRYPTO_MAC_SIZE)) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t data[ONION_MAX_PACKET_SIZE]; + data[0] = NET_PACKET_ONION_SEND_2; + memcpy(data + 1, packet + 1, CRYPTO_NONCE_SIZE); + memcpy(data + 1 + CRYPTO_NONCE_SIZE, plain + SIZE_IPPORT, len - SIZE_IPPORT); + uint16_t data_len = 1 + CRYPTO_NONCE_SIZE + (len - SIZE_IPPORT); + uint8_t *ret_part = data + data_len; + random_nonce(ret_part); + uint8_t ret_data[RETURN_1 + SIZE_IPPORT]; + ipport_pack(ret_data, &source); + memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_1), RETURN_1); + len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), + ret_part + CRYPTO_NONCE_SIZE); + + if (len != RETURN_2 - CRYPTO_NONCE_SIZE) { + return 1; + } + + data_len += CRYPTO_NONCE_SIZE + len; + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + +static int handle_send_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + SEND_3) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[ONION_MAX_PACKET_SIZE]; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + get_shared_key(&onion->shared_keys_3, shared_key, onion->dht->self_secret_key, packet + 1 + CRYPTO_NONCE_SIZE); + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2), plain); + + if (len != length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + RETURN_2 + CRYPTO_MAC_SIZE)) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t data[ONION_MAX_PACKET_SIZE]; + memcpy(data, plain + SIZE_IPPORT, len - SIZE_IPPORT); + uint16_t data_len = (len - SIZE_IPPORT); + uint8_t *ret_part = data + (len - SIZE_IPPORT); + random_nonce(ret_part); + uint8_t ret_data[RETURN_2 + SIZE_IPPORT]; + ipport_pack(ret_data, &source); + memcpy(ret_data + SIZE_IPPORT, packet + (length - RETURN_2), RETURN_2); + len = encrypt_data_symmetric(onion->secret_symmetric_key, ret_part, ret_data, sizeof(ret_data), + ret_part + CRYPTO_NONCE_SIZE); + + if (len != RETURN_3 - CRYPTO_NONCE_SIZE) { + return 1; + } + + data_len += RETURN_3; + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + + +static int handle_recv_3(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + RETURN_3) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[SIZE_IPPORT + RETURN_2]; + int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + SIZE_IPPORT + RETURN_2 + CRYPTO_MAC_SIZE, plain); + + if ((uint32_t)len != sizeof(plain)) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t data[ONION_MAX_PACKET_SIZE]; + data[0] = NET_PACKET_ONION_RECV_2; + memcpy(data + 1, plain + SIZE_IPPORT, RETURN_2); + memcpy(data + 1 + RETURN_2, packet + 1 + RETURN_3, length - (1 + RETURN_3)); + uint16_t data_len = 1 + RETURN_2 + (length - (1 + RETURN_3)); + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + +static int handle_recv_2(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + RETURN_2) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[SIZE_IPPORT + RETURN_1]; + int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + SIZE_IPPORT + RETURN_1 + CRYPTO_MAC_SIZE, plain); + + if ((uint32_t)len != sizeof(plain)) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 0) == -1) { + return 1; + } + + uint8_t data[ONION_MAX_PACKET_SIZE]; + data[0] = NET_PACKET_ONION_RECV_1; + memcpy(data + 1, plain + SIZE_IPPORT, RETURN_1); + memcpy(data + 1 + RETURN_1, packet + 1 + RETURN_2, length - (1 + RETURN_2)); + uint16_t data_len = 1 + RETURN_1 + (length - (1 + RETURN_2)); + + if ((uint32_t)sendpacket(onion->net, send_to, data, data_len) != data_len) { + return 1; + } + + return 0; +} + +static int handle_recv_1(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion *onion = (Onion *)object; + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + if (length <= 1 + RETURN_1) { + return 1; + } + + change_symmetric_key(onion); + + uint8_t plain[SIZE_IPPORT]; + int len = decrypt_data_symmetric(onion->secret_symmetric_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE, + SIZE_IPPORT + CRYPTO_MAC_SIZE, plain); + + if ((uint32_t)len != SIZE_IPPORT) { + return 1; + } + + IP_Port send_to; + + if (ipport_unpack(&send_to, plain, len, 1) == -1) { + return 1; + } + + uint16_t data_len = length - (1 + RETURN_1); + + if (onion->recv_1_function && + send_to.ip.family != TOX_AF_INET && + send_to.ip.family != TOX_AF_INET6) { + return onion->recv_1_function(onion->callback_object, send_to, packet + (1 + RETURN_1), data_len); + } + + if ((uint32_t)sendpacket(onion->net, send_to, packet + (1 + RETURN_1), data_len) != data_len) { + return 1; + } + + return 0; +} + +void set_callback_handle_recv_1(Onion *onion, int (*function)(void *, IP_Port, const uint8_t *, uint16_t), void *object) +{ + onion->recv_1_function = function; + onion->callback_object = object; +} + +Onion *new_onion(DHT *dht) +{ + if (dht == NULL) { + return NULL; + } + + Onion *onion = (Onion *)calloc(1, sizeof(Onion)); + + if (onion == NULL) { + return NULL; + } + + onion->dht = dht; + onion->net = dht->net; + new_symmetric_key(onion->secret_symmetric_key); + onion->timestamp = unix_time(); + + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, &handle_send_initial, onion); + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, &handle_send_1, onion); + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, &handle_send_2, onion); + + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_3, &handle_recv_3, onion); + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_2, &handle_recv_2, onion); + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_1, &handle_recv_1, onion); + + return onion; +} + +void kill_onion(Onion *onion) +{ + if (onion == NULL) { + return; + } + + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_INITIAL, NULL, NULL); + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_1, NULL, NULL); + networking_registerhandler(onion->net, NET_PACKET_ONION_SEND_2, NULL, NULL); + + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_3, NULL, NULL); + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_2, NULL, NULL); + networking_registerhandler(onion->net, NET_PACKET_ONION_RECV_1, NULL, NULL); + + free(onion); +} diff --git a/libs/libtox/src/toxcore/onion.h b/libs/libtox/src/toxcore/onion.h new file mode 100644 index 0000000000..e81b3a52ae --- /dev/null +++ b/libs/libtox/src/toxcore/onion.h @@ -0,0 +1,165 @@ +/* + * Implementation of the onion part of docs/Prevent_Tracking.txt + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef ONION_H +#define ONION_H + +#include "DHT.h" + +typedef struct { + DHT *dht; + Networking_Core *net; + uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + uint64_t timestamp; + + Shared_Keys shared_keys_1; + Shared_Keys shared_keys_2; + Shared_Keys shared_keys_3; + + int (*recv_1_function)(void *, IP_Port, const uint8_t *, uint16_t); + void *callback_object; +} Onion; + +#define ONION_MAX_PACKET_SIZE 1400 + +#define ONION_RETURN_1 (CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_MAC_SIZE) +#define ONION_RETURN_2 (CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_MAC_SIZE + ONION_RETURN_1) +#define ONION_RETURN_3 (CRYPTO_NONCE_SIZE + SIZE_IPPORT + CRYPTO_MAC_SIZE + ONION_RETURN_2) + +#define ONION_SEND_BASE (CRYPTO_PUBLIC_KEY_SIZE + SIZE_IPPORT + CRYPTO_MAC_SIZE) +#define ONION_SEND_3 (CRYPTO_NONCE_SIZE + ONION_SEND_BASE + ONION_RETURN_2) +#define ONION_SEND_2 (CRYPTO_NONCE_SIZE + ONION_SEND_BASE*2 + ONION_RETURN_1) +#define ONION_SEND_1 (CRYPTO_NONCE_SIZE + ONION_SEND_BASE*3) + +#define ONION_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (ONION_SEND_1 + 1)) +#define ONION_RESPONSE_MAX_DATA_SIZE (ONION_MAX_PACKET_SIZE - (1 + ONION_RETURN_3)) + +#define ONION_PATH_LENGTH 3 + +typedef struct { + uint8_t shared_key1[CRYPTO_SHARED_KEY_SIZE]; + uint8_t shared_key2[CRYPTO_SHARED_KEY_SIZE]; + uint8_t shared_key3[CRYPTO_SHARED_KEY_SIZE]; + + uint8_t public_key1[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t public_key2[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t public_key3[CRYPTO_PUBLIC_KEY_SIZE]; + + IP_Port ip_port1; + uint8_t node_public_key1[CRYPTO_PUBLIC_KEY_SIZE]; + + IP_Port ip_port2; + uint8_t node_public_key2[CRYPTO_PUBLIC_KEY_SIZE]; + + IP_Port ip_port3; + uint8_t node_public_key3[CRYPTO_PUBLIC_KEY_SIZE]; + + uint32_t path_num; +} Onion_Path; + +/* Create a new onion path. + * + * Create a new onion path out of nodes (nodes is a list of ONION_PATH_LENGTH nodes) + * + * new_path must be an empty memory location of atleast Onion_Path size. + * + * return -1 on failure. + * return 0 on success. + */ +int create_onion_path(const DHT *dht, Onion_Path *new_path, const Node_format *nodes); + +/* Dump nodes in onion path to nodes of length num_nodes; + * + * return -1 on failure. + * return 0 on success. + */ +int onion_path_to_nodes(Node_format *nodes, unsigned int num_nodes, const Onion_Path *path); + +/* Create a onion packet. + * + * Use Onion_Path path to create packet for data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * packet should be at least ONION_MAX_PACKET_SIZE big. + * + * return -1 on failure. + * return length of created packet on success. + */ +int create_onion_packet(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length); + + +/* Create a onion packet to be sent over tcp. + * + * Use Onion_Path path to create packet for data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * packet should be at least ONION_MAX_PACKET_SIZE big. + * + * return -1 on failure. + * return length of created packet on success. + */ +int create_onion_packet_tcp(uint8_t *packet, uint16_t max_packet_length, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length); + +/* Create and send a onion packet. + * + * Use Onion_Path path to send data of length to dest. + * Maximum length of data is ONION_MAX_DATA_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_onion_packet(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *data, uint16_t length); + +/* Create and send a onion response sent initially to dest with. + * Maximum length of data is ONION_RESPONSE_MAX_DATA_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_onion_response(Networking_Core *net, IP_Port dest, const uint8_t *data, uint16_t length, const uint8_t *ret); + +/* Function to handle/send received decrypted versions of the packet sent with send_onion_packet. + * + * return 0 on success. + * return 1 on failure. + * + * Used to handle these packets that are received in a non traditional way (by TCP for example). + * + * Source family must be set to something else than TOX_AF_INET6 or TOX_AF_INET so that the callback gets called + * when the response is received. + */ +int onion_send_1(const Onion *onion, const uint8_t *plain, uint16_t len, IP_Port source, const uint8_t *nonce); + +/* Set the callback to be called when the dest ip_port doesn't have TOX_AF_INET6 or TOX_AF_INET as the family. + * + * Format: function(void *object, IP_Port dest, uint8_t *data, uint16_t length) + */ +void set_callback_handle_recv_1(Onion *onion, int (*function)(void *, IP_Port, const uint8_t *, uint16_t), + void *object); + +Onion *new_onion(DHT *dht); + +void kill_onion(Onion *onion); + + +#endif diff --git a/libs/libtox/src/toxcore/onion_announce.c b/libs/libtox/src/toxcore/onion_announce.c new file mode 100644 index 0000000000..c093800719 --- /dev/null +++ b/libs/libtox/src/toxcore/onion_announce.c @@ -0,0 +1,497 @@ +/* + * Implementation of the announce part of docs/Prevent_Tracking.txt + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "onion_announce.h" + +#include "LAN_discovery.h" +#include "util.h" + +#define PING_ID_TIMEOUT ONION_ANNOUNCE_TIMEOUT + +#define ANNOUNCE_REQUEST_SIZE_RECV (ONION_ANNOUNCE_REQUEST_SIZE + ONION_RETURN_3) + +#define DATA_REQUEST_MIN_SIZE ONION_DATA_REQUEST_MIN_SIZE +#define DATA_REQUEST_MIN_SIZE_RECV (DATA_REQUEST_MIN_SIZE + ONION_RETURN_3) + +/* Create an onion announce request packet in packet of max_packet_length (recommended size ONION_ANNOUNCE_REQUEST_SIZE). + * + * dest_client_id is the public key of the node the packet will be sent to. + * public_key and secret_key is the kepair which will be used to encrypt the request. + * ping_id is the ping id that will be sent in the request. + * client_id is the client id of the node we are searching for. + * data_public_key is the public key we want others to encrypt their data packets with. + * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to + * receive back in the response. + * + * return -1 on failure. + * return packet length on success. + */ +int create_announce_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, + const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, + const uint8_t *data_public_key, uint64_t sendback_data) +{ + if (max_packet_length < ONION_ANNOUNCE_REQUEST_SIZE) { + return -1; + } + + uint8_t plain[ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; + memcpy(plain, ping_id, ONION_PING_ID_SIZE); + memcpy(plain + ONION_PING_ID_SIZE, client_id, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE, data_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE, &sendback_data, + sizeof(sendback_data)); + + packet[0] = NET_PACKET_ANNOUNCE_REQUEST; + random_nonce(packet + 1); + + int len = encrypt_data(dest_client_id, secret_key, packet + 1, plain, sizeof(plain), + packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); + + if ((uint32_t)len + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE != ONION_ANNOUNCE_REQUEST_SIZE) { + return -1; + } + + memcpy(packet + 1 + CRYPTO_NONCE_SIZE, public_key, CRYPTO_PUBLIC_KEY_SIZE); + + return ONION_ANNOUNCE_REQUEST_SIZE; +} + +/* Create an onion data request packet in packet of max_packet_length (recommended size ONION_MAX_PACKET_SIZE). + * + * public_key is the real public key of the node which we want to send the data of length length to. + * encrypt_public_key is the public key used to encrypt the data packet. + * + * nonce is the nonce to encrypt this packet with + * + * return -1 on failure. + * return 0 on success. + */ +int create_data_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key, + const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length) +{ + if (DATA_REQUEST_MIN_SIZE + length > max_packet_length) { + return -1; + } + + if (DATA_REQUEST_MIN_SIZE + length > ONION_MAX_DATA_SIZE) { + return -1; + } + + packet[0] = NET_PACKET_ONION_DATA_REQUEST; + memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); + + uint8_t random_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t random_secret_key[CRYPTO_SECRET_KEY_SIZE]; + crypto_new_keypair(random_public_key, random_secret_key); + + memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, random_public_key, CRYPTO_PUBLIC_KEY_SIZE); + + int len = encrypt_data(encrypt_public_key, random_secret_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE); + + if (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + len != DATA_REQUEST_MIN_SIZE + + length) { + return -1; + } + + return DATA_REQUEST_MIN_SIZE + length; +} + +/* Create and send an onion announce request packet. + * + * path is the path the request will take before it is sent to dest. + * + * public_key and secret_key is the kepair which will be used to encrypt the request. + * ping_id is the ping id that will be sent in the request. + * client_id is the client id of the node we are searching for. + * data_public_key is the public key we want others to encrypt their data packets with. + * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to + * receive back in the response. + * + * return -1 on failure. + * return 0 on success. + */ +int send_announce_request(Networking_Core *net, const Onion_Path *path, Node_format dest, const uint8_t *public_key, + const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, + uint64_t sendback_data) +{ + uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE]; + int len = create_announce_request(request, sizeof(request), dest.public_key, public_key, secret_key, ping_id, client_id, + data_public_key, sendback_data); + + if (len != sizeof(request)) { + return -1; + } + + uint8_t packet[ONION_MAX_PACKET_SIZE]; + len = create_onion_packet(packet, sizeof(packet), path, dest.ip_port, request, sizeof(request)); + + if (len == -1) { + return -1; + } + + if (sendpacket(net, path->ip_port1, packet, len) != len) { + return -1; + } + + return 0; +} + +/* Create and send an onion data request packet. + * + * path is the path the request will take before it is sent to dest. + * (if dest knows the person with the public_key they should + * send the packet to that person in the form of a response) + * + * public_key is the real public key of the node which we want to send the data of length length to. + * encrypt_public_key is the public key used to encrypt the data packet. + * + * nonce is the nonce to encrypt this packet with + * + * return -1 on failure. + * return 0 on success. + */ +int send_data_request(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *public_key, + const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length) +{ + uint8_t request[ONION_MAX_DATA_SIZE]; + int len = create_data_request(request, sizeof(request), public_key, encrypt_public_key, nonce, data, length); + + if (len == -1) { + return -1; + } + + uint8_t packet[ONION_MAX_PACKET_SIZE]; + len = create_onion_packet(packet, sizeof(packet), path, dest, request, len); + + if (len == -1) { + return -1; + } + + if (sendpacket(net, path->ip_port1, packet, len) != len) { + return -1; + } + + return 0; +} + +/* Generate a ping_id and put it in ping_id */ +static void generate_ping_id(const Onion_Announce *onion_a, uint64_t time, const uint8_t *public_key, + IP_Port ret_ip_port, uint8_t *ping_id) +{ + time /= PING_ID_TIMEOUT; + uint8_t data[CRYPTO_SYMMETRIC_KEY_SIZE + sizeof(time) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(ret_ip_port)]; + memcpy(data, onion_a->secret_bytes, CRYPTO_SYMMETRIC_KEY_SIZE); + memcpy(data + CRYPTO_SYMMETRIC_KEY_SIZE, &time, sizeof(time)); + memcpy(data + CRYPTO_SYMMETRIC_KEY_SIZE + sizeof(time), public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(data + CRYPTO_SYMMETRIC_KEY_SIZE + sizeof(time) + CRYPTO_PUBLIC_KEY_SIZE, &ret_ip_port, sizeof(ret_ip_port)); + crypto_sha256(ping_id, data, sizeof(data)); +} + +/* check if public key is in entries list + * + * return -1 if no + * return position in list if yes + */ +static int in_entries(const Onion_Announce *onion_a, const uint8_t *public_key) +{ + unsigned int i; + + for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) { + if (!is_timeout(onion_a->entries[i].time, ONION_ANNOUNCE_TIMEOUT) + && public_key_cmp(onion_a->entries[i].public_key, public_key) == 0) { + return i; + } + } + + return -1; +} + +typedef struct { + const uint8_t *base_public_key; + Onion_Announce_Entry entry; +} Cmp_data; + +static int cmp_entry(const void *a, const void *b) +{ + Cmp_data cmp1, cmp2; + memcpy(&cmp1, a, sizeof(Cmp_data)); + memcpy(&cmp2, b, sizeof(Cmp_data)); + Onion_Announce_Entry entry1 = cmp1.entry; + Onion_Announce_Entry entry2 = cmp2.entry; + const uint8_t *cmp_public_key = cmp1.base_public_key; + + int t1 = is_timeout(entry1.time, ONION_ANNOUNCE_TIMEOUT); + int t2 = is_timeout(entry2.time, ONION_ANNOUNCE_TIMEOUT); + + if (t1 && t2) { + return 0; + } + + if (t1) { + return -1; + } + + if (t2) { + return 1; + } + + int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); + + if (close == 1) { + return 1; + } + + if (close == 2) { + return -1; + } + + return 0; +} + +static void sort_onion_announce_list(Onion_Announce_Entry *list, unsigned int length, const uint8_t *comp_public_key) +{ + // Pass comp_public_key to qsort with each Client_data entry, so the + // comparison function can use it as the base of comparison. + VLA(Cmp_data, cmp_list, length); + + for (uint32_t i = 0; i < length; i++) { + cmp_list[i].base_public_key = comp_public_key; + cmp_list[i].entry = list[i]; + } + + qsort(cmp_list, length, sizeof(Cmp_data), cmp_entry); + + for (uint32_t i = 0; i < length; i++) { + list[i] = cmp_list[i].entry; + } +} + +/* add entry to entries list + * + * return -1 if failure + * return position if added + */ +static int add_to_entries(Onion_Announce *onion_a, IP_Port ret_ip_port, const uint8_t *public_key, + const uint8_t *data_public_key, const uint8_t *ret) +{ + + int pos = in_entries(onion_a, public_key); + + unsigned int i; + + if (pos == -1) { + for (i = 0; i < ONION_ANNOUNCE_MAX_ENTRIES; ++i) { + if (is_timeout(onion_a->entries[i].time, ONION_ANNOUNCE_TIMEOUT)) { + pos = i; + } + } + } + + if (pos == -1) { + if (id_closest(onion_a->dht->self_public_key, public_key, onion_a->entries[0].public_key) == 1) { + pos = 0; + } + } + + if (pos == -1) { + return -1; + } + + memcpy(onion_a->entries[pos].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + onion_a->entries[pos].ret_ip_port = ret_ip_port; + memcpy(onion_a->entries[pos].ret, ret, ONION_RETURN_3); + memcpy(onion_a->entries[pos].data_public_key, data_public_key, CRYPTO_PUBLIC_KEY_SIZE); + onion_a->entries[pos].time = unix_time(); + + sort_onion_announce_list(onion_a->entries, ONION_ANNOUNCE_MAX_ENTRIES, onion_a->dht->self_public_key); + return in_entries(onion_a, public_key); +} + +static int handle_announce_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion_Announce *onion_a = (Onion_Announce *)object; + + if (length != ANNOUNCE_REQUEST_SIZE_RECV) { + return 1; + } + + const uint8_t *packet_public_key = packet + 1 + CRYPTO_NONCE_SIZE; + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + get_shared_key(&onion_a->shared_keys_recv, shared_key, onion_a->dht->self_secret_key, packet_public_key); + + uint8_t plain[ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH]; + int len = decrypt_data_symmetric(shared_key, packet + 1, packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + + CRYPTO_MAC_SIZE, plain); + + if ((uint32_t)len != sizeof(plain)) { + return 1; + } + + uint8_t ping_id1[ONION_PING_ID_SIZE]; + generate_ping_id(onion_a, unix_time(), packet_public_key, source, ping_id1); + + uint8_t ping_id2[ONION_PING_ID_SIZE]; + generate_ping_id(onion_a, unix_time() + PING_ID_TIMEOUT, packet_public_key, source, ping_id2); + + int index = -1; + + uint8_t *data_public_key = plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE; + + if (crypto_memcmp(ping_id1, plain, ONION_PING_ID_SIZE) == 0 + || crypto_memcmp(ping_id2, plain, ONION_PING_ID_SIZE) == 0) { + index = add_to_entries(onion_a, source, packet_public_key, data_public_key, + packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3)); + } else { + index = in_entries(onion_a, plain + ONION_PING_ID_SIZE); + } + + /*Respond with a announce response packet*/ + Node_format nodes_list[MAX_SENT_NODES]; + unsigned int num_nodes = get_close_nodes(onion_a->dht, plain + ONION_PING_ID_SIZE, nodes_list, 0, + LAN_ip(source.ip) == 0, 1); + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + uint8_t pl[1 + ONION_PING_ID_SIZE + sizeof(nodes_list)]; + + if (index == -1) { + pl[0] = 0; + memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); + } else { + if (public_key_cmp(onion_a->entries[index].public_key, packet_public_key) == 0) { + if (public_key_cmp(onion_a->entries[index].data_public_key, data_public_key) != 0) { + pl[0] = 0; + memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); + } else { + pl[0] = 2; + memcpy(pl + 1, ping_id2, ONION_PING_ID_SIZE); + } + } else { + pl[0] = 1; + memcpy(pl + 1, onion_a->entries[index].data_public_key, CRYPTO_PUBLIC_KEY_SIZE); + } + } + + int nodes_length = 0; + + if (num_nodes != 0) { + nodes_length = pack_nodes(pl + 1 + ONION_PING_ID_SIZE, sizeof(nodes_list), nodes_list, num_nodes); + + if (nodes_length <= 0) { + return 1; + } + } + + uint8_t data[ONION_ANNOUNCE_RESPONSE_MAX_SIZE]; + len = encrypt_data_symmetric(shared_key, nonce, pl, 1 + ONION_PING_ID_SIZE + nodes_length, + data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE); + + if (len != 1 + ONION_PING_ID_SIZE + nodes_length + CRYPTO_MAC_SIZE) { + return 1; + } + + data[0] = NET_PACKET_ANNOUNCE_RESPONSE; + memcpy(data + 1, plain + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH); + memcpy(data + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, nonce, CRYPTO_NONCE_SIZE); + + if (send_onion_response(onion_a->net, source, data, + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE + len, + packet + (ANNOUNCE_REQUEST_SIZE_RECV - ONION_RETURN_3)) == -1) { + return 1; + } + + return 0; +} + +static int handle_data_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion_Announce *onion_a = (Onion_Announce *)object; + + if (length <= DATA_REQUEST_MIN_SIZE_RECV) { + return 1; + } + + if (length > ONION_MAX_PACKET_SIZE) { + return 1; + } + + int index = in_entries(onion_a, packet + 1); + + if (index == -1) { + return 1; + } + + VLA(uint8_t, data, length - (CRYPTO_PUBLIC_KEY_SIZE + ONION_RETURN_3)); + data[0] = NET_PACKET_ONION_DATA_RESPONSE; + memcpy(data + 1, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, length - (1 + CRYPTO_PUBLIC_KEY_SIZE + ONION_RETURN_3)); + + if (send_onion_response(onion_a->net, onion_a->entries[index].ret_ip_port, data, SIZEOF_VLA(data), + onion_a->entries[index].ret) == -1) { + return 1; + } + + return 0; +} + +Onion_Announce *new_onion_announce(DHT *dht) +{ + if (dht == NULL) { + return NULL; + } + + Onion_Announce *onion_a = (Onion_Announce *)calloc(1, sizeof(Onion_Announce)); + + if (onion_a == NULL) { + return NULL; + } + + onion_a->dht = dht; + onion_a->net = dht->net; + new_symmetric_key(onion_a->secret_bytes); + + networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, &handle_announce_request, onion_a); + networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, &handle_data_request, onion_a); + + return onion_a; +} + +void kill_onion_announce(Onion_Announce *onion_a) +{ + if (onion_a == NULL) { + return; + } + + networking_registerhandler(onion_a->net, NET_PACKET_ANNOUNCE_REQUEST, NULL, NULL); + networking_registerhandler(onion_a->net, NET_PACKET_ONION_DATA_REQUEST, NULL, NULL); + free(onion_a); +} diff --git a/libs/libtox/src/toxcore/onion_announce.h b/libs/libtox/src/toxcore/onion_announce.h new file mode 100644 index 0000000000..548d4b798b --- /dev/null +++ b/libs/libtox/src/toxcore/onion_announce.h @@ -0,0 +1,140 @@ +/* + * Implementation of the announce part of docs/Prevent_Tracking.txt + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef ONION_ANNOUNCE_H +#define ONION_ANNOUNCE_H + +#include "onion.h" + +#define ONION_ANNOUNCE_MAX_ENTRIES 160 +#define ONION_ANNOUNCE_TIMEOUT 300 +#define ONION_PING_ID_SIZE CRYPTO_SHA256_SIZE + +#define ONION_ANNOUNCE_SENDBACK_DATA_LENGTH (sizeof(uint64_t)) + +#define ONION_ANNOUNCE_REQUEST_SIZE (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + ONION_PING_ID_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_PUBLIC_KEY_SIZE + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_MAC_SIZE) + +#define ONION_ANNOUNCE_RESPONSE_MIN_SIZE (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE + 1 + ONION_PING_ID_SIZE + CRYPTO_MAC_SIZE) +#define ONION_ANNOUNCE_RESPONSE_MAX_SIZE (ONION_ANNOUNCE_RESPONSE_MIN_SIZE + sizeof(Node_format)*MAX_SENT_NODES) + +#define ONION_DATA_RESPONSE_MIN_SIZE (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE) + +#if ONION_PING_ID_SIZE != CRYPTO_PUBLIC_KEY_SIZE +#error announce response packets assume that ONION_PING_ID_SIZE is equal to CRYPTO_PUBLIC_KEY_SIZE +#endif + +#define ONION_DATA_REQUEST_MIN_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE) +#define MAX_DATA_REQUEST_SIZE (ONION_MAX_DATA_SIZE - ONION_DATA_REQUEST_MIN_SIZE) + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ret_ip_port; + uint8_t ret[ONION_RETURN_3]; + uint8_t data_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint64_t time; +} Onion_Announce_Entry; + +typedef struct { + DHT *dht; + Networking_Core *net; + Onion_Announce_Entry entries[ONION_ANNOUNCE_MAX_ENTRIES]; + /* This is CRYPTO_SYMMETRIC_KEY_SIZE long just so we can use new_symmetric_key() to fill it */ + uint8_t secret_bytes[CRYPTO_SYMMETRIC_KEY_SIZE]; + + Shared_Keys shared_keys_recv; +} Onion_Announce; + +/* Create an onion announce request packet in packet of max_packet_length (recommended size ONION_ANNOUNCE_REQUEST_SIZE). + * + * dest_client_id is the public key of the node the packet will be sent to. + * public_key and secret_key is the kepair which will be used to encrypt the request. + * ping_id is the ping id that will be sent in the request. + * client_id is the client id of the node we are searching for. + * data_public_key is the public key we want others to encrypt their data packets with. + * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to + * receive back in the response. + * + * return -1 on failure. + * return packet length on success. + */ +int create_announce_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *dest_client_id, + const uint8_t *public_key, const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, + const uint8_t *data_public_key, uint64_t sendback_data); + +/* Create an onion data request packet in packet of max_packet_length (recommended size ONION_MAX_PACKET_SIZE). + * + * public_key is the real public key of the node which we want to send the data of length length to. + * encrypt_public_key is the public key used to encrypt the data packet. + * + * nonce is the nonce to encrypt this packet with + * + * return -1 on failure. + * return 0 on success. + */ +int create_data_request(uint8_t *packet, uint16_t max_packet_length, const uint8_t *public_key, + const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length); + +/* Create and send an onion announce request packet. + * + * path is the path the request will take before it is sent to dest. + * + * public_key and secret_key is the kepair which will be used to encrypt the request. + * ping_id is the ping id that will be sent in the request. + * client_id is the client id of the node we are searching for. + * data_public_key is the public key we want others to encrypt their data packets with. + * sendback_data is the data of ONION_ANNOUNCE_SENDBACK_DATA_LENGTH length that we expect to + * receive back in the response. + * + * return -1 on failure. + * return 0 on success. + */ +int send_announce_request(Networking_Core *net, const Onion_Path *path, Node_format dest, const uint8_t *public_key, + const uint8_t *secret_key, const uint8_t *ping_id, const uint8_t *client_id, const uint8_t *data_public_key, + uint64_t sendback_data); + +/* Create and send an onion data request packet. + * + * path is the path the request will take before it is sent to dest. + * (if dest knows the person with the public_key they should + * send the packet to that person in the form of a response) + * + * public_key is the real public key of the node which we want to send the data of length length to. + * encrypt_public_key is the public key used to encrypt the data packet. + * + * nonce is the nonce to encrypt this packet with + * + * The maximum length of data is MAX_DATA_REQUEST_SIZE. + * + * return -1 on failure. + * return 0 on success. + */ +int send_data_request(Networking_Core *net, const Onion_Path *path, IP_Port dest, const uint8_t *public_key, + const uint8_t *encrypt_public_key, const uint8_t *nonce, const uint8_t *data, uint16_t length); + + +Onion_Announce *new_onion_announce(DHT *dht); + +void kill_onion_announce(Onion_Announce *onion_a); + + +#endif diff --git a/libs/libtox/src/toxcore/onion_client.c b/libs/libtox/src/toxcore/onion_client.c new file mode 100644 index 0000000000..94e9c91652 --- /dev/null +++ b/libs/libtox/src/toxcore/onion_client.c @@ -0,0 +1,1771 @@ +/* + * Implementation of the client part of docs/Prevent_Tracking.txt (The part that + * uses the onion stuff to connect to the friend) + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "onion_client.h" + +#include "LAN_discovery.h" +#include "util.h" + +/* defines for the array size and + timeout for onion announce packets. */ +#define ANNOUNCE_ARRAY_SIZE 256 +#define ANNOUNCE_TIMEOUT 10 + +/* Add a node to the path_nodes bootstrap array. + * + * return -1 on failure + * return 0 on success + */ +int onion_add_bs_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key) +{ + if (ip_port.ip.family != TOX_AF_INET && ip_port.ip.family != TOX_AF_INET6) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_PATH_NODES; ++i) { + if (public_key_cmp(public_key, onion_c->path_nodes_bs[i].public_key) == 0) { + return -1; + } + } + + onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].ip_port = ip_port; + memcpy(onion_c->path_nodes_bs[onion_c->path_nodes_index_bs % MAX_PATH_NODES].public_key, public_key, + CRYPTO_PUBLIC_KEY_SIZE); + + uint16_t last = onion_c->path_nodes_index_bs; + ++onion_c->path_nodes_index_bs; + + if (onion_c->path_nodes_index_bs < last) { + onion_c->path_nodes_index_bs = MAX_PATH_NODES + 1; + } + + return 0; +} + +/* Add a node to the path_nodes array. + * + * return -1 on failure + * return 0 on success + */ +static int onion_add_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key) +{ + if (ip_port.ip.family != TOX_AF_INET && ip_port.ip.family != TOX_AF_INET6) { + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_PATH_NODES; ++i) { + if (public_key_cmp(public_key, onion_c->path_nodes[i].public_key) == 0) { + return -1; + } + } + + onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].ip_port = ip_port; + memcpy(onion_c->path_nodes[onion_c->path_nodes_index % MAX_PATH_NODES].public_key, public_key, + CRYPTO_PUBLIC_KEY_SIZE); + + uint16_t last = onion_c->path_nodes_index; + ++onion_c->path_nodes_index; + + if (onion_c->path_nodes_index < last) { + onion_c->path_nodes_index = MAX_PATH_NODES + 1; + } + + return 0; +} + +/* Put up to max_num nodes in nodes. + * + * return the number of nodes. + */ +uint16_t onion_backup_nodes(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num) +{ + unsigned int i; + + if (!max_num) { + return 0; + } + + unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; + + if (num_nodes == 0) { + return 0; + } + + if (num_nodes < max_num) { + max_num = num_nodes; + } + + for (i = 0; i < max_num; ++i) { + nodes[i] = onion_c->path_nodes[(onion_c->path_nodes_index - (1 + i)) % num_nodes]; + } + + return max_num; +} + +/* Put up to max_num random nodes in nodes. + * + * return the number of nodes. + */ +static uint16_t random_nodes_path_onion(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num) +{ + unsigned int i; + + if (!max_num) { + return 0; + } + + unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; + + //if (DHT_non_lan_connected(onion_c->dht)) { + if (DHT_isconnected(onion_c->dht)) { + if (num_nodes == 0) { + return 0; + } + + for (i = 0; i < max_num; ++i) { + nodes[i] = onion_c->path_nodes[rand() % num_nodes]; + } + } else { + int random_tcp = get_random_tcp_con_number(onion_c->c); + + if (random_tcp == -1) { + return 0; + } + + if (num_nodes >= 2) { + nodes[0].ip_port.ip.family = TCP_FAMILY; + nodes[0].ip_port.ip.ip4.uint32 = random_tcp; + + for (i = 1; i < max_num; ++i) { + nodes[i] = onion_c->path_nodes[rand() % num_nodes]; + } + } else { + unsigned int num_nodes_bs = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs : + MAX_PATH_NODES; + + if (num_nodes_bs == 0) { + return 0; + } + + nodes[0].ip_port.ip.family = TCP_FAMILY; + nodes[0].ip_port.ip.ip4.uint32 = random_tcp; + + for (i = 1; i < max_num; ++i) { + nodes[i] = onion_c->path_nodes_bs[rand() % num_nodes_bs]; + } + } + } + + return max_num; +} + +/* + * return -1 if nodes are suitable for creating a new path. + * return path number of already existing similar path if one already exists. + */ +static int is_path_used(const Onion_Client_Paths *onion_paths, const Node_format *nodes) +{ + unsigned int i; + + for (i = 0; i < NUMBER_ONION_PATHS; ++i) { + if (is_timeout(onion_paths->last_path_success[i], ONION_PATH_TIMEOUT)) { + continue; + } + + if (is_timeout(onion_paths->path_creation_time[i], ONION_PATH_MAX_LIFETIME)) { + continue; + } + + // TODO(irungentoo): do we really have to check it with the last node? + if (ipport_equal(&onion_paths->paths[i].ip_port1, &nodes[ONION_PATH_LENGTH - 1].ip_port)) { + return i; + } + } + + return -1; +} + +/* is path timed out */ +static bool path_timed_out(Onion_Client_Paths *onion_paths, uint32_t pathnum) +{ + pathnum = pathnum % NUMBER_ONION_PATHS; + + bool is_new = onion_paths->last_path_success[pathnum] == onion_paths->path_creation_time[pathnum]; + uint64_t timeout = is_new ? ONION_PATH_FIRST_TIMEOUT : ONION_PATH_TIMEOUT; + + return ((onion_paths->last_path_used_times[pathnum] >= ONION_PATH_MAX_NO_RESPONSE_USES + && is_timeout(onion_paths->last_path_used[pathnum], timeout)) + || is_timeout(onion_paths->path_creation_time[pathnum], ONION_PATH_MAX_LIFETIME)); +} + +/* should node be considered to have timed out */ +static bool onion_node_timed_out(const Onion_Node *node) +{ + return (node->timestamp == 0 + || (node->unsuccessful_pings >= ONION_NODE_MAX_PINGS + && is_timeout(node->last_pinged, ONION_NODE_TIMEOUT))); +} + +/* Create a new path or use an old suitable one (if pathnum is valid) + * or a random one from onion_paths. + * + * return -1 on failure + * return 0 on success + * + * TODO(irungentoo): Make this function better, it currently probably is + * vulnerable to some attacks that could deanonimize us. + */ +static int random_path(const Onion_Client *onion_c, Onion_Client_Paths *onion_paths, uint32_t pathnum, Onion_Path *path) +{ + if (pathnum == UINT32_MAX) { + pathnum = rand() % NUMBER_ONION_PATHS; + } else { + pathnum = pathnum % NUMBER_ONION_PATHS; + } + + if (path_timed_out(onion_paths, pathnum)) { + Node_format nodes[ONION_PATH_LENGTH]; + + if (random_nodes_path_onion(onion_c, nodes, ONION_PATH_LENGTH) != ONION_PATH_LENGTH) { + return -1; + } + + int n = is_path_used(onion_paths, nodes); + + if (n == -1) { + if (create_onion_path(onion_c->dht, &onion_paths->paths[pathnum], nodes) == -1) { + return -1; + } + + onion_paths->path_creation_time[pathnum] = unix_time(); + onion_paths->last_path_success[pathnum] = onion_paths->path_creation_time[pathnum]; + onion_paths->last_path_used_times[pathnum] = ONION_PATH_MAX_NO_RESPONSE_USES / 2; + + uint32_t path_num = rand(); + path_num /= NUMBER_ONION_PATHS; + path_num *= NUMBER_ONION_PATHS; + path_num += pathnum; + + onion_paths->paths[pathnum].path_num = path_num; + } else { + pathnum = n; + } + } + + if (onion_paths->last_path_used_times[pathnum] < ONION_PATH_MAX_NO_RESPONSE_USES) { + onion_paths->last_path_used[pathnum] = unix_time(); + } + + ++onion_paths->last_path_used_times[pathnum]; + memcpy(path, &onion_paths->paths[pathnum], sizeof(Onion_Path)); + return 0; +} + +/* Does path with path_num exist. */ +static bool path_exists(Onion_Client_Paths *onion_paths, uint32_t path_num) +{ + if (path_timed_out(onion_paths, path_num)) { + return 0; + } + + return onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num; +} + +/* Set path timeouts, return the path number. + * + */ +static uint32_t set_path_timeouts(Onion_Client *onion_c, uint32_t num, uint32_t path_num) +{ + if (num > onion_c->num_friends) { + return -1; + } + + Onion_Client_Paths *onion_paths; + + if (num == 0) { + onion_paths = &onion_c->onion_paths_self; + } else { + onion_paths = &onion_c->onion_paths_friends; + } + + if (onion_paths->paths[path_num % NUMBER_ONION_PATHS].path_num == path_num) { + onion_paths->last_path_success[path_num % NUMBER_ONION_PATHS] = unix_time(); + onion_paths->last_path_used_times[path_num % NUMBER_ONION_PATHS] = 0; + + Node_format nodes[ONION_PATH_LENGTH]; + + if (onion_path_to_nodes(nodes, ONION_PATH_LENGTH, &onion_paths->paths[path_num % NUMBER_ONION_PATHS]) == 0) { + unsigned int i; + + for (i = 0; i < ONION_PATH_LENGTH; ++i) { + onion_add_path_node(onion_c, nodes[i].ip_port, nodes[i].public_key); + } + } + + return path_num; + } + + return ~0; +} + +/* Function to send onion packet via TCP and UDP. + * + * return -1 on failure. + * return 0 on success. + */ +static int send_onion_packet_tcp_udp(const Onion_Client *onion_c, const Onion_Path *path, IP_Port dest, + const uint8_t *data, uint16_t length) +{ + if (path->ip_port1.ip.family == TOX_AF_INET || path->ip_port1.ip.family == TOX_AF_INET6) { + uint8_t packet[ONION_MAX_PACKET_SIZE]; + int len = create_onion_packet(packet, sizeof(packet), path, dest, data, length); + + if (len == -1) { + return -1; + } + + if (sendpacket(onion_c->net, path->ip_port1, packet, len) != len) { + return -1; + } + + return 0; + } + + if (path->ip_port1.ip.family == TCP_FAMILY) { + uint8_t packet[ONION_MAX_PACKET_SIZE]; + int len = create_onion_packet_tcp(packet, sizeof(packet), path, dest, data, length); + + if (len == -1) { + return -1; + } + + return send_tcp_onion_request(onion_c->c, path->ip_port1.ip.ip4.uint32, packet, len); + } + + return -1; +} + +/* Creates a sendback for use in an announce request. + * + * num is 0 if we used our secret public key for the announce + * num is 1 + friendnum if we use a temporary one. + * + * Public key is the key we will be sending it to. + * ip_port is the ip_port of the node we will be sending + * it to. + * + * sendback must be at least ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big + * + * return -1 on failure + * return 0 on success + * + */ +static int new_sendback(Onion_Client *onion_c, uint32_t num, const uint8_t *public_key, IP_Port ip_port, + uint32_t path_num, uint64_t *sendback) +{ + uint8_t data[sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port) + sizeof(uint32_t)]; + memcpy(data, &num, sizeof(uint32_t)); + memcpy(data + sizeof(uint32_t), public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE, &ip_port, sizeof(IP_Port)); + memcpy(data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port), &path_num, sizeof(uint32_t)); + *sendback = ping_array_add(&onion_c->announce_ping_array, data, sizeof(data)); + + if (*sendback == 0) { + return -1; + } + + return 0; +} + +/* Checks if the sendback is valid and returns the public key contained in it in ret_pubkey and the + * ip contained in it in ret_ip_port + * + * sendback is the sendback ONION_ANNOUNCE_SENDBACK_DATA_LENGTH big + * ret_pubkey must be at least CRYPTO_PUBLIC_KEY_SIZE big + * ret_ip_port must be at least 1 big + * + * return ~0 on failure + * return num (see new_sendback(...)) on success + */ +static uint32_t check_sendback(Onion_Client *onion_c, const uint8_t *sendback, uint8_t *ret_pubkey, + IP_Port *ret_ip_port, uint32_t *path_num) +{ + uint64_t sback; + memcpy(&sback, sendback, sizeof(uint64_t)); + uint8_t data[sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port) + sizeof(uint32_t)]; + + if (ping_array_check(data, sizeof(data), &onion_c->announce_ping_array, sback) != sizeof(data)) { + return ~0; + } + + memcpy(ret_pubkey, data + sizeof(uint32_t), CRYPTO_PUBLIC_KEY_SIZE); + memcpy(ret_ip_port, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE, sizeof(IP_Port)); + memcpy(path_num, data + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port), sizeof(uint32_t)); + + uint32_t num; + memcpy(&num, data, sizeof(uint32_t)); + return num; +} + +static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, IP_Port dest, const uint8_t *dest_pubkey, + const uint8_t *ping_id, uint32_t pathnum) +{ + if (num > onion_c->num_friends) { + return -1; + } + + uint64_t sendback; + Onion_Path path; + + if (num == 0) { + if (random_path(onion_c, &onion_c->onion_paths_self, pathnum, &path) == -1) { + return -1; + } + } else { + if (random_path(onion_c, &onion_c->onion_paths_friends, pathnum, &path) == -1) { + return -1; + } + } + + if (new_sendback(onion_c, num, dest_pubkey, dest, path.path_num, &sendback) == -1) { + return -1; + } + + uint8_t zero_ping_id[ONION_PING_ID_SIZE] = {0}; + + if (ping_id == NULL) { + ping_id = zero_ping_id; + } + + uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE]; + int len; + + if (num == 0) { + len = create_announce_request(request, sizeof(request), dest_pubkey, onion_c->c->self_public_key, + onion_c->c->self_secret_key, ping_id, onion_c->c->self_public_key, onion_c->temp_public_key, sendback); + } else { + len = create_announce_request(request, sizeof(request), dest_pubkey, onion_c->friends_list[num - 1].temp_public_key, + onion_c->friends_list[num - 1].temp_secret_key, ping_id, onion_c->friends_list[num - 1].real_public_key, zero_ping_id, + sendback); + } + + if (len == -1) { + return -1; + } + + return send_onion_packet_tcp_udp(onion_c, &path, dest, request, len); +} + +typedef struct { + const uint8_t *base_public_key; + Onion_Node entry; +} Onion_Client_Cmp_data; + +static int onion_client_cmp_entry(const void *a, const void *b) +{ + Onion_Client_Cmp_data cmp1, cmp2; + memcpy(&cmp1, a, sizeof(Onion_Client_Cmp_data)); + memcpy(&cmp2, b, sizeof(Onion_Client_Cmp_data)); + Onion_Node entry1 = cmp1.entry; + Onion_Node entry2 = cmp2.entry; + const uint8_t *cmp_public_key = cmp1.base_public_key; + + int t1 = onion_node_timed_out(&entry1); + int t2 = onion_node_timed_out(&entry2); + + if (t1 && t2) { + return 0; + } + + if (t1) { + return -1; + } + + if (t2) { + return 1; + } + + int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key); + + if (close == 1) { + return 1; + } + + if (close == 2) { + return -1; + } + + return 0; +} + +static void sort_onion_node_list(Onion_Node *list, unsigned int length, const uint8_t *comp_public_key) +{ + // Pass comp_public_key to qsort with each Client_data entry, so the + // comparison function can use it as the base of comparison. + VLA(Onion_Client_Cmp_data, cmp_list, length); + + for (uint32_t i = 0; i < length; i++) { + cmp_list[i].base_public_key = comp_public_key; + cmp_list[i].entry = list[i]; + } + + qsort(cmp_list, length, sizeof(Onion_Client_Cmp_data), onion_client_cmp_entry); + + for (uint32_t i = 0; i < length; i++) { + list[i] = cmp_list[i].entry; + } +} + +static int client_add_to_list(Onion_Client *onion_c, uint32_t num, const uint8_t *public_key, IP_Port ip_port, + uint8_t is_stored, const uint8_t *pingid_or_key, uint32_t path_used) +{ + if (num > onion_c->num_friends) { + return -1; + } + + Onion_Node *list_nodes = NULL; + uint8_t *reference_id = NULL; + unsigned int list_length; + + if (num == 0) { + list_nodes = onion_c->clients_announce_list; + reference_id = onion_c->c->self_public_key; + list_length = MAX_ONION_CLIENTS_ANNOUNCE; + + if (is_stored == 1 && public_key_cmp(pingid_or_key, onion_c->temp_public_key) != 0) { + is_stored = 0; + } + } else { + if (is_stored >= 2) { + return -1; + } + + if (is_stored == 1) { + onion_c->friends_list[num - 1].last_reported_announced = unix_time(); + } + + list_nodes = onion_c->friends_list[num - 1].clients_list; + reference_id = onion_c->friends_list[num - 1].real_public_key; + list_length = MAX_ONION_CLIENTS; + } + + sort_onion_node_list(list_nodes, list_length, reference_id); + + int index = -1, stored = 0; + unsigned int i; + + if (onion_node_timed_out(&list_nodes[0]) + || id_closest(reference_id, list_nodes[0].public_key, public_key) == 2) { + index = 0; + } + + for (i = 0; i < list_length; ++i) { + if (public_key_cmp(list_nodes[i].public_key, public_key) == 0) { + index = i; + stored = 1; + break; + } + } + + if (index == -1) { + return 0; + } + + memcpy(list_nodes[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + list_nodes[index].ip_port = ip_port; + + // TODO(irungentoo): remove this and find a better source of nodes to use for paths. + onion_add_path_node(onion_c, ip_port, public_key); + + if (is_stored == 1) { + memcpy(list_nodes[index].data_public_key, pingid_or_key, CRYPTO_PUBLIC_KEY_SIZE); + } else { + memcpy(list_nodes[index].ping_id, pingid_or_key, ONION_PING_ID_SIZE); + } + + list_nodes[index].is_stored = is_stored; + list_nodes[index].timestamp = unix_time(); + list_nodes[index].unsuccessful_pings = 0; + + if (!stored) { + list_nodes[index].last_pinged = 0; + list_nodes[index].added_time = unix_time(); + } + + list_nodes[index].path_used = path_used; + return 0; +} + +static int good_to_ping(Last_Pinged *last_pinged, uint8_t *last_pinged_index, const uint8_t *public_key) +{ + unsigned int i; + + for (i = 0; i < MAX_STORED_PINGED_NODES; ++i) { + if (!is_timeout(last_pinged[i].timestamp, MIN_NODE_PING_TIME)) { + if (public_key_cmp(last_pinged[i].public_key, public_key) == 0) { + return 0; + } + } + } + + memcpy(last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + last_pinged[*last_pinged_index % MAX_STORED_PINGED_NODES].timestamp = unix_time(); + ++*last_pinged_index; + return 1; +} + +static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, const Node_format *nodes, uint16_t num_nodes, + IP_Port source) +{ + if (num > onion_c->num_friends) { + return -1; + } + + if (num_nodes == 0) { + return 0; + } + + Onion_Node *list_nodes = NULL; + uint8_t *reference_id = NULL; + unsigned int list_length; + + Last_Pinged *last_pinged = NULL; + uint8_t *last_pinged_index = NULL; + + if (num == 0) { + list_nodes = onion_c->clients_announce_list; + reference_id = onion_c->c->self_public_key; + list_length = MAX_ONION_CLIENTS_ANNOUNCE; + last_pinged = onion_c->last_pinged; + last_pinged_index = &onion_c->last_pinged_index; + } else { + list_nodes = onion_c->friends_list[num - 1].clients_list; + reference_id = onion_c->friends_list[num - 1].real_public_key; + list_length = MAX_ONION_CLIENTS; + last_pinged = onion_c->friends_list[num - 1].last_pinged; + last_pinged_index = &onion_c->friends_list[num - 1].last_pinged_index; + } + + unsigned int i, j; + int lan_ips_accepted = (LAN_ip(source.ip) == 0); + + for (i = 0; i < num_nodes; ++i) { + + if (!lan_ips_accepted) { + if (LAN_ip(nodes[i].ip_port.ip) == 0) { + continue; + } + } + + if (onion_node_timed_out(&list_nodes[0]) + || id_closest(reference_id, list_nodes[0].public_key, nodes[i].public_key) == 2 + || onion_node_timed_out(&list_nodes[1]) + || id_closest(reference_id, list_nodes[1].public_key, nodes[i].public_key) == 2) { + /* check if node is already in list. */ + for (j = 0; j < list_length; ++j) { + if (public_key_cmp(list_nodes[j].public_key, nodes[i].public_key) == 0) { + break; + } + } + + if (j == list_length && good_to_ping(last_pinged, last_pinged_index, nodes[i].public_key)) { + client_send_announce_request(onion_c, num, nodes[i].ip_port, nodes[i].public_key, NULL, ~0); + } + } + } + + return 0; +} + +static int handle_announce_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length, + void *userdata) +{ + Onion_Client *onion_c = (Onion_Client *)object; + + if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) { + return 1; + } + + uint16_t len_nodes = length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE; + + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ip_port; + uint32_t path_num; + uint32_t num = check_sendback(onion_c, packet + 1, public_key, &ip_port, &path_num); + + if (num > onion_c->num_friends) { + return 1; + } + + VLA(uint8_t, plain, 1 + ONION_PING_ID_SIZE + len_nodes); + int len = -1; + + if (num == 0) { + len = decrypt_data(public_key, onion_c->c->self_secret_key, packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, + packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE, + length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain); + } else { + if (onion_c->friends_list[num - 1].status == 0) { + return 1; + } + + len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key, + packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH, + packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE, + length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain); + } + + if ((uint32_t)len != SIZEOF_VLA(plain)) { + return 1; + } + + uint32_t path_used = set_path_timeouts(onion_c, num, path_num); + + if (client_add_to_list(onion_c, num, public_key, ip_port, plain[0], plain + 1, path_used) == -1) { + return 1; + } + + if (len_nodes != 0) { + Node_format nodes[MAX_SENT_NODES]; + int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, plain + 1 + ONION_PING_ID_SIZE, len_nodes, 0); + + if (num_nodes <= 0) { + return 1; + } + + if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1) { + return 1; + } + } + + // TODO(irungentoo): LAN vs non LAN ips?, if we are connected only to LAN, are we offline? + onion_c->last_packet_recv = unix_time(); + return 0; +} + +#define DATA_IN_RESPONSE_MIN_SIZE ONION_DATA_IN_RESPONSE_MIN_SIZE + +static int handle_data_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + Onion_Client *onion_c = (Onion_Client *)object; + + if (length <= (ONION_DATA_RESPONSE_MIN_SIZE + DATA_IN_RESPONSE_MIN_SIZE)) { + return 1; + } + + if (length > MAX_DATA_REQUEST_SIZE) { + return 1; + } + + VLA(uint8_t, temp_plain, length - ONION_DATA_RESPONSE_MIN_SIZE); + int len = decrypt_data(packet + 1 + CRYPTO_NONCE_SIZE, onion_c->temp_secret_key, packet + 1, + packet + 1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE, + length - (1 + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE), temp_plain); + + if ((uint32_t)len != SIZEOF_VLA(temp_plain)) { + return 1; + } + + VLA(uint8_t, plain, SIZEOF_VLA(temp_plain) - DATA_IN_RESPONSE_MIN_SIZE); + len = decrypt_data(temp_plain, onion_c->c->self_secret_key, packet + 1, temp_plain + CRYPTO_PUBLIC_KEY_SIZE, + SIZEOF_VLA(temp_plain) - CRYPTO_PUBLIC_KEY_SIZE, plain); + + if ((uint32_t)len != SIZEOF_VLA(plain)) { + return 1; + } + + if (!onion_c->Onion_Data_Handlers[plain[0]].function) { + return 1; + } + + return onion_c->Onion_Data_Handlers[plain[0]].function(onion_c->Onion_Data_Handlers[plain[0]].object, temp_plain, plain, + SIZEOF_VLA(plain), userdata); +} + +#define DHTPK_DATA_MIN_LENGTH (1 + sizeof(uint64_t) + CRYPTO_PUBLIC_KEY_SIZE) +#define DHTPK_DATA_MAX_LENGTH (DHTPK_DATA_MIN_LENGTH + sizeof(Node_format)*MAX_SENT_NODES) +static int handle_dhtpk_announce(void *object, const uint8_t *source_pubkey, const uint8_t *data, uint16_t length, + void *userdata) +{ + Onion_Client *onion_c = (Onion_Client *)object; + + if (length < DHTPK_DATA_MIN_LENGTH) { + return 1; + } + + if (length > DHTPK_DATA_MAX_LENGTH) { + return 1; + } + + int friend_num = onion_friend_num(onion_c, source_pubkey); + + if (friend_num == -1) { + return 1; + } + + uint64_t no_replay; + memcpy(&no_replay, data + 1, sizeof(uint64_t)); + net_to_host((uint8_t *) &no_replay, sizeof(no_replay)); + + if (no_replay <= onion_c->friends_list[friend_num].last_noreplay) { + return 1; + } + + onion_c->friends_list[friend_num].last_noreplay = no_replay; + + if (onion_c->friends_list[friend_num].dht_pk_callback) { + onion_c->friends_list[friend_num].dht_pk_callback(onion_c->friends_list[friend_num].dht_pk_callback_object, + onion_c->friends_list[friend_num].dht_pk_callback_number, data + 1 + sizeof(uint64_t), userdata); + } + + onion_set_friend_DHT_pubkey(onion_c, friend_num, data + 1 + sizeof(uint64_t)); + onion_c->friends_list[friend_num].last_seen = unix_time(); + + uint16_t len_nodes = length - DHTPK_DATA_MIN_LENGTH; + + if (len_nodes != 0) { + Node_format nodes[MAX_SENT_NODES]; + int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, 0, data + 1 + sizeof(uint64_t) + CRYPTO_PUBLIC_KEY_SIZE, + len_nodes, 1); + + if (num_nodes <= 0) { + return 1; + } + + int i; + + for (i = 0; i < num_nodes; ++i) { + uint8_t family = nodes[i].ip_port.ip.family; + + if (family == TOX_AF_INET || family == TOX_AF_INET6) { + DHT_getnodes(onion_c->dht, &nodes[i].ip_port, nodes[i].public_key, onion_c->friends_list[friend_num].dht_public_key); + } else if (family == TCP_INET || family == TCP_INET6) { + if (onion_c->friends_list[friend_num].tcp_relay_node_callback) { + void *obj = onion_c->friends_list[friend_num].tcp_relay_node_callback_object; + uint32_t number = onion_c->friends_list[friend_num].tcp_relay_node_callback_number; + onion_c->friends_list[friend_num].tcp_relay_node_callback(obj, number, nodes[i].ip_port, nodes[i].public_key); + } + } + } + } + + return 0; +} + +static int handle_tcp_onion(void *object, const uint8_t *data, uint16_t length, void *userdata) +{ + if (length == 0) { + return 1; + } + + IP_Port ip_port = {{0}}; + ip_port.ip.family = TCP_FAMILY; + + if (data[0] == NET_PACKET_ANNOUNCE_RESPONSE) { + return handle_announce_response(object, ip_port, data, length, userdata); + } + + if (data[0] == NET_PACKET_ONION_DATA_RESPONSE) { + return handle_data_response(object, ip_port, data, length, userdata); + } + + return 1; +} + +/* Send data of length length to friendnum. + * This data will be received by the friend using the Onion_Data_Handlers callbacks. + * + * Even if this function succeeds, the friend might not receive any data. + * + * return the number of packets sent on success + * return -1 on failure. + */ +int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + if (length + DATA_IN_RESPONSE_MIN_SIZE > MAX_DATA_REQUEST_SIZE) { + return -1; + } + + if (length == 0) { + return -1; + } + + unsigned int i, good_nodes[MAX_ONION_CLIENTS], num_good = 0, num_nodes = 0; + Onion_Node *list_nodes = onion_c->friends_list[friend_num].clients_list; + + for (i = 0; i < MAX_ONION_CLIENTS; ++i) { + if (onion_node_timed_out(&list_nodes[i])) { + continue; + } + + ++num_nodes; + + if (list_nodes[i].is_stored) { + good_nodes[num_good] = i; + ++num_good; + } + } + + if (num_good < (num_nodes - 1) / 4 + 1) { + return -1; + } + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + VLA(uint8_t, packet, DATA_IN_RESPONSE_MIN_SIZE + length); + memcpy(packet, onion_c->c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, onion_c->c->self_secret_key, nonce, data, + length, packet + CRYPTO_PUBLIC_KEY_SIZE); + + if ((uint32_t)len + CRYPTO_PUBLIC_KEY_SIZE != SIZEOF_VLA(packet)) { + return -1; + } + + unsigned int good = 0; + + for (i = 0; i < num_good; ++i) { + Onion_Path path; + + if (random_path(onion_c, &onion_c->onion_paths_friends, ~0, &path) == -1) { + continue; + } + + uint8_t o_packet[ONION_MAX_PACKET_SIZE]; + len = create_data_request(o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key, + list_nodes[good_nodes[i]].data_public_key, nonce, packet, SIZEOF_VLA(packet)); + + if (len == -1) { + continue; + } + + if (send_onion_packet_tcp_udp(onion_c, &path, list_nodes[good_nodes[i]].ip_port, o_packet, len) == 0) { + ++good; + } + } + + return good; +} + +/* Try to send the dht public key via the DHT instead of onion + * + * Even if this function succeeds, the friend might not receive any data. + * + * return the number of packets sent on success + * return -1 on failure. + */ +static int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + if (!onion_c->friends_list[friend_num].know_dht_public_key) { + return -1; + } + + uint8_t nonce[CRYPTO_NONCE_SIZE]; + random_nonce(nonce); + + VLA(uint8_t, temp, DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE + length); + memcpy(temp, onion_c->c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + memcpy(temp + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE); + int len = encrypt_data(onion_c->friends_list[friend_num].real_public_key, onion_c->c->self_secret_key, nonce, data, + length, temp + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if ((uint32_t)len + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE != SIZEOF_VLA(temp)) { + return -1; + } + + uint8_t packet[MAX_CRYPTO_REQUEST_SIZE]; + len = create_request(onion_c->dht->self_public_key, onion_c->dht->self_secret_key, packet, + onion_c->friends_list[friend_num].dht_public_key, temp, SIZEOF_VLA(temp), CRYPTO_PACKET_DHTPK); + + if (len == -1) { + return -1; + } + + return route_tofriend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, packet, len); +} + +static int handle_dht_dhtpk(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet, + uint16_t length, void *userdata) +{ + Onion_Client *onion_c = (Onion_Client *)object; + + if (length < DHTPK_DATA_MIN_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE) { + return 1; + } + + if (length > DHTPK_DATA_MAX_LENGTH + DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE) { + return 1; + } + + uint8_t plain[DHTPK_DATA_MAX_LENGTH]; + int len = decrypt_data(packet, onion_c->c->self_secret_key, packet + CRYPTO_PUBLIC_KEY_SIZE, + packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE), plain); + + if (len != length - (DATA_IN_RESPONSE_MIN_SIZE + CRYPTO_NONCE_SIZE)) { + return 1; + } + + if (public_key_cmp(source_pubkey, plain + 1 + sizeof(uint64_t)) != 0) { + return 1; + } + + return handle_dhtpk_announce(onion_c, packet, plain, len, userdata); +} +/* Send the packets to tell our friends what our DHT public key is. + * + * if onion_dht_both is 0, use only the onion to send the packet. + * if it is 1, use only the dht. + * if it is something else, use both. + * + * return the number of packets sent on success + * return -1 on failure. + */ +static int send_dhtpk_announce(Onion_Client *onion_c, uint16_t friend_num, uint8_t onion_dht_both) +{ + if (friend_num >= onion_c->num_friends) { + return -1; + } + + uint8_t data[DHTPK_DATA_MAX_LENGTH]; + data[0] = ONION_DATA_DHTPK; + uint64_t no_replay = unix_time(); + host_to_net((uint8_t *)&no_replay, sizeof(no_replay)); + memcpy(data + 1, &no_replay, sizeof(no_replay)); + memcpy(data + 1 + sizeof(uint64_t), onion_c->dht->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + Node_format nodes[MAX_SENT_NODES]; + uint16_t num_relays = copy_connected_tcp_relays(onion_c->c, nodes, (MAX_SENT_NODES / 2)); + uint16_t num_nodes = closelist_nodes(onion_c->dht, &nodes[num_relays], MAX_SENT_NODES - num_relays); + num_nodes += num_relays; + int nodes_len = 0; + + if (num_nodes != 0) { + nodes_len = pack_nodes(data + DHTPK_DATA_MIN_LENGTH, DHTPK_DATA_MAX_LENGTH - DHTPK_DATA_MIN_LENGTH, nodes, + num_nodes); + + if (nodes_len <= 0) { + return -1; + } + } + + int num1 = -1, num2 = -1; + + if (onion_dht_both != 1) { + num1 = send_onion_data(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len); + } + + if (onion_dht_both != 0) { + num2 = send_dht_dhtpk(onion_c, friend_num, data, DHTPK_DATA_MIN_LENGTH + nodes_len); + } + + if (num1 == -1) { + return num2; + } + + if (num2 == -1) { + return num1; + } + + return num1 + num2; +} + +/* Get the friend_num of a friend. + * + * return -1 on failure. + * return friend number on success. + */ +int onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key) +{ + unsigned int i; + + for (i = 0; i < onion_c->num_friends; ++i) { + if (onion_c->friends_list[i].status == 0) { + continue; + } + + if (public_key_cmp(public_key, onion_c->friends_list[i].real_public_key) == 0) { + return i; + } + } + + return -1; +} + +/* Set the size of the friend list to num. + * + * return -1 if realloc fails. + * return 0 if it succeeds. + */ +static int realloc_onion_friends(Onion_Client *onion_c, uint32_t num) +{ + if (num == 0) { + free(onion_c->friends_list); + onion_c->friends_list = NULL; + return 0; + } + + Onion_Friend *newonion_friends = (Onion_Friend *)realloc(onion_c->friends_list, num * sizeof(Onion_Friend)); + + if (newonion_friends == NULL) { + return -1; + } + + onion_c->friends_list = newonion_friends; + return 0; +} + +/* Add a friend who we want to connect to. + * + * return -1 on failure. + * return the friend number on success or if the friend was already added. + */ +int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key) +{ + int num = onion_friend_num(onion_c, public_key); + + if (num != -1) { + return num; + } + + unsigned int i, index = ~0; + + for (i = 0; i < onion_c->num_friends; ++i) { + if (onion_c->friends_list[i].status == 0) { + index = i; + break; + } + } + + if (index == (uint32_t)~0) { + if (realloc_onion_friends(onion_c, onion_c->num_friends + 1) == -1) { + return -1; + } + + index = onion_c->num_friends; + memset(&(onion_c->friends_list[onion_c->num_friends]), 0, sizeof(Onion_Friend)); + ++onion_c->num_friends; + } + + onion_c->friends_list[index].status = 1; + memcpy(onion_c->friends_list[index].real_public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + crypto_new_keypair(onion_c->friends_list[index].temp_public_key, onion_c->friends_list[index].temp_secret_key); + return index; +} + +/* Delete a friend. + * + * return -1 on failure. + * return the deleted friend number on success. + */ +int onion_delfriend(Onion_Client *onion_c, int friend_num) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + //if (onion_c->friends_list[friend_num].know_dht_public_key) + // DHT_delfriend(onion_c->dht, onion_c->friends_list[friend_num].dht_public_key, 0); + + crypto_memzero(&(onion_c->friends_list[friend_num]), sizeof(Onion_Friend)); + unsigned int i; + + for (i = onion_c->num_friends; i != 0; --i) { + if (onion_c->friends_list[i - 1].status != 0) { + break; + } + } + + if (onion_c->num_friends != i) { + onion_c->num_friends = i; + realloc_onion_friends(onion_c, onion_c->num_friends); + } + + return friend_num; +} + +/* Set the function for this friend that will be callbacked with object and number + * when that friends gives us one of the TCP relays he is connected to. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, + uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + onion_c->friends_list[friend_num].tcp_relay_node_callback = tcp_relay_node_callback; + onion_c->friends_list[friend_num].tcp_relay_node_callback_object = object; + onion_c->friends_list[friend_num].tcp_relay_node_callback_number = number; + return 0; +} + +/* Set the function for this friend that will be callbacked with object and number + * when that friend gives us his DHT temporary public key. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number, + const uint8_t *dht_public_key, void *userdata), void *object, uint32_t number) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + onion_c->friends_list[friend_num].dht_pk_callback = function; + onion_c->friends_list[friend_num].dht_pk_callback_object = object; + onion_c->friends_list[friend_num].dht_pk_callback_number = number; + return 0; +} + +/* Set a friends DHT public key. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + if (onion_c->friends_list[friend_num].status == 0) { + return -1; + } + + if (onion_c->friends_list[friend_num].know_dht_public_key) { + if (public_key_cmp(dht_key, onion_c->friends_list[friend_num].dht_public_key) == 0) { + return -1; + } + + onion_c->friends_list[friend_num].know_dht_public_key = 0; + } + + onion_c->friends_list[friend_num].last_seen = unix_time(); + onion_c->friends_list[friend_num].know_dht_public_key = 1; + memcpy(onion_c->friends_list[friend_num].dht_public_key, dht_key, CRYPTO_PUBLIC_KEY_SIZE); + + return 0; +} + +/* Copy friends DHT public key into dht_key. + * + * return 0 on failure (no key copied). + * return 1 on success (key copied). + */ +unsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return 0; + } + + if (onion_c->friends_list[friend_num].status == 0) { + return 0; + } + + if (!onion_c->friends_list[friend_num].know_dht_public_key) { + return 0; + } + + memcpy(dht_key, onion_c->friends_list[friend_num].dht_public_key, CRYPTO_PUBLIC_KEY_SIZE); + return 1; +} + +/* Get the ip of friend friendnum and put it in ip_port + * + * return -1, -- if public_key does NOT refer to a friend + * return 0, -- if public_key refers to a friend and we failed to find the friend (yet) + * return 1, ip if public_key refers to a friend and we found him + * + */ +int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port) +{ + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + + if (onion_getfriend_DHT_pubkey(onion_c, friend_num, dht_public_key) == 0) { + return -1; + } + + return DHT_getfriendip(onion_c->dht, dht_public_key, ip_port); +} + + +/* Set if friend is online or not. + * NOTE: This function is there and should be used so that we don't send useless packets to the friend if he is online. + * + * is_online 1 means friend is online. + * is_online 0 means friend is offline + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_online) +{ + if ((uint32_t)friend_num >= onion_c->num_friends) { + return -1; + } + + if (is_online == 0 && onion_c->friends_list[friend_num].is_online == 1) { + onion_c->friends_list[friend_num].last_seen = unix_time(); + } + + onion_c->friends_list[friend_num].is_online = is_online; + + /* This should prevent some clock related issues */ + if (!is_online) { + onion_c->friends_list[friend_num].last_noreplay = 0; + onion_c->friends_list[friend_num].run_count = 0; + } + + return 0; +} + +static void populate_path_nodes(Onion_Client *onion_c) +{ + Node_format nodes_list[MAX_FRIEND_CLIENTS]; + + unsigned int num_nodes = randfriends_nodes(onion_c->dht, nodes_list, MAX_FRIEND_CLIENTS); + + unsigned int i; + + for (i = 0; i < num_nodes; ++i) { + onion_add_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key); + } +} + +static void populate_path_nodes_tcp(Onion_Client *onion_c) +{ + Node_format nodes_list[MAX_SENT_NODES]; + + unsigned int num_nodes = copy_connected_tcp_relays(onion_c->c, nodes_list, MAX_SENT_NODES);; + unsigned int i; + + for (i = 0; i < num_nodes; ++i) { + onion_add_bs_path_node(onion_c, nodes_list[i].ip_port, nodes_list[i].public_key); + } +} + +#define ANNOUNCE_FRIEND (ONION_NODE_PING_INTERVAL * 6) +#define ANNOUNCE_FRIEND_BEGINNING 3 + +#define RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING 17 + +#define ONION_FRIEND_BACKOFF_FACTOR 4 +#define ONION_FRIEND_MAX_PING_INTERVAL (5*60*MAX_ONION_CLIENTS) + +static void do_friend(Onion_Client *onion_c, uint16_t friendnum) +{ + if (friendnum >= onion_c->num_friends) { + return; + } + + if (onion_c->friends_list[friendnum].status == 0) { + return; + } + + unsigned int interval = ANNOUNCE_FRIEND; + + if (onion_c->friends_list[friendnum].run_count < RUN_COUNT_FRIEND_ANNOUNCE_BEGINNING) { + interval = ANNOUNCE_FRIEND_BEGINNING; + } else { + if (onion_c->friends_list[friendnum].last_reported_announced == 0) { + onion_c->friends_list[friendnum].last_reported_announced = unix_time(); + } + + uint64_t backoff_interval = (unix_time() - onion_c->friends_list[friendnum].last_reported_announced) + / ONION_FRIEND_BACKOFF_FACTOR; + + if (backoff_interval > ONION_FRIEND_MAX_PING_INTERVAL) { + backoff_interval = ONION_FRIEND_MAX_PING_INTERVAL; + } + + if (interval < backoff_interval) { + interval = backoff_interval; + } + } + + unsigned int i, count = 0; + Onion_Node *list_nodes = onion_c->friends_list[friendnum].clients_list; + + if (!onion_c->friends_list[friendnum].is_online) { + // ensure we get a response from some node roughly once per + // (interval / MAX_ONION_CLIENTS) + bool ping_random = true; + + for (i = 0; i < MAX_ONION_CLIENTS; ++i) { + if (!(is_timeout(list_nodes[i].timestamp, interval / MAX_ONION_CLIENTS) + && is_timeout(list_nodes[i].last_pinged, ONION_NODE_PING_INTERVAL))) { + ping_random = false; + break; + } + } + + for (i = 0; i < MAX_ONION_CLIENTS; ++i) { + if (onion_node_timed_out(&list_nodes[i])) { + continue; + } + + ++count; + + + if (list_nodes[i].last_pinged == 0) { + list_nodes[i].last_pinged = unix_time(); + continue; + } + + if (list_nodes[i].unsuccessful_pings >= ONION_NODE_MAX_PINGS) { + continue; + } + + if (is_timeout(list_nodes[i].last_pinged, interval) + || (ping_random && rand() % (MAX_ONION_CLIENTS - i) == 0)) { + if (client_send_announce_request(onion_c, friendnum + 1, list_nodes[i].ip_port, list_nodes[i].public_key, 0, ~0) == 0) { + list_nodes[i].last_pinged = unix_time(); + ++list_nodes[i].unsuccessful_pings; + ping_random = false; + } + } + } + + if (count != MAX_ONION_CLIENTS) { + unsigned int num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; + + unsigned int n = num_nodes; + + if (num_nodes > (MAX_ONION_CLIENTS / 2)) { + n = (MAX_ONION_CLIENTS / 2); + } + + if (count <= (uint32_t)rand() % MAX_ONION_CLIENTS) { + if (num_nodes != 0) { + unsigned int j; + + for (j = 0; j < n; ++j) { + unsigned int num = rand() % num_nodes; + client_send_announce_request(onion_c, friendnum + 1, onion_c->path_nodes[num].ip_port, + onion_c->path_nodes[num].public_key, 0, ~0); + } + + ++onion_c->friends_list[friendnum].run_count; + } + } + } else { + ++onion_c->friends_list[friendnum].run_count; + } + + /* send packets to friend telling them our DHT public key. */ + if (is_timeout(onion_c->friends_list[friendnum].last_dht_pk_onion_sent, ONION_DHTPK_SEND_INTERVAL)) { + if (send_dhtpk_announce(onion_c, friendnum, 0) >= 1) { + onion_c->friends_list[friendnum].last_dht_pk_onion_sent = unix_time(); + } + } + + if (is_timeout(onion_c->friends_list[friendnum].last_dht_pk_dht_sent, DHT_DHTPK_SEND_INTERVAL)) { + if (send_dhtpk_announce(onion_c, friendnum, 1) >= 1) { + onion_c->friends_list[friendnum].last_dht_pk_dht_sent = unix_time(); + } + } + } +} + + +/* Function to call when onion data packet with contents beginning with byte is received. */ +void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object) +{ + onion_c->Onion_Data_Handlers[byte].function = cb; + onion_c->Onion_Data_Handlers[byte].object = object; +} + +#define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 3 +#define ANNOUNCE_INTERVAL_ANNOUNCED ONION_NODE_PING_INTERVAL + +#define TIME_TO_STABLE (ONION_NODE_PING_INTERVAL * 6) +#define ANNOUNCE_INTERVAL_STABLE (ONION_NODE_PING_INTERVAL * 8) + +static void do_announce(Onion_Client *onion_c) +{ + unsigned int i, count = 0; + Onion_Node *list_nodes = onion_c->clients_announce_list; + + for (i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE; ++i) { + if (onion_node_timed_out(&list_nodes[i])) { + continue; + } + + ++count; + + /* Don't announce ourselves the first time this is run to new peers */ + if (list_nodes[i].last_pinged == 0) { + list_nodes[i].last_pinged = 1; + continue; + } + + if (list_nodes[i].unsuccessful_pings >= ONION_NODE_MAX_PINGS) { + continue; + } + + + unsigned int interval = ANNOUNCE_INTERVAL_NOT_ANNOUNCED; + + if (list_nodes[i].is_stored && path_exists(&onion_c->onion_paths_self, list_nodes[i].path_used)) { + interval = ANNOUNCE_INTERVAL_ANNOUNCED; + + uint32_t pathnum = list_nodes[i].path_used % NUMBER_ONION_PATHS; + + /* A node/path is considered 'stable', and can be pinged less + * aggressively, if it has survived for at least TIME_TO_STABLE + * and the latest packets sent to it are not timing out. + */ + if (is_timeout(list_nodes[i].added_time, TIME_TO_STABLE) + && !(list_nodes[i].unsuccessful_pings > 0 + && is_timeout(list_nodes[i].last_pinged, ONION_NODE_TIMEOUT)) + && is_timeout(onion_c->onion_paths_self.path_creation_time[pathnum], TIME_TO_STABLE) + && !(onion_c->onion_paths_self.last_path_used_times[pathnum] > 0 + && is_timeout(onion_c->onion_paths_self.last_path_used[pathnum], ONION_PATH_TIMEOUT))) { + interval = ANNOUNCE_INTERVAL_STABLE; + } + } + + if (is_timeout(list_nodes[i].last_pinged, interval) + || (is_timeout(onion_c->last_announce, ONION_NODE_PING_INTERVAL) + && rand() % (MAX_ONION_CLIENTS_ANNOUNCE - i) == 0)) { + uint32_t path_to_use = list_nodes[i].path_used; + + if (list_nodes[i].unsuccessful_pings == ONION_NODE_MAX_PINGS - 1 + && is_timeout(list_nodes[i].added_time, TIME_TO_STABLE)) { + /* Last chance for a long-lived node - try a random path */ + path_to_use = ~0; + } + + if (client_send_announce_request(onion_c, 0, list_nodes[i].ip_port, list_nodes[i].public_key, + list_nodes[i].ping_id, path_to_use) == 0) { + list_nodes[i].last_pinged = unix_time(); + ++list_nodes[i].unsuccessful_pings; + onion_c->last_announce = unix_time(); + } + } + } + + if (count != MAX_ONION_CLIENTS_ANNOUNCE) { + unsigned int num_nodes; + Node_format *path_nodes; + + if (rand() % 2 == 0 || onion_c->path_nodes_index == 0) { + num_nodes = (onion_c->path_nodes_index_bs < MAX_PATH_NODES) ? onion_c->path_nodes_index_bs : MAX_PATH_NODES; + path_nodes = onion_c->path_nodes_bs; + } else { + num_nodes = (onion_c->path_nodes_index < MAX_PATH_NODES) ? onion_c->path_nodes_index : MAX_PATH_NODES; + path_nodes = onion_c->path_nodes; + } + + if (count <= (uint32_t)rand() % MAX_ONION_CLIENTS_ANNOUNCE) { + if (num_nodes != 0) { + for (i = 0; i < (MAX_ONION_CLIENTS_ANNOUNCE / 2); ++i) { + unsigned int num = rand() % num_nodes; + client_send_announce_request(onion_c, 0, path_nodes[num].ip_port, path_nodes[num].public_key, 0, ~0); + } + } + } + } +} + +/* return 0 if we are not connected to the network. + * return 1 if we are. + */ +static int onion_isconnected(const Onion_Client *onion_c) +{ + unsigned int i, num = 0, announced = 0; + + if (is_timeout(onion_c->last_packet_recv, ONION_OFFLINE_TIMEOUT)) { + return 0; + } + + if (onion_c->path_nodes_index == 0) { + return 0; + } + + for (i = 0; i < MAX_ONION_CLIENTS_ANNOUNCE; ++i) { + if (!onion_node_timed_out(&onion_c->clients_announce_list[i])) { + ++num; + + if (onion_c->clients_announce_list[i].is_stored) { + ++announced; + } + } + } + + unsigned int pnodes = onion_c->path_nodes_index; + + if (pnodes > MAX_ONION_CLIENTS_ANNOUNCE) { + pnodes = MAX_ONION_CLIENTS_ANNOUNCE; + } + + /* Consider ourselves online if we are announced to half or more nodes + we are connected to */ + if (num && announced) { + if ((num / 2) <= announced && (pnodes / 2) <= num) { + return 1; + } + } + + return 0; +} + +#define ONION_CONNECTION_SECONDS 3 + +/* return 0 if we are not connected to the network. + * return 1 if we are connected with TCP only. + * return 2 if we are also connected with UDP. + */ +unsigned int onion_connection_status(const Onion_Client *onion_c) +{ + if (onion_c->onion_connected >= ONION_CONNECTION_SECONDS) { + if (onion_c->UDP_connected) { + return 2; + } + + return 1; + } + + return 0; +} + +void do_onion_client(Onion_Client *onion_c) +{ + unsigned int i; + + if (onion_c->last_run == unix_time()) { + return; + } + + if (is_timeout(onion_c->first_run, ONION_CONNECTION_SECONDS)) { + populate_path_nodes(onion_c); + do_announce(onion_c); + } + + if (onion_isconnected(onion_c)) { + if (onion_c->onion_connected < ONION_CONNECTION_SECONDS * 2) { + ++onion_c->onion_connected; + } + } else { + populate_path_nodes_tcp(onion_c); + + if (onion_c->onion_connected != 0) { + --onion_c->onion_connected; + } + } + + bool UDP_connected = DHT_non_lan_connected(onion_c->dht); + + if (is_timeout(onion_c->first_run, ONION_CONNECTION_SECONDS * 2)) { + set_tcp_onion_status(onion_c->c->tcp_c, !UDP_connected); + } + + onion_c->UDP_connected = UDP_connected + || get_random_tcp_onion_conn_number(onion_c->c->tcp_c) == -1; /* Check if connected to any TCP relays. */ + + if (onion_connection_status(onion_c)) { + for (i = 0; i < onion_c->num_friends; ++i) { + do_friend(onion_c, i); + } + } + + if (onion_c->last_run == 0) { + onion_c->first_run = unix_time(); + } + + onion_c->last_run = unix_time(); +} + +Onion_Client *new_onion_client(Net_Crypto *c) +{ + if (c == NULL) { + return NULL; + } + + Onion_Client *onion_c = (Onion_Client *)calloc(1, sizeof(Onion_Client)); + + if (onion_c == NULL) { + return NULL; + } + + if (ping_array_init(&onion_c->announce_ping_array, ANNOUNCE_ARRAY_SIZE, ANNOUNCE_TIMEOUT) != 0) { + free(onion_c); + return NULL; + } + + onion_c->dht = c->dht; + onion_c->net = c->dht->net; + onion_c->c = c; + new_symmetric_key(onion_c->secret_symmetric_key); + crypto_new_keypair(onion_c->temp_public_key, onion_c->temp_secret_key); + networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c); + networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c); + oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, &handle_dhtpk_announce, onion_c); + cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, &handle_dht_dhtpk, onion_c); + set_onion_packet_tcp_connection_callback(onion_c->c->tcp_c, &handle_tcp_onion, onion_c); + + return onion_c; +} + +void kill_onion_client(Onion_Client *onion_c) +{ + if (onion_c == NULL) { + return; + } + + ping_array_free_all(&onion_c->announce_ping_array); + realloc_onion_friends(onion_c, 0); + networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, NULL, NULL); + networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, NULL, NULL); + oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, NULL, NULL); + cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, NULL, NULL); + set_onion_packet_tcp_connection_callback(onion_c->c->tcp_c, NULL, NULL); + crypto_memzero(onion_c, sizeof(Onion_Client)); + free(onion_c); +} + diff --git a/libs/libtox/src/toxcore/onion_client.h b/libs/libtox/src/toxcore/onion_client.h new file mode 100644 index 0000000000..216dbec050 --- /dev/null +++ b/libs/libtox/src/toxcore/onion_client.h @@ -0,0 +1,302 @@ +/* + * Implementation of the client part of docs/Prevent_Tracking.txt (The part that + * uses the onion stuff to connect to the friend) + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef ONION_CLIENT_H +#define ONION_CLIENT_H + +#include "net_crypto.h" +#include "onion_announce.h" +#include "ping_array.h" + +#define MAX_ONION_CLIENTS 8 +#define MAX_ONION_CLIENTS_ANNOUNCE 12 /* Number of nodes to announce ourselves to. */ +#define ONION_NODE_PING_INTERVAL 15 +#define ONION_NODE_TIMEOUT ONION_NODE_PING_INTERVAL + +/* The interval in seconds at which to tell our friends where we are */ +#define ONION_DHTPK_SEND_INTERVAL 30 +#define DHT_DHTPK_SEND_INTERVAL 20 + +#define NUMBER_ONION_PATHS 6 + +/* The timeout the first time the path is added and + then for all the next consecutive times */ +#define ONION_PATH_FIRST_TIMEOUT 4 +#define ONION_PATH_TIMEOUT 10 +#define ONION_PATH_MAX_LIFETIME 1200 +#define ONION_PATH_MAX_NO_RESPONSE_USES 4 + +#define MAX_STORED_PINGED_NODES 9 +#define MIN_NODE_PING_TIME 10 + +#define ONION_NODE_MAX_PINGS 3 + +#define MAX_PATH_NODES 32 + +/* If no announce response packets are received within this interval tox will + * be considered offline. We give time for a node to be pinged often enough + * that it times out, which leads to the network being thoroughly tested as it + * is replaced. + */ +#define ONION_OFFLINE_TIMEOUT (ONION_NODE_PING_INTERVAL * (ONION_NODE_MAX_PINGS+2)) + +/* Onion data packet ids. */ +#define ONION_DATA_FRIEND_REQ CRYPTO_PACKET_FRIEND_REQ +#define ONION_DATA_DHTPK CRYPTO_PACKET_DHTPK + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + IP_Port ip_port; + uint8_t ping_id[ONION_PING_ID_SIZE]; + uint8_t data_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t is_stored; + + uint64_t added_time; + + uint64_t timestamp; + + uint64_t last_pinged; + + uint8_t unsuccessful_pings; + + uint32_t path_used; +} Onion_Node; + +typedef struct { + Onion_Path paths[NUMBER_ONION_PATHS]; + uint64_t last_path_success[NUMBER_ONION_PATHS]; + uint64_t last_path_used[NUMBER_ONION_PATHS]; + uint64_t path_creation_time[NUMBER_ONION_PATHS]; + /* number of times used without success. */ + unsigned int last_path_used_times[NUMBER_ONION_PATHS]; +} Onion_Client_Paths; + +typedef struct { + uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint64_t timestamp; +} Last_Pinged; + +typedef struct { + uint8_t status; /* 0 if friend is not valid, 1 if friend is valid.*/ + uint8_t is_online; /* Set by the onion_set_friend_status function. */ + + uint8_t know_dht_public_key; /* 0 if we don't know the dht public key of the other, 1 if we do. */ + uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t real_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + + Onion_Node clients_list[MAX_ONION_CLIENTS]; + uint8_t temp_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + uint64_t last_reported_announced; + + uint64_t last_dht_pk_onion_sent; + uint64_t last_dht_pk_dht_sent; + + uint64_t last_noreplay; + + uint64_t last_seen; + + Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; + uint8_t last_pinged_index; + + int (*tcp_relay_node_callback)(void *object, uint32_t number, IP_Port ip_port, const uint8_t *public_key); + void *tcp_relay_node_callback_object; + uint32_t tcp_relay_node_callback_number; + + void (*dht_pk_callback)(void *data, int32_t number, const uint8_t *dht_public_key, void *userdata); + void *dht_pk_callback_object; + uint32_t dht_pk_callback_number; + + uint32_t run_count; +} Onion_Friend; + +typedef int (*oniondata_handler_callback)(void *object, const uint8_t *source_pubkey, const uint8_t *data, + uint16_t len, void *userdata); + +typedef struct { + DHT *dht; + Net_Crypto *c; + Networking_Core *net; + Onion_Friend *friends_list; + uint16_t num_friends; + + Onion_Node clients_announce_list[MAX_ONION_CLIENTS_ANNOUNCE]; + uint64_t last_announce; + + Onion_Client_Paths onion_paths_self; + Onion_Client_Paths onion_paths_friends; + + uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + uint64_t last_run, first_run; + + uint8_t temp_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; + + Last_Pinged last_pinged[MAX_STORED_PINGED_NODES]; + + Node_format path_nodes[MAX_PATH_NODES]; + uint16_t path_nodes_index; + + Node_format path_nodes_bs[MAX_PATH_NODES]; + uint16_t path_nodes_index_bs; + + Ping_Array announce_ping_array; + uint8_t last_pinged_index; + struct { + oniondata_handler_callback function; + void *object; + } Onion_Data_Handlers[256]; + + uint64_t last_packet_recv; + + unsigned int onion_connected; + bool UDP_connected; +} Onion_Client; + + +/* Add a node to the path_nodes bootstrap array. + * + * return -1 on failure + * return 0 on success + */ +int onion_add_bs_path_node(Onion_Client *onion_c, IP_Port ip_port, const uint8_t *public_key); + +/* Put up to max_num nodes in nodes. + * + * return the number of nodes. + */ +uint16_t onion_backup_nodes(const Onion_Client *onion_c, Node_format *nodes, uint16_t max_num); + +/* Add a friend who we want to connect to. + * + * return -1 on failure. + * return the friend number on success or if the friend was already added. + */ +int onion_friend_num(const Onion_Client *onion_c, const uint8_t *public_key); + +/* Add a friend who we want to connect to. + * + * return -1 on failure. + * return the friend number on success. + */ +int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key); + +/* Delete a friend. + * + * return -1 on failure. + * return the deleted friend number on success. + */ +int onion_delfriend(Onion_Client *onion_c, int friend_num); + +/* Set if friend is online or not. + * NOTE: This function is there and should be used so that we don't send useless packets to the friend if he is online. + * + * is_online 1 means friend is online. + * is_online 0 means friend is offline + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_online(Onion_Client *onion_c, int friend_num, uint8_t is_online); + +/* Get the ip of friend friendnum and put it in ip_port + * + * return -1, -- if public_key does NOT refer to a friend + * return 0, -- if public_key refers to a friend and we failed to find the friend (yet) + * return 1, ip if public_key refers to a friend and we found him + * + */ +int onion_getfriendip(const Onion_Client *onion_c, int friend_num, IP_Port *ip_port); + +/* Set the function for this friend that will be callbacked with object and number + * when that friends gives us one of the TCP relays he is connected to. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int recv_tcp_relay_handler(Onion_Client *onion_c, int friend_num, int (*tcp_relay_node_callback)(void *object, + uint32_t number, IP_Port ip_port, const uint8_t *public_key), void *object, uint32_t number); + + +/* Set the function for this friend that will be callbacked with object and number + * when that friend gives us his DHT temporary public key. + * + * object and number will be passed as argument to this function. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_dht_pk_callback(Onion_Client *onion_c, int friend_num, void (*function)(void *data, int32_t number, + const uint8_t *dht_public_key, void *userdata), void *object, uint32_t number); + +/* Set a friends DHT public key. + * timestamp is the time (current_time_monotonic()) at which the key was last confirmed belonging to + * the other peer. + * + * return -1 on failure. + * return 0 on success. + */ +int onion_set_friend_DHT_pubkey(Onion_Client *onion_c, int friend_num, const uint8_t *dht_key); + +/* Copy friends DHT public key into dht_key. + * + * return 0 on failure (no key copied). + * return 1 on success (key copied). + */ +unsigned int onion_getfriend_DHT_pubkey(const Onion_Client *onion_c, int friend_num, uint8_t *dht_key); + +#define ONION_DATA_IN_RESPONSE_MIN_SIZE (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_MAC_SIZE) +#define ONION_CLIENT_MAX_DATA_SIZE (MAX_DATA_REQUEST_SIZE - ONION_DATA_IN_RESPONSE_MIN_SIZE) + +/* Send data of length length to friendnum. + * Maximum length of data is ONION_CLIENT_MAX_DATA_SIZE. + * This data will be received by the friend using the Onion_Data_Handlers callbacks. + * + * Even if this function succeeds, the friend might not receive any data. + * + * return the number of packets sent on success + * return -1 on failure. + */ +int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data, uint16_t length); + +/* Function to call when onion data packet with contents beginning with byte is received. */ +void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_handler_callback cb, void *object); + +void do_onion_client(Onion_Client *onion_c); + +Onion_Client *new_onion_client(Net_Crypto *c); + +void kill_onion_client(Onion_Client *onion_c); + + +/* return 0 if we are not connected to the network. + * return 1 if we are connected with TCP only. + * return 2 if we are also connected with UDP. + */ +unsigned int onion_connection_status(const Onion_Client *onion_c); + +#endif diff --git a/libs/libtox/src/toxcore/ping.c b/libs/libtox/src/toxcore/ping.c new file mode 100644 index 0000000000..72b3fe6259 --- /dev/null +++ b/libs/libtox/src/toxcore/ping.c @@ -0,0 +1,381 @@ +/* + * Buffered pinging using cyclic arrays. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * Copyright © 2013 plutooo + * + * This file is part of Tox, the free peer to peer instant messenger. + * This file is donated to the Tox Project. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ping.h" + +#include "DHT.h" +#include "network.h" +#include "ping_array.h" +#include "util.h" + +#include + +#define PING_NUM_MAX 512 + +/* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */ +#define MAX_TO_PING 32 + +/* Ping newly announced nodes to ping per TIME_TO_PING seconds*/ +#define TIME_TO_PING 2 + + +struct PING { + DHT *dht; + + Ping_Array ping_array; + Node_format to_ping[MAX_TO_PING]; + uint64_t last_to_ping; +}; + + +#define PING_PLAIN_SIZE (1 + sizeof(uint64_t)) +#define DHT_PING_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) +#define PING_DATA_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(IP_Port)) + +int send_ping_request(PING *ping, IP_Port ipp, const uint8_t *public_key) +{ + uint8_t pk[DHT_PING_SIZE]; + int rc; + uint64_t ping_id; + + if (id_equal(public_key, ping->dht->self_public_key)) { + return 1; + } + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + + // generate key to encrypt ping_id with recipient privkey + DHT_get_shared_key_sent(ping->dht, shared_key, public_key); + // Generate random ping_id. + uint8_t data[PING_DATA_SIZE]; + id_copy(data, public_key); + memcpy(data + CRYPTO_PUBLIC_KEY_SIZE, &ipp, sizeof(IP_Port)); + ping_id = ping_array_add(&ping->ping_array, data, sizeof(data)); + + if (ping_id == 0) { + return 1; + } + + uint8_t ping_plain[PING_PLAIN_SIZE]; + ping_plain[0] = NET_PACKET_PING_REQUEST; + memcpy(ping_plain + 1, &ping_id, sizeof(ping_id)); + + pk[0] = NET_PACKET_PING_REQUEST; + id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey + random_nonce(pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce + + + rc = encrypt_data_symmetric(shared_key, + pk + 1 + CRYPTO_PUBLIC_KEY_SIZE, + ping_plain, sizeof(ping_plain), + pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) { + return 1; + } + + return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); +} + +static int send_ping_response(PING *ping, IP_Port ipp, const uint8_t *public_key, uint64_t ping_id, + uint8_t *shared_encryption_key) +{ + uint8_t pk[DHT_PING_SIZE]; + int rc; + + if (id_equal(public_key, ping->dht->self_public_key)) { + return 1; + } + + uint8_t ping_plain[PING_PLAIN_SIZE]; + ping_plain[0] = NET_PACKET_PING_RESPONSE; + memcpy(ping_plain + 1, &ping_id, sizeof(ping_id)); + + pk[0] = NET_PACKET_PING_RESPONSE; + id_copy(pk + 1, ping->dht->self_public_key); // Our pubkey + random_nonce(pk + 1 + CRYPTO_PUBLIC_KEY_SIZE); // Generate new nonce + + // Encrypt ping_id using recipient privkey + rc = encrypt_data_symmetric(shared_encryption_key, + pk + 1 + CRYPTO_PUBLIC_KEY_SIZE, + ping_plain, sizeof(ping_plain), + pk + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); + + if (rc != PING_PLAIN_SIZE + CRYPTO_MAC_SIZE) { + return 1; + } + + return sendpacket(ping->dht->net, ipp, pk, sizeof(pk)); +} + +static int handle_ping_request(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + int rc; + + if (length != DHT_PING_SIZE) { + return 1; + } + + PING *ping = dht->ping; + + if (id_equal(packet + 1, ping->dht->self_public_key)) { + return 1; + } + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + + uint8_t ping_plain[PING_PLAIN_SIZE]; + // Decrypt ping_id + DHT_get_shared_key_recv(dht, shared_key, packet + 1); + rc = decrypt_data_symmetric(shared_key, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + PING_PLAIN_SIZE + CRYPTO_MAC_SIZE, + ping_plain); + + if (rc != sizeof(ping_plain)) { + return 1; + } + + if (ping_plain[0] != NET_PACKET_PING_REQUEST) { + return 1; + } + + uint64_t ping_id; + memcpy(&ping_id, ping_plain + 1, sizeof(ping_id)); + // Send response + send_ping_response(ping, source, packet + 1, ping_id, shared_key); + add_to_ping(ping, packet + 1, source); + + return 0; +} + +static int handle_ping_response(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata) +{ + DHT *dht = (DHT *)object; + int rc; + + if (length != DHT_PING_SIZE) { + return 1; + } + + PING *ping = dht->ping; + + if (id_equal(packet + 1, ping->dht->self_public_key)) { + return 1; + } + + uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; + + // generate key to encrypt ping_id with recipient privkey + DHT_get_shared_key_sent(ping->dht, shared_key, packet + 1); + + uint8_t ping_plain[PING_PLAIN_SIZE]; + // Decrypt ping_id + rc = decrypt_data_symmetric(shared_key, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, + packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, + PING_PLAIN_SIZE + CRYPTO_MAC_SIZE, + ping_plain); + + if (rc != sizeof(ping_plain)) { + return 1; + } + + if (ping_plain[0] != NET_PACKET_PING_RESPONSE) { + return 1; + } + + uint64_t ping_id; + memcpy(&ping_id, ping_plain + 1, sizeof(ping_id)); + uint8_t data[PING_DATA_SIZE]; + + if (ping_array_check(data, sizeof(data), &ping->ping_array, ping_id) != sizeof(data)) { + return 1; + } + + if (!id_equal(packet + 1, data)) { + return 1; + } + + IP_Port ipp; + memcpy(&ipp, data + CRYPTO_PUBLIC_KEY_SIZE, sizeof(IP_Port)); + + if (!ipport_equal(&ipp, &source)) { + return 1; + } + + addto_lists(dht, source, packet + 1); + return 0; +} + +/* Check if public_key with ip_port is in the list. + * + * return 1 if it is. + * return 0 if it isn't. + */ +static int in_list(const Client_data *list, uint16_t length, const uint8_t *public_key, IP_Port ip_port) +{ + unsigned int i; + + for (i = 0; i < length; ++i) { + if (id_equal(list[i].public_key, public_key)) { + const IPPTsPng *ipptp; + + if (ip_port.ip.family == TOX_AF_INET) { + ipptp = &list[i].assoc4; + } else { + ipptp = &list[i].assoc6; + } + + if (!is_timeout(ipptp->timestamp, BAD_NODE_TIMEOUT) && ipport_equal(&ipptp->ip_port, &ip_port)) { + return 1; + } + } + } + + return 0; +} + +/* Add nodes to the to_ping list. + * All nodes in this list are pinged every TIME_TO_PING seconds + * and are then removed from the list. + * If the list is full the nodes farthest from our public_key are replaced. + * The purpose of this list is to enable quick integration of new nodes into the + * network while preventing amplification attacks. + * + * return 0 if node was added. + * return -1 if node was not added. + */ +int add_to_ping(PING *ping, const uint8_t *public_key, IP_Port ip_port) +{ + if (!ip_isset(&ip_port.ip)) { + return -1; + } + + if (!node_addable_to_close_list(ping->dht, public_key, ip_port)) { + return -1; + } + + if (in_list(ping->dht->close_clientlist, LCLIENT_LIST, public_key, ip_port)) { + return -1; + } + + IP_Port temp; + + if (DHT_getfriendip(ping->dht, public_key, &temp) == 0) { + send_ping_request(ping, ip_port, public_key); + return -1; + } + + unsigned int i; + + for (i = 0; i < MAX_TO_PING; ++i) { + if (!ip_isset(&ping->to_ping[i].ip_port.ip)) { + memcpy(ping->to_ping[i].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); + ipport_copy(&ping->to_ping[i].ip_port, &ip_port); + return 0; + } + + if (public_key_cmp(ping->to_ping[i].public_key, public_key) == 0) { + return -1; + } + } + + if (add_to_list(ping->to_ping, MAX_TO_PING, public_key, ip_port, ping->dht->self_public_key)) { + return 0; + } + + return -1; +} + + +/* Ping all the valid nodes in the to_ping list every TIME_TO_PING seconds. + * This function must be run at least once every TIME_TO_PING seconds. + */ +void do_to_ping(PING *ping) +{ + if (!is_timeout(ping->last_to_ping, TIME_TO_PING)) { + return; + } + + if (!ip_isset(&ping->to_ping[0].ip_port.ip)) { + return; + } + + unsigned int i; + + for (i = 0; i < MAX_TO_PING; ++i) { + if (!ip_isset(&ping->to_ping[i].ip_port.ip)) { + break; + } + + if (!node_addable_to_close_list(ping->dht, ping->to_ping[i].public_key, ping->to_ping[i].ip_port)) { + continue; + } + + send_ping_request(ping, ping->to_ping[i].ip_port, ping->to_ping[i].public_key); + ip_reset(&ping->to_ping[i].ip_port.ip); + } + + if (i != 0) { + ping->last_to_ping = unix_time(); + } +} + + +PING *new_ping(DHT *dht) +{ + PING *ping = (PING *)calloc(1, sizeof(PING)); + + if (ping == NULL) { + return NULL; + } + + if (ping_array_init(&ping->ping_array, PING_NUM_MAX, PING_TIMEOUT) != 0) { + free(ping); + return NULL; + } + + ping->dht = dht; + networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, &handle_ping_request, dht); + networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, &handle_ping_response, dht); + + return ping; +} + +void kill_ping(PING *ping) +{ + networking_registerhandler(ping->dht->net, NET_PACKET_PING_REQUEST, NULL, NULL); + networking_registerhandler(ping->dht->net, NET_PACKET_PING_RESPONSE, NULL, NULL); + ping_array_free_all(&ping->ping_array); + + free(ping); +} diff --git a/libs/libtox/src/toxcore/ping.h b/libs/libtox/src/toxcore/ping.h new file mode 100644 index 0000000000..cc3428c548 --- /dev/null +++ b/libs/libtox/src/toxcore/ping.h @@ -0,0 +1,54 @@ +/* + * Buffered pinging using cyclic arrays. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * Copyright © 2013 plutooo + * + * This file is part of Tox, the free peer to peer instant messenger. + * This file is donated to the Tox Project. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef PING_H +#define PING_H + +#include "DHT.h" +#include "network.h" + +#include + +typedef struct PING PING; + +/* Add nodes to the to_ping list. + * All nodes in this list are pinged every TIME_TOPING seconds + * and are then removed from the list. + * If the list is full the nodes farthest from our public_key are replaced. + * The purpose of this list is to enable quick integration of new nodes into the + * network while preventing amplification attacks. + * + * return 0 if node was added. + * return -1 if node was not added. + */ +int add_to_ping(PING *ping, const uint8_t *public_key, IP_Port ip_port); +void do_to_ping(PING *ping); + +PING *new_ping(DHT *dht); +void kill_ping(PING *ping); + +int send_ping_request(PING *ping, IP_Port ipp, const uint8_t *public_key); + +#endif /* PING_H */ diff --git a/libs/libtox/src/toxcore/ping_array.c b/libs/libtox/src/toxcore/ping_array.c new file mode 100644 index 0000000000..ea3e5101b1 --- /dev/null +++ b/libs/libtox/src/toxcore/ping_array.c @@ -0,0 +1,172 @@ +/* + * Implementation of an efficient array to store that we pinged something. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ping_array.h" + +#include "crypto_core.h" +#include "util.h" + +static void clear_entry(Ping_Array *array, uint32_t index) +{ + free(array->entries[index].data); + array->entries[index].data = NULL; + array->entries[index].length = + array->entries[index].time = + array->entries[index].ping_id = 0; +} + +/* Clear timed out entries. + */ +static void ping_array_clear_timedout(Ping_Array *array) +{ + while (array->last_deleted != array->last_added) { + uint32_t index = array->last_deleted % array->total_size; + + if (!is_timeout(array->entries[index].time, array->timeout)) { + break; + } + + clear_entry(array, index); + ++array->last_deleted; + } +} + +/* Add a data with length to the Ping_Array list and return a ping_id. + * + * return ping_id on success. + * return 0 on failure. + */ +uint64_t ping_array_add(Ping_Array *array, const uint8_t *data, uint32_t length) +{ + ping_array_clear_timedout(array); + uint32_t index = array->last_added % array->total_size; + + if (array->entries[index].data != NULL) { + array->last_deleted = array->last_added - array->total_size; + clear_entry(array, index); + } + + array->entries[index].data = malloc(length); + + if (array->entries[index].data == NULL) { + return 0; + } + + memcpy(array->entries[index].data, data, length); + array->entries[index].length = length; + array->entries[index].time = unix_time(); + ++array->last_added; + uint64_t ping_id = random_64b(); + ping_id /= array->total_size; + ping_id *= array->total_size; + ping_id += index; + + if (ping_id == 0) { + ping_id += array->total_size; + } + + array->entries[index].ping_id = ping_id; + return ping_id; +} + + +/* Check if ping_id is valid and not timed out. + * + * On success, copies the data into data of length, + * + * return length of data copied on success. + * return -1 on failure. + */ +int ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id) +{ + if (ping_id == 0) { + return -1; + } + + uint32_t index = ping_id % array->total_size; + + if (array->entries[index].ping_id != ping_id) { + return -1; + } + + if (is_timeout(array->entries[index].time, array->timeout)) { + return -1; + } + + if (array->entries[index].length > length) { + return -1; + } + + if (array->entries[index].data == NULL) { + return -1; + } + + memcpy(data, array->entries[index].data, array->entries[index].length); + uint32_t len = array->entries[index].length; + clear_entry(array, index); + return len; +} + +/* Initialize a Ping_Array. + * size represents the total size of the array and should be a power of 2. + * timeout represents the maximum timeout in seconds for the entry. + * + * return 0 on success. + * return -1 on failure. + */ +int ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout) +{ + if (size == 0 || timeout == 0 || empty_array == NULL) { + return -1; + } + + empty_array->entries = (Ping_Array_Entry *)calloc(size, sizeof(Ping_Array_Entry)); + + if (empty_array->entries == NULL) { + return -1; + } + + empty_array->last_deleted = empty_array->last_added = 0; + empty_array->total_size = size; + empty_array->timeout = timeout; + return 0; +} + +/* Free all the allocated memory in a Ping_Array. + */ +void ping_array_free_all(Ping_Array *array) +{ + while (array->last_deleted != array->last_added) { + uint32_t index = array->last_deleted % array->total_size; + clear_entry(array, index); + ++array->last_deleted; + } + + free(array->entries); + array->entries = NULL; +} + diff --git a/libs/libtox/src/toxcore/ping_array.h b/libs/libtox/src/toxcore/ping_array.h new file mode 100644 index 0000000000..bdf3c6db3d --- /dev/null +++ b/libs/libtox/src/toxcore/ping_array.h @@ -0,0 +1,76 @@ +/* + * Implementation of an efficient array to store that we pinged something. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef PING_ARRAY_H +#define PING_ARRAY_H + +#include "network.h" + +typedef struct { + void *data; + uint32_t length; + uint64_t time; + uint64_t ping_id; +} Ping_Array_Entry; + + +typedef struct { + Ping_Array_Entry *entries; + + uint32_t last_deleted; /* number representing the next entry to be deleted. */ + uint32_t last_added; /* number representing the last entry to be added. */ + uint32_t total_size; /* The length of entries */ + uint32_t timeout; /* The timeout after which entries are cleared. */ +} Ping_Array; + + +/* Add a data with length to the Ping_Array list and return a ping_id. + * + * return ping_id on success. + * return 0 on failure. + */ +uint64_t ping_array_add(Ping_Array *array, const uint8_t *data, uint32_t length); + +/* Check if ping_id is valid and not timed out. + * + * On success, copies the data into data of length, + * + * return length of data copied on success. + * return -1 on failure. + */ +int ping_array_check(uint8_t *data, uint32_t length, Ping_Array *array, uint64_t ping_id); + +/* Initialize a Ping_Array. + * size represents the total size of the array and should be a power of 2. + * timeout represents the maximum timeout in seconds for the entry. + * + * return 0 on success. + * return -1 on failure. + */ +int ping_array_init(Ping_Array *empty_array, uint32_t size, uint32_t timeout); + +/* Free all the allocated memory in a Ping_Array. + */ +void ping_array_free_all(Ping_Array *array); + +#endif diff --git a/libs/libtox/src/toxcore/tox.api.h b/libs/libtox/src/toxcore/tox.api.h new file mode 100644 index 0000000000..0763c7789d --- /dev/null +++ b/libs/libtox/src/toxcore/tox.api.h @@ -0,0 +1,2583 @@ +%{ +/* + * The Tox public API. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef TOX_H +#define TOX_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +%} + + +/***************************************************************************** + * `tox.h` SHOULD *NOT* BE EDITED MANUALLY – any changes should be made to * + * `tox.api.h`, located in `toxcore/`. For instructions on how to * + * generate `tox.h` from `tox.api.h` please refer to `docs/apidsl.md` * + *****************************************************************************/ + + +/** \page core Public core API for Tox clients. + * + * Every function that can fail takes a function-specific error code pointer + * that can be used to diagnose problems with the Tox state or the function + * arguments. The error code pointer can be NULL, which does not influence the + * function's behaviour, but can be done if the reason for failure is irrelevant + * to the client. + * + * The exception to this rule are simple allocation functions whose only failure + * mode is allocation failure. They return NULL in that case, and do not set an + * error code. + * + * Every error code type has an OK value to which functions will set their error + * code value on success. Clients can keep their error code uninitialised before + * passing it to a function. The library guarantees that after returning, the + * value pointed to by the error code pointer has been initialised. + * + * Functions with pointer parameters often have a NULL error code, meaning they + * could not perform any operation, because one of the required parameters was + * NULL. Some functions operate correctly or are defined as effectless on NULL. + * + * Some functions additionally return a value outside their + * return type domain, or a bool containing true on success and false on + * failure. + * + * All functions that take a Tox instance pointer will cause undefined behaviour + * when passed a NULL Tox pointer. + * + * All integer values are expected in host byte order. + * + * Functions with parameters with enum types cause unspecified behaviour if the + * enumeration value is outside the valid range of the type. If possible, the + * function will try to use a sane default, but there will be no error code, + * and one possible action for the function to take is to have no effect. + * + * Integer constants and the memory layout of publicly exposed structs are not + * part of the ABI. + */ + +/** \subsection events Events and callbacks + * + * Events are handled by callbacks. One callback can be registered per event. + * All events have a callback function type named `tox_{event}_cb` and a + * function to register it named `tox_callback_{event}`. Passing a NULL + * callback will result in no callback being registered for that event. Only + * one callback per event can be registered, so if a client needs multiple + * event listeners, it needs to implement the dispatch functionality itself. + * + * The last argument to a callback is the user data pointer. It is passed from + * ${tox.iterate} to each callback in sequence. + * + * The user data pointer is never stored or dereferenced by any library code, so + * can be any pointer, including NULL. Callbacks must all operate on the same + * object type. In the apidsl code (tox.in.h), this is denoted with `any`. The + * `any` in ${tox.iterate} must be the same `any` as in all callbacks. In C, + * lacking parametric polymorphism, this is a pointer to void. + * + * Old style callbacks that are registered together with a user data pointer + * receive that pointer as argument when they are called. They can each have + * their own user data pointer of their own type. + */ + +/** \subsection threading Threading implications + * + * It is possible to run multiple concurrent threads with a Tox instance for + * each thread. It is also possible to run all Tox instances in the same thread. + * A common way to run Tox (multiple or single instance) is to have one thread + * running a simple ${tox.iterate} loop, sleeping for ${tox.iteration_interval} + * milliseconds on each iteration. + * + * If you want to access a single Tox instance from multiple threads, access + * to the instance must be synchronised. While multiple threads can concurrently + * access multiple different Tox instances, no more than one API function can + * operate on a single instance at any given time. + * + * Functions that write to variable length byte arrays will always have a size + * function associated with them. The result of this size function is only valid + * until another mutating function (one that takes a pointer to non-const Tox) + * is called. Thus, clients must ensure that no other thread calls a mutating + * function between the call to the size function and the call to the retrieval + * function. + * + * E.g. to get the current nickname, one would write + * + * \code + * size_t length = ${tox.self.name.size}(tox); + * uint8_t *name = malloc(length); + * if (!name) abort(); + * ${tox.self.name.get}(tox, name); + * \endcode + * + * If any other thread calls ${tox.self.name.set} while this thread is allocating + * memory, the length may have become invalid, and the call to + * ${tox.self.name.get} may cause undefined behaviour. + */ + +// The rest of this file is in class tox. +class tox { + +/** + * The Tox instance type. All the state associated with a connection is held + * within the instance. Multiple instances can exist and operate concurrently. + * The maximum number of Tox instances that can exist on a single network + * device is limited. Note that this is not just a per-process limit, since the + * limiting factor is the number of usable ports on a device. + */ +struct this; + + +/******************************************************************************* + * + * :: API version + * + ******************************************************************************/ + + +/** + * The major version number. Incremented when the API or ABI changes in an + * incompatible way. + * + * The function variants of these constants return the version number of the + * library. They can be used to display the Tox library version or to check + * whether the client is compatible with the dynamically linked version of Tox. + */ +const VERSION_MAJOR = 0; + +/** + * The minor version number. Incremented when functionality is added without + * breaking the API or ABI. Set to 0 when the major version number is + * incremented. + */ +const VERSION_MINOR = 1; + +/** + * The patch or revision number. Incremented when bugfixes are applied without + * changing any functionality or API or ABI. + */ +const VERSION_PATCH = 10; + +/** + * A macro to check at preprocessing time whether the client code is compatible + * with the installed version of Tox. Leading zeros in the version number are + * ignored. E.g. 0.1.5 is to 0.1.4 what 1.5 is to 1.4, that is: it can add new + * features, but can't break the API. + */ +#define TOX_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH) \ + (TOX_VERSION_MAJOR > 0 && TOX_VERSION_MAJOR == MAJOR) && ( \ + /* 1.x.x, 2.x.x, etc. with matching major version. */ \ + TOX_VERSION_MINOR > MINOR || \ + TOX_VERSION_MINOR == MINOR && TOX_VERSION_PATCH >= PATCH \ + ) || (TOX_VERSION_MAJOR == 0 && MAJOR == 0) && ( \ + /* 0.x.x makes minor behave like major above. */ \ + (TOX_VERSION_MINOR > 0 && TOX_VERSION_MINOR == MINOR) && ( \ + TOX_VERSION_PATCH >= PATCH \ + ) || (TOX_VERSION_MINOR == 0 && MINOR == 0) && ( \ + /* 0.0.x and 0.0.y are only compatible if x == y. */ \ + TOX_VERSION_PATCH == PATCH \ + ) \ + ) + +static namespace version { + + /** + * Return whether the compiled library version is compatible with the passed + * version numbers. + */ + bool is_compatible(uint32_t major, uint32_t minor, uint32_t patch); + +} + +/** + * A convenience macro to call tox_version_is_compatible with the currently + * compiling API version. + */ +#define TOX_VERSION_IS_ABI_COMPATIBLE() \ + tox_version_is_compatible(TOX_VERSION_MAJOR, TOX_VERSION_MINOR, TOX_VERSION_PATCH) + +/******************************************************************************* + * + * :: Numeric constants + * + * The values of these are not part of the ABI. Prefer to use the function + * versions of them for code that should remain compatible with future versions + * of toxcore. + * + ******************************************************************************/ + + +/** + * The size of a Tox Public Key in bytes. + */ +const PUBLIC_KEY_SIZE = 32; + +/** + * The size of a Tox Secret Key in bytes. + */ +const SECRET_KEY_SIZE = 32; + +/** + * The size of the nospam in bytes when written in a Tox address. + */ +const NOSPAM_SIZE = sizeof(uint32_t); + +/** + * The size of a Tox address in bytes. Tox addresses are in the format + * [Public Key ($PUBLIC_KEY_SIZE bytes)][nospam (4 bytes)][checksum (2 bytes)]. + * + * The checksum is computed over the Public Key and the nospam value. The first + * byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an + * XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam. + */ +const ADDRESS_SIZE = PUBLIC_KEY_SIZE + NOSPAM_SIZE + sizeof(uint16_t); + +/** + * Maximum length of a nickname in bytes. + */ +const MAX_NAME_LENGTH = 128; + +/** + * Maximum length of a status message in bytes. + */ +const MAX_STATUS_MESSAGE_LENGTH = 1007; + +/** + * Maximum length of a friend request message in bytes. + */ +const MAX_FRIEND_REQUEST_LENGTH = 1016; + +/** + * Maximum length of a single message after which it should be split. + */ +const MAX_MESSAGE_LENGTH = 1372; + +/** + * Maximum size of custom packets. TODO(iphydf): should be LENGTH? + */ +const MAX_CUSTOM_PACKET_SIZE = 1373; + +/** + * The number of bytes in a hash generated by $hash. + */ +const HASH_LENGTH = 32; + +/** + * The number of bytes in a file id. + */ +const FILE_ID_LENGTH = 32; + +/** + * Maximum file name length for file transfers. + */ +const MAX_FILENAME_LENGTH = 255; + + +/******************************************************************************* + * + * :: Global enumerations + * + ******************************************************************************/ + + +/** + * Represents the possible statuses a client can have. + */ +enum class USER_STATUS { + /** + * User is online and available. + */ + NONE, + /** + * User is away. Clients can set this e.g. after a user defined + * inactivity time. + */ + AWAY, + /** + * User is busy. Signals to other clients that this client does not + * currently wish to communicate. + */ + BUSY, +} + + +/** + * Represents message types for ${tox.friend.send.message} and conference + * messages. + */ +enum class MESSAGE_TYPE { + /** + * Normal text message. Similar to PRIVMSG on IRC. + */ + NORMAL, + /** + * A message describing an user action. This is similar to /me (CTCP ACTION) + * on IRC. + */ + ACTION, +} + + +/******************************************************************************* + * + * :: Startup options + * + ******************************************************************************/ + + +/** + * Type of proxy used to connect to TCP relays. + */ +enum class PROXY_TYPE { + /** + * Don't use a proxy. + */ + NONE, + /** + * HTTP proxy using CONNECT. + */ + HTTP, + /** + * SOCKS proxy for simple socket pipes. + */ + SOCKS5, +} + +/** + * Type of savedata to create the Tox instance from. + */ +enum class SAVEDATA_TYPE { + /** + * No savedata. + */ + NONE, + /** + * Savedata is one that was obtained from ${savedata.get}. + */ + TOX_SAVE, + /** + * Savedata is a secret key of length $SECRET_KEY_SIZE. + */ + SECRET_KEY, +} + + +/** + * Severity level of log messages. + */ +enum class LOG_LEVEL { + /** + * Very detailed traces including all network activity. + */ + TRACE, + /** + * Debug messages such as which port we bind to. + */ + DEBUG, + /** + * Informational log messages such as video call status changes. + */ + INFO, + /** + * Warnings about internal inconsistency or logic errors. + */ + WARNING, + /** + * Severe unexpected errors caused by external or internal inconsistency. + */ + ERROR, +} + +/** + * This event is triggered when the toxcore library logs an internal message. + * This is mostly useful for debugging. This callback can be called from any + * function, not just $iterate. This means the user data lifetime must at + * least extend between registering and unregistering it or $kill. + * + * Other toxcore modules such as toxav may concurrently call this callback at + * any time. Thus, user code must make sure it is equipped to handle concurrent + * execution, e.g. by employing appropriate mutex locking. + * + * @param level The severity of the log message. + * @param file The source file from which the message originated. + * @param line The source line from which the message originated. + * @param func The function from which the message originated. + * @param message The log message. + * @param user_data The user data pointer passed to $new in options. + */ +typedef void log_cb(LOG_LEVEL level, string file, uint32_t line, string func, string message, any user_data); + + +static class options { + /** + * This struct contains all the startup options for Tox. You must $new to + * allocate an object of this type. + * + * WARNING: Although this struct happens to be visible in the API, it is + * effectively private. Do not allocate this yourself or access members + * directly, as it *will* break binary compatibility frequently. + * + * @deprecated The memory layout of this struct (size, alignment, and field + * order) is not part of the ABI. To remain compatible, prefer to use $new to + * allocate the object and accessor functions to set the members. The struct + * will become opaque (i.e. the definition will become private) in v0.2.0. + */ + struct this [get, set] { + /** + * The type of socket to create. + * + * If this is set to false, an IPv4 socket is created, which subsequently + * only allows IPv4 communication. + * If it is set to true, an IPv6 socket is created, allowing both IPv4 and + * IPv6 communication. + */ + bool ipv6_enabled; + + /** + * Enable the use of UDP communication when available. + * + * Setting this to false will force Tox to use TCP only. Communications will + * need to be relayed through a TCP relay node, potentially slowing them down. + * Disabling UDP support is necessary when using anonymous proxies or Tor. + */ + bool udp_enabled; + + /** + * Enable local network peer discovery. + * + * Disabling this will cause Tox to not look for peers on the local network. + */ + bool local_discovery_enabled; + + namespace proxy { + /** + * Pass communications through a proxy. + */ + PROXY_TYPE type; + + /** + * The IP address or DNS name of the proxy to be used. + * + * If used, this must be non-NULL and be a valid DNS name. The name must not + * exceed 255 characters, and be in a NUL-terminated C string format + * (255 chars + 1 NUL byte). + * + * This member is ignored (it can be NULL) if proxy_type is ${PROXY_TYPE.NONE}. + * + * The data pointed at by this member is owned by the user, so must + * outlive the options object. + */ + string host; + + /** + * The port to use to connect to the proxy server. + * + * Ports must be in the range (1, 65535). The value is ignored if + * proxy_type is ${PROXY_TYPE.NONE}. + */ + uint16_t port; + } + + /** + * The start port of the inclusive port range to attempt to use. + * + * If both start_port and end_port are 0, the default port range will be + * used: [33445, 33545]. + * + * If either start_port or end_port is 0 while the other is non-zero, the + * non-zero port will be the only port in the range. + * + * Having start_port > end_port will yield the same behavior as if start_port + * and end_port were swapped. + */ + uint16_t start_port; + + /** + * The end port of the inclusive port range to attempt to use. + */ + uint16_t end_port; + + /** + * The port to use for the TCP server (relay). If 0, the TCP server is + * disabled. + * + * Enabling it is not required for Tox to function properly. + * + * When enabled, your Tox instance can act as a TCP relay for other Tox + * instance. This leads to increased traffic, thus when writing a client + * it is recommended to enable TCP server only if the user has an option + * to disable it. + */ + uint16_t tcp_port; + + /** + * Enables or disables UDP hole-punching in toxcore. (Default: enabled). + */ + bool hole_punching_enabled; + + namespace savedata { + /** + * The type of savedata to load from. + */ + SAVEDATA_TYPE type; + + /** + * The savedata. + * + * The data pointed at by this member is owned by the user, so must + * outlive the options object. + */ + const uint8_t[length] data; + + /** + * The length of the savedata. + */ + size_t length; + } + + namespace log { + /** + * Logging callback for the new tox instance. + */ + log_cb *callback; + + /** + * User data pointer passed to the logging callback. + */ + any user_data; + } + } + + + /** + * Initialises a $this object with the default options. + * + * The result of this function is independent of the original options. All + * values will be overwritten, no values will be read (so it is permissible + * to pass an uninitialised object). + * + * If options is NULL, this function has no effect. + * + * @param options An options object to be filled with default options. + */ + void default(); + + + /** + * Allocates a new $this object and initialises it with the default + * options. This function can be used to preserve long term ABI compatibility by + * giving the responsibility of allocation and deallocation to the Tox library. + * + * Objects returned from this function must be freed using the $free + * function. + * + * @return A new $this object with default options or NULL on failure. + */ + static this new() { + /** + * The function failed to allocate enough memory for the options struct. + */ + MALLOC, + } + + + /** + * Releases all resources associated with an options objects. + * + * Passing a pointer that was not returned by $new results in + * undefined behaviour. + */ + void free(); +} + + +/******************************************************************************* + * + * :: Creation and destruction + * + ******************************************************************************/ + + +/** + * @brief Creates and initialises a new Tox instance with the options passed. + * + * This function will bring the instance into a valid state. Running the event + * loop with a new instance will operate correctly. + * + * If loading failed or succeeded only partially, the new or partially loaded + * instance is returned and an error code is set. + * + * @param options An options object as described above. If this parameter is + * NULL, the default options are used. + * + * @see $iterate for the event loop. + * + * @return A new Tox instance pointer on success or NULL on failure. + */ +static this new(const options_t *options) { + NULL, + /** + * The function was unable to allocate enough memory to store the internal + * structures for the Tox object. + */ + MALLOC, + /** + * The function was unable to bind to a port. This may mean that all ports + * have already been bound, e.g. by other Tox instances, or it may mean + * a permission error. You may be able to gather more information from errno. + */ + PORT_ALLOC, + + namespace PROXY { + /** + * proxy_type was invalid. + */ + BAD_TYPE, + /** + * proxy_type was valid but the proxy_host passed had an invalid format + * or was NULL. + */ + BAD_HOST, + /** + * proxy_type was valid, but the proxy_port was invalid. + */ + BAD_PORT, + /** + * The proxy address passed could not be resolved. + */ + NOT_FOUND, + } + + namespace LOAD { + /** + * The byte array to be loaded contained an encrypted save. + */ + ENCRYPTED, + /** + * The data format was invalid. This can happen when loading data that was + * saved by an older version of Tox, or when the data has been corrupted. + * When loading from badly formatted data, some data may have been loaded, + * and the rest is discarded. Passing an invalid length parameter also + * causes this error. + */ + BAD_FORMAT, + } +} + + +/** + * Releases all resources associated with the Tox instance and disconnects from + * the network. + * + * After calling this function, the Tox pointer becomes invalid. No other + * functions can be called, and the pointer value can no longer be read. + */ +void kill(); + + +uint8_t[size] savedata { + /** + * Calculates the number of bytes required to store the tox instance with + * $get. This function cannot fail. The result is always greater than 0. + * + * @see threading for concurrency implications. + */ + size(); + + /** + * Store all information associated with the tox instance to a byte array. + * + * @param savedata A memory region large enough to store the tox instance + * data. Call $size to find the number of bytes required. If this parameter + * is NULL, this function has no effect. + */ + get(); +} + + +/******************************************************************************* + * + * :: Connection lifecycle and event loop + * + ******************************************************************************/ + + +/** + * Sends a "get nodes" request to the given bootstrap node with IP, port, and + * public key to setup connections. + * + * This function will attempt to connect to the node using UDP. You must use + * this function even if ${options.this.udp_enabled} was set to false. + * + * @param address The hostname or IP address (IPv4 or IPv6) of the node. + * @param port The port on the host on which the bootstrap Tox instance is + * listening. + * @param public_key The long term public key of the bootstrap node + * ($PUBLIC_KEY_SIZE bytes). + * @return true on success. + */ +bool bootstrap(string address, uint16_t port, const uint8_t[PUBLIC_KEY_SIZE] public_key) { + NULL, + /** + * The address could not be resolved to an IP address, or the IP address + * passed was invalid. + */ + BAD_HOST, + /** + * The port passed was invalid. The valid port range is (1, 65535). + */ + BAD_PORT, +} + + +/** + * Adds additional host:port pair as TCP relay. + * + * This function can be used to initiate TCP connections to different ports on + * the same bootstrap node, or to add TCP relays without using them as + * bootstrap nodes. + * + * @param address The hostname or IP address (IPv4 or IPv6) of the TCP relay. + * @param port The port on the host on which the TCP relay is listening. + * @param public_key The long term public key of the TCP relay + * ($PUBLIC_KEY_SIZE bytes). + * @return true on success. + */ +bool add_tcp_relay(string address, uint16_t port, const uint8_t[PUBLIC_KEY_SIZE] public_key) + with error for bootstrap; + + +/** + * Protocols that can be used to connect to the network or friends. + */ +enum class CONNECTION { + /** + * There is no connection. This instance, or the friend the state change is + * about, is now offline. + */ + NONE, + /** + * A TCP connection has been established. For the own instance, this means it + * is connected through a TCP relay, only. For a friend, this means that the + * connection to that particular friend goes through a TCP relay. + */ + TCP, + /** + * A UDP connection has been established. For the own instance, this means it + * is able to send UDP packets to DHT nodes, but may still be connected to + * a TCP relay. For a friend, this means that the connection to that + * particular friend was built using direct UDP packets. + */ + UDP, +} + + +inline namespace self { + + CONNECTION connection_status { + /** + * Return whether we are connected to the DHT. The return value is equal to the + * last value received through the `${event connection_status}` callback. + */ + get(); + } + + + /** + * This event is triggered whenever there is a change in the DHT connection + * state. When disconnected, a client may choose to call $bootstrap again, to + * reconnect to the DHT. Note that this state may frequently change for short + * amounts of time. Clients should therefore not immediately bootstrap on + * receiving a disconnect. + * + * TODO(iphydf): how long should a client wait before bootstrapping again? + */ + event connection_status const { + /** + * @param connection_status Whether we are connected to the DHT. + */ + typedef void(CONNECTION connection_status); + } + +} + + +/** + * Return the time in milliseconds before $iterate() should be called again + * for optimal performance. + */ +const uint32_t iteration_interval(); + + +/** + * The main loop that needs to be run in intervals of $iteration_interval() + * milliseconds. + */ +void iterate(any user_data); + + +/******************************************************************************* + * + * :: Internal client information (Tox address/id) + * + ******************************************************************************/ + + +inline namespace self { + + uint8_t[ADDRESS_SIZE] address { + /** + * Writes the Tox friend address of the client to a byte array. The address is + * not in human-readable format. If a client wants to display the address, + * formatting is required. + * + * @param address A memory region of at least $ADDRESS_SIZE bytes. If this + * parameter is NULL, this function has no effect. + * @see $ADDRESS_SIZE for the address format. + */ + get(); + } + + + uint32_t nospam { + /** + * Set the 4-byte nospam part of the address. This value is expected in host + * byte order. I.e. 0x12345678 will form the bytes [12, 34, 56, 78] in the + * nospam part of the Tox friend address. + * + * @param nospam Any 32 bit unsigned integer. + */ + set(); + + /** + * Get the 4-byte nospam part of the address. This value is returned in host + * byte order. + */ + get(); + } + + + uint8_t[PUBLIC_KEY_SIZE] public_key { + /** + * Copy the Tox Public Key (long term) from the Tox object. + * + * @param public_key A memory region of at least $PUBLIC_KEY_SIZE bytes. If + * this parameter is NULL, this function has no effect. + */ + get(); + } + + + uint8_t[SECRET_KEY_SIZE] secret_key { + /** + * Copy the Tox Secret Key from the Tox object. + * + * @param secret_key A memory region of at least $SECRET_KEY_SIZE bytes. If + * this parameter is NULL, this function has no effect. + */ + get(); + } + +} + + +/******************************************************************************* + * + * :: User-visible client information (nickname/status) + * + ******************************************************************************/ + + +/** + * Common error codes for all functions that set a piece of user-visible + * client information. + */ +error for set_info { + NULL, + /** + * Information length exceeded maximum permissible size. + */ + TOO_LONG, +} + + +inline namespace self { + + uint8_t[length <= MAX_NAME_LENGTH] name { + /** + * Set the nickname for the Tox client. + * + * Nickname length cannot exceed $MAX_NAME_LENGTH. If length is 0, the name + * parameter is ignored (it can be NULL), and the nickname is set back to empty. + * + * @param name A byte array containing the new nickname. + * @param length The size of the name byte array. + * + * @return true on success. + */ + set() with error for set_info; + + /** + * Return the length of the current nickname as passed to $set. + * + * If no nickname was set before calling this function, the name is empty, + * and this function returns 0. + * + * @see threading for concurrency implications. + */ + size(); + + /** + * Write the nickname set by $set to a byte array. + * + * If no nickname was set before calling this function, the name is empty, + * and this function has no effect. + * + * Call $size to find out how much memory to allocate for + * the result. + * + * @param name A valid memory location large enough to hold the nickname. + * If this parameter is NULL, the function has no effect. + */ + get(); + } + + + uint8_t[length <= MAX_STATUS_MESSAGE_LENGTH] status_message { + /** + * Set the client's status message. + * + * Status message length cannot exceed $MAX_STATUS_MESSAGE_LENGTH. If + * length is 0, the status parameter is ignored (it can be NULL), and the + * user status is set back to empty. + */ + set() with error for set_info; + + /** + * Return the length of the current status message as passed to $set. + * + * If no status message was set before calling this function, the status + * is empty, and this function returns 0. + * + * @see threading for concurrency implications. + */ + size(); + + /** + * Write the status message set by $set to a byte array. + * + * If no status message was set before calling this function, the status is + * empty, and this function has no effect. + * + * Call $size to find out how much memory to allocate for + * the result. + * + * @param status_message A valid memory location large enough to hold the + * status message. If this parameter is NULL, the function has no effect. + */ + get(); + } + + + USER_STATUS status { + /** + * Set the client's user status. + * + * @param status One of the user statuses listed in the enumeration above. + */ + set(); + + /** + * Returns the client's user status. + */ + get(); + } + +} + + +/******************************************************************************* + * + * :: Friend list management + * + ******************************************************************************/ + + +namespace friend { + + /** + * Add a friend to the friend list and send a friend request. + * + * A friend request message must be at least 1 byte long and at most + * $MAX_FRIEND_REQUEST_LENGTH. + * + * Friend numbers are unique identifiers used in all functions that operate on + * friends. Once added, a friend number is stable for the lifetime of the Tox + * object. After saving the state and reloading it, the friend numbers may not + * be the same as before. Deleting a friend creates a gap in the friend number + * set, which is filled by the next adding of a friend. Any pattern in friend + * numbers should not be relied on. + * + * If more than INT32_MAX friends are added, this function causes undefined + * behaviour. + * + * @param address The address of the friend (returned by ${self.address.get} of + * the friend you wish to add) it must be $ADDRESS_SIZE bytes. + * @param message The message that will be sent along with the friend request. + * @param length The length of the data byte array. + * + * @return the friend number on success, UINT32_MAX on failure. + */ + uint32_t add( + const uint8_t[ADDRESS_SIZE] address, + const uint8_t[length <= MAX_FRIEND_REQUEST_LENGTH] message + ) { + NULL, + /** + * The length of the friend request message exceeded + * $MAX_FRIEND_REQUEST_LENGTH. + */ + TOO_LONG, + /** + * The friend request message was empty. This, and the TOO_LONG code will + * never be returned from $add_norequest. + */ + NO_MESSAGE, + /** + * The friend address belongs to the sending client. + */ + OWN_KEY, + /** + * A friend request has already been sent, or the address belongs to a friend + * that is already on the friend list. + */ + ALREADY_SENT, + /** + * The friend address checksum failed. + */ + BAD_CHECKSUM, + /** + * The friend was already there, but the nospam value was different. + */ + SET_NEW_NOSPAM, + /** + * A memory allocation failed when trying to increase the friend list size. + */ + MALLOC, + } + + + /** + * Add a friend without sending a friend request. + * + * This function is used to add a friend in response to a friend request. If the + * client receives a friend request, it can be reasonably sure that the other + * client added this client as a friend, eliminating the need for a friend + * request. + * + * This function is also useful in a situation where both instances are + * controlled by the same entity, so that this entity can perform the mutual + * friend adding. In this case, there is no need for a friend request, either. + * + * @param public_key A byte array of length $PUBLIC_KEY_SIZE containing the + * Public Key (not the Address) of the friend to add. + * + * @return the friend number on success, UINT32_MAX on failure. + * @see $add for a more detailed description of friend numbers. + */ + uint32_t add_norequest(const uint8_t[PUBLIC_KEY_SIZE] public_key) + with error for add; + + + /** + * Remove a friend from the friend list. + * + * This does not notify the friend of their deletion. After calling this + * function, this client will appear offline to the friend and no communication + * can occur between the two. + * + * @param friend_number Friend number for the friend to be deleted. + * + * @return true on success. + */ + bool delete(uint32_t friend_number) { + /** + * There was no friend with the given friend number. No friends were deleted. + */ + FRIEND_NOT_FOUND, + } + +} + + +/******************************************************************************* + * + * :: Friend list queries + * + ******************************************************************************/ + +namespace friend { + + /** + * Return the friend number associated with that Public Key. + * + * @return the friend number on success, UINT32_MAX on failure. + * @param public_key A byte array containing the Public Key. + */ + const uint32_t by_public_key(const uint8_t[PUBLIC_KEY_SIZE] public_key) { + NULL, + /** + * No friend with the given Public Key exists on the friend list. + */ + NOT_FOUND, + } + + + /** + * Checks if a friend with the given friend number exists and returns true if + * it does. + */ + const bool exists(uint32_t friend_number); + +} + +inline namespace self { + + uint32_t[size] friend_list { + /** + * Return the number of friends on the friend list. + * + * This function can be used to determine how much memory to allocate for + * $get. + */ + size(); + + + /** + * Copy a list of valid friend numbers into an array. + * + * Call $size to determine the number of elements to allocate. + * + * @param friend_list A memory region with enough space to hold the friend + * list. If this parameter is NULL, this function has no effect. + */ + get(); + } + +} + + + +namespace friend { + + uint8_t[PUBLIC_KEY_SIZE] public_key { + /** + * Copies the Public Key associated with a given friend number to a byte array. + * + * @param friend_number The friend number you want the Public Key of. + * @param public_key A memory region of at least $PUBLIC_KEY_SIZE bytes. If + * this parameter is NULL, this function has no effect. + * + * @return true on success. + */ + get(uint32_t friend_number) { + /** + * No friend with the given number exists on the friend list. + */ + FRIEND_NOT_FOUND, + } + } + +} + +namespace friend { + + uint64_t last_online { + /** + * Return a unix-time timestamp of the last time the friend associated with a given + * friend number was seen online. This function will return UINT64_MAX on error. + * + * @param friend_number The friend number you want to query. + */ + get(uint32_t friend_number) { + /** + * No friend with the given number exists on the friend list. + */ + FRIEND_NOT_FOUND, + } + } + +} + +/******************************************************************************* + * + * :: Friend-specific state queries (can also be received through callbacks) + * + ******************************************************************************/ + + +namespace friend { + + /** + * Common error codes for friend state query functions. + */ + error for query { + /** + * The pointer parameter for storing the query result (name, message) was + * NULL. Unlike the `_self_` variants of these functions, which have no effect + * when a parameter is NULL, these functions return an error in that case. + */ + NULL, + /** + * The friend_number did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + } + + + uint8_t[length <= MAX_NAME_LENGTH] name { + /** + * Return the length of the friend's name. If the friend number is invalid, the + * return value is unspecified. + * + * The return value is equal to the `length` argument received by the last + * `${event name}` callback. + */ + size(uint32_t friend_number) + with error for query; + + /** + * Write the name of the friend designated by the given friend number to a byte + * array. + * + * Call $size to determine the allocation size for the `name` + * parameter. + * + * The data written to `name` is equal to the data received by the last + * `${event name}` callback. + * + * @param name A valid memory region large enough to store the friend's name. + * + * @return true on success. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend changes their name. + */ + event name const { + /** + * @param friend_number The friend number of the friend whose name changed. + * @param name A byte array containing the same data as + * ${name.get} would write to its `name` parameter. + * @param length A value equal to the return value of + * ${name.size}. + */ + typedef void(uint32_t friend_number, const uint8_t[length <= MAX_NAME_LENGTH] name); + } + + + uint8_t[length <= MAX_STATUS_MESSAGE_LENGTH] status_message { + /** + * Return the length of the friend's status message. If the friend number is + * invalid, the return value is SIZE_MAX. + */ + size(uint32_t friend_number) + with error for query; + + /** + * Write the status message of the friend designated by the given friend number to a byte + * array. + * + * Call $size to determine the allocation size for the `status_name` + * parameter. + * + * The data written to `status_message` is equal to the data received by the last + * `${event status_message}` callback. + * + * @param status_message A valid memory region large enough to store the friend's status message. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend changes their status message. + */ + event status_message const { + /** + * @param friend_number The friend number of the friend whose status message + * changed. + * @param message A byte array containing the same data as + * ${status_message.get} would write to its `status_message` parameter. + * @param length A value equal to the return value of + * ${status_message.size}. + */ + typedef void(uint32_t friend_number, const uint8_t[length <= MAX_STATUS_MESSAGE_LENGTH] message); + } + + + USER_STATUS status { + /** + * Return the friend's user status (away/busy/...). If the friend number is + * invalid, the return value is unspecified. + * + * The status returned is equal to the last status received through the + * `${event status}` callback. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend changes their user status. + */ + event status const { + /** + * @param friend_number The friend number of the friend whose user status + * changed. + * @param status The new user status. + */ + typedef void(uint32_t friend_number, USER_STATUS status); + } + + + CONNECTION connection_status { + /** + * Check whether a friend is currently connected to this client. + * + * The result of this function is equal to the last value received by the + * `${event connection_status}` callback. + * + * @param friend_number The friend number for which to query the connection + * status. + * + * @return the friend's connection status as it was received through the + * `${event connection_status}` event. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend goes offline after having been online, + * or when a friend goes online. + * + * This callback is not called when adding friends. It is assumed that when + * adding friends, their connection status is initially offline. + */ + event connection_status const { + /** + * @param friend_number The friend number of the friend whose connection status + * changed. + * @param connection_status The result of calling + * ${connection_status.get} on the passed friend_number. + */ + typedef void(uint32_t friend_number, CONNECTION connection_status); + } + + + bool typing { + /** + * Check whether a friend is currently typing a message. + * + * @param friend_number The friend number for which to query the typing status. + * + * @return true if the friend is typing. + * @return false if the friend is not typing, or the friend number was + * invalid. Inspect the error code to determine which case it is. + */ + get(uint32_t friend_number) + with error for query; + } + + + /** + * This event is triggered when a friend starts or stops typing. + */ + event typing const { + /** + * @param friend_number The friend number of the friend who started or stopped + * typing. + * @param is_typing The result of calling ${typing.get} on the passed + * friend_number. + */ + typedef void(uint32_t friend_number, bool is_typing); + } + +} + + +/******************************************************************************* + * + * :: Sending private messages + * + ******************************************************************************/ + + +inline namespace self { + + bool typing { + /** + * Set the client's typing status for a friend. + * + * The client is responsible for turning it on or off. + * + * @param friend_number The friend to which the client is typing a message. + * @param typing The typing status. True means the client is typing. + * + * @return true on success. + */ + set(uint32_t friend_number) { + /** + * The friend number did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + } + } + +} + + +namespace friend { + + namespace send { + + /** + * Send a text chat message to an online friend. + * + * This function creates a chat message packet and pushes it into the send + * queue. + * + * The message length may not exceed $MAX_MESSAGE_LENGTH. Larger messages + * must be split by the client and sent as separate messages. Other clients can + * then reassemble the fragments. Messages may not be empty. + * + * The return value of this function is the message ID. If a read receipt is + * received, the triggered `${event read_receipt}` event will be passed this message ID. + * + * Message IDs are unique per friend. The first message ID is 0. Message IDs are + * incremented by 1 each time a message is sent. If UINT32_MAX messages were + * sent, the next message ID is 0. + * + * @param type Message type (normal, action, ...). + * @param friend_number The friend number of the friend to send the message to. + * @param message A non-NULL pointer to the first element of a byte array + * containing the message text. + * @param length Length of the message to be sent. + */ + uint32_t message(uint32_t friend_number, MESSAGE_TYPE type, + const uint8_t[length <= MAX_MESSAGE_LENGTH] message) { + NULL, + /** + * The friend number did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * An allocation error occurred while increasing the send queue size. + */ + SENDQ, + /** + * Message length exceeded $MAX_MESSAGE_LENGTH. + */ + TOO_LONG, + /** + * Attempted to send a zero-length message. + */ + EMPTY, + } + + } + + + /** + * This event is triggered when the friend receives the message sent with + * ${send.message} with the corresponding message ID. + */ + event read_receipt const { + /** + * @param friend_number The friend number of the friend who received the message. + * @param message_id The message ID as returned from ${send.message} + * corresponding to the message sent. + */ + typedef void(uint32_t friend_number, uint32_t message_id); + } + +} + + +/******************************************************************************* + * + * :: Receiving private messages and friend requests + * + ******************************************************************************/ + + +namespace friend { + + /** + * This event is triggered when a friend request is received. + */ + event request const { + /** + * @param public_key The Public Key of the user who sent the friend request. + * @param message The message they sent along with the request. + * @param length The size of the message byte array. + */ + typedef void(const uint8_t[PUBLIC_KEY_SIZE] public_key, + const uint8_t[length <= MAX_MESSAGE_LENGTH] message); + } + + + /** + * This event is triggered when a message from a friend is received. + */ + event message const { + /** + * @param friend_number The friend number of the friend who sent the message. + * @param message The message data they sent. + * @param length The size of the message byte array. + */ + typedef void(uint32_t friend_number, MESSAGE_TYPE type, + const uint8_t[length <= MAX_MESSAGE_LENGTH] message); + } + +} + + +/******************************************************************************* + * + * :: File transmission: common between sending and receiving + * + ******************************************************************************/ + + +/** + * Generates a cryptographic hash of the given data. + * + * This function may be used by clients for any purpose, but is provided + * primarily for validating cached avatars. This use is highly recommended to + * avoid unnecessary avatar updates. + * + * If hash is NULL or data is NULL while length is not 0 the function returns false, + * otherwise it returns true. + * + * This function is a wrapper to internal message-digest functions. + * + * @param hash A valid memory location the hash data. It must be at least + * $HASH_LENGTH bytes in size. + * @param data Data to be hashed or NULL. + * @param length Size of the data array or 0. + * + * @return true if hash was not NULL. + */ +static bool hash(uint8_t[HASH_LENGTH] hash, const uint8_t[length] data); + + +namespace file { + + enum KIND { + /** + * Arbitrary file data. Clients can choose to handle it based on the file name + * or magic or any other way they choose. + */ + DATA, + /** + * Avatar file_id. This consists of $hash(image). + * Avatar data. This consists of the image data. + * + * Avatars can be sent at any time the client wishes. Generally, a client will + * send the avatar to a friend when that friend comes online, and to all + * friends when the avatar changed. A client can save some traffic by + * remembering which friend received the updated avatar already and only send + * it if the friend has an out of date avatar. + * + * Clients who receive avatar send requests can reject it (by sending + * ${CONTROL.CANCEL} before any other controls), or accept it (by + * sending ${CONTROL.RESUME}). The file_id of length $HASH_LENGTH bytes + * (same length as $FILE_ID_LENGTH) will contain the hash. A client can compare + * this hash with a saved hash and send ${CONTROL.CANCEL} to terminate the avatar + * transfer if it matches. + * + * When file_size is set to 0 in the transfer request it means that the client + * has no avatar. + */ + AVATAR, + } + + + enum class CONTROL { + /** + * Sent by the receiving side to accept a file send request. Also sent after a + * $PAUSE command to continue sending or receiving. + */ + RESUME, + /** + * Sent by clients to pause the file transfer. The initial state of a file + * transfer is always paused on the receiving side and running on the sending + * side. If both the sending and receiving side pause the transfer, then both + * need to send $RESUME for the transfer to resume. + */ + PAUSE, + /** + * Sent by the receiving side to reject a file send request before any other + * commands are sent. Also sent by either side to terminate a file transfer. + */ + CANCEL, + } + + + /** + * Sends a file control command to a friend for a given file transfer. + * + * @param friend_number The friend number of the friend the file is being + * transferred to or received from. + * @param file_number The friend-specific identifier for the file transfer. + * @param control The control command to send. + * + * @return true on success. + */ + bool control(uint32_t friend_number, uint32_t file_number, CONTROL control) { + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * No file transfer with the given file number was found for the given friend. + */ + NOT_FOUND, + /** + * A RESUME control was sent, but the file transfer is running normally. + */ + NOT_PAUSED, + /** + * A RESUME control was sent, but the file transfer was paused by the other + * party. Only the party that paused the transfer can resume it. + */ + DENIED, + /** + * A PAUSE control was sent, but the file transfer was already paused. + */ + ALREADY_PAUSED, + /** + * Packet queue is full. + */ + SENDQ, + } + + + /** + * This event is triggered when a file control command is received from a + * friend. + */ + event recv_control const { + /** + * When receiving ${CONTROL.CANCEL}, the client should release the + * resources associated with the file number and consider the transfer failed. + * + * @param friend_number The friend number of the friend who is sending the file. + * @param file_number The friend-specific file number the data received is + * associated with. + * @param control The file control command received. + */ + typedef void(uint32_t friend_number, uint32_t file_number, CONTROL control); + } + + /** + * Sends a file seek control command to a friend for a given file transfer. + * + * This function can only be called to resume a file transfer right before + * ${CONTROL.RESUME} is sent. + * + * @param friend_number The friend number of the friend the file is being + * received from. + * @param file_number The friend-specific identifier for the file transfer. + * @param position The position that the file should be seeked to. + */ + bool seek(uint32_t friend_number, uint32_t file_number, uint64_t position) { + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * No file transfer with the given file number was found for the given friend. + */ + NOT_FOUND, + /** + * File was not in a state where it could be seeked. + */ + DENIED, + /** + * Seek position was invalid + */ + INVALID_POSITION, + /** + * Packet queue is full. + */ + SENDQ, + } + + + error for get { + NULL, + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * No file transfer with the given file number was found for the given friend. + */ + NOT_FOUND, + } + + uint8_t[FILE_ID_LENGTH] file_id { + /** + * Copy the file id associated to the file transfer to a byte array. + * + * @param friend_number The friend number of the friend the file is being + * transferred to or received from. + * @param file_number The friend-specific identifier for the file transfer. + * @param file_id A memory region of at least $FILE_ID_LENGTH bytes. If + * this parameter is NULL, this function has no effect. + * + * @return true on success. + */ + get(uint32_t friend_number, uint32_t file_number) + with error for get; + } + +} + + +/******************************************************************************* + * + * :: File transmission: sending + * + ******************************************************************************/ + + +namespace file { + + /** + * Send a file transmission request. + * + * Maximum filename length is $MAX_FILENAME_LENGTH bytes. The filename + * should generally just be a file name, not a path with directory names. + * + * If a non-UINT64_MAX file size is provided, it can be used by both sides to + * determine the sending progress. File size can be set to UINT64_MAX for streaming + * data of unknown size. + * + * File transmission occurs in chunks, which are requested through the + * `${event chunk_request}` event. + * + * When a friend goes offline, all file transfers associated with the friend are + * purged from core. + * + * If the file contents change during a transfer, the behaviour is unspecified + * in general. What will actually happen depends on the mode in which the file + * was modified and how the client determines the file size. + * + * - If the file size was increased + * - and sending mode was streaming (file_size = UINT64_MAX), the behaviour + * will be as expected. + * - and sending mode was file (file_size != UINT64_MAX), the + * ${event chunk_request} callback will receive length = 0 when Core thinks + * the file transfer has finished. If the client remembers the file size as + * it was when sending the request, it will terminate the transfer normally. + * If the client re-reads the size, it will think the friend cancelled the + * transfer. + * - If the file size was decreased + * - and sending mode was streaming, the behaviour is as expected. + * - and sending mode was file, the callback will return 0 at the new + * (earlier) end-of-file, signalling to the friend that the transfer was + * cancelled. + * - If the file contents were modified + * - at a position before the current read, the two files (local and remote) + * will differ after the transfer terminates. + * - at a position after the current read, the file transfer will succeed as + * expected. + * - In either case, both sides will regard the transfer as complete and + * successful. + * + * @param friend_number The friend number of the friend the file send request + * should be sent to. + * @param kind The meaning of the file to be sent. + * @param file_size Size in bytes of the file the client wants to send, UINT64_MAX if + * unknown or streaming. + * @param file_id A file identifier of length $FILE_ID_LENGTH that can be used to + * uniquely identify file transfers across core restarts. If NULL, a random one will + * be generated by core. It can then be obtained by using ${file_id.get}(). + * @param filename Name of the file. Does not need to be the actual name. This + * name will be sent along with the file send request. + * @param filename_length Size in bytes of the filename. + * + * @return A file number used as an identifier in subsequent callbacks. This + * number is per friend. File numbers are reused after a transfer terminates. + * On failure, this function returns UINT32_MAX. Any pattern in file numbers + * should not be relied on. + */ + uint32_t send(uint32_t friend_number, uint32_t kind, uint64_t file_size, + const uint8_t[FILE_ID_LENGTH] file_id, + const uint8_t[filename_length <= MAX_FILENAME_LENGTH] filename) { + NULL, + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * Filename length exceeded $MAX_FILENAME_LENGTH bytes. + */ + NAME_TOO_LONG, + /** + * Too many ongoing transfers. The maximum number of concurrent file transfers + * is 256 per friend per direction (sending and receiving). + */ + TOO_MANY, + } + + + /** + * Send a chunk of file data to a friend. + * + * This function is called in response to the `${event chunk_request}` callback. The + * length parameter should be equal to the one received though the callback. + * If it is zero, the transfer is assumed complete. For files with known size, + * Core will know that the transfer is complete after the last byte has been + * received, so it is not necessary (though not harmful) to send a zero-length + * chunk to terminate. For streams, core will know that the transfer is finished + * if a chunk with length less than the length requested in the callback is sent. + * + * @param friend_number The friend number of the receiving friend for this file. + * @param file_number The file transfer identifier returned by tox_file_send. + * @param position The file or stream position from which to continue reading. + * @return true on success. + */ + bool send_chunk(uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t[length] data) { + /** + * The length parameter was non-zero, but data was NULL. + */ + NULL, + /** + * The friend_number passed did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * No file transfer with the given file number was found for the given friend. + */ + NOT_FOUND, + /** + * File transfer was found but isn't in a transferring state: (paused, done, + * broken, etc...) (happens only when not called from the request chunk callback). + */ + NOT_TRANSFERRING, + /** + * Attempted to send more or less data than requested. The requested data size is + * adjusted according to maximum transmission unit and the expected end of + * the file. Trying to send less or more than requested will return this error. + */ + INVALID_LENGTH, + /** + * Packet queue is full. + */ + SENDQ, + /** + * Position parameter was wrong. + */ + WRONG_POSITION, + } + + + /** + * This event is triggered when Core is ready to send more file data. + */ + event chunk_request const { + /** + * If the length parameter is 0, the file transfer is finished, and the client's + * resources associated with the file number should be released. After a call + * with zero length, the file number can be reused for future file transfers. + * + * If the requested position is not equal to the client's idea of the current + * file or stream position, it will need to seek. In case of read-once streams, + * the client should keep the last read chunk so that a seek back can be + * supported. A seek-back only ever needs to read from the last requested chunk. + * This happens when a chunk was requested, but the send failed. A seek-back + * request can occur an arbitrary number of times for any given chunk. + * + * In response to receiving this callback, the client should call the function + * `$send_chunk` with the requested chunk. If the number of bytes sent + * through that function is zero, the file transfer is assumed complete. A + * client must send the full length of data requested with this callback. + * + * @param friend_number The friend number of the receiving friend for this file. + * @param file_number The file transfer identifier returned by $send. + * @param position The file or stream position from which to continue reading. + * @param length The number of bytes requested for the current chunk. + */ + typedef void(uint32_t friend_number, uint32_t file_number, uint64_t position, size_t length); + } + +} + + +/******************************************************************************* + * + * :: File transmission: receiving + * + ******************************************************************************/ + + +namespace file { + + /** + * This event is triggered when a file transfer request is received. + */ + event recv const { + /** + * The client should acquire resources to be associated with the file transfer. + * Incoming file transfers start in the PAUSED state. After this callback + * returns, a transfer can be rejected by sending a ${CONTROL.CANCEL} + * control command before any other control commands. It can be accepted by + * sending ${CONTROL.RESUME}. + * + * @param friend_number The friend number of the friend who is sending the file + * transfer request. + * @param file_number The friend-specific file number the data received is + * associated with. + * @param kind The meaning of the file to be sent. + * @param file_size Size in bytes of the file the client wants to send, + * UINT64_MAX if unknown or streaming. + * @param filename Name of the file. Does not need to be the actual name. This + * name will be sent along with the file send request. + * @param filename_length Size in bytes of the filename. + */ + typedef void(uint32_t friend_number, uint32_t file_number, uint32_t kind, + uint64_t file_size, const uint8_t[filename_length <= MAX_FILENAME_LENGTH] filename); + } + + + /** + * This event is first triggered when a file transfer request is received, and + * subsequently when a chunk of file data for an accepted request was received. + */ + event recv_chunk const { + /** + * When length is 0, the transfer is finished and the client should release the + * resources it acquired for the transfer. After a call with length = 0, the + * file number can be reused for new file transfers. + * + * If position is equal to file_size (received in the file_receive callback) + * when the transfer finishes, the file was received completely. Otherwise, if + * file_size was UINT64_MAX, streaming ended successfully when length is 0. + * + * @param friend_number The friend number of the friend who is sending the file. + * @param file_number The friend-specific file number the data received is + * associated with. + * @param position The file position of the first byte in data. + * @param data A byte array containing the received chunk. + * @param length The length of the received chunk. + */ + typedef void(uint32_t friend_number, uint32_t file_number, uint64_t position, + const uint8_t[length] data); + } + +} + + +/******************************************************************************* + * + * :: Conference management + * + ******************************************************************************/ + +namespace conference { + + /** + * Conference types for the ${event invite} event. + */ + enum class TYPE { + /** + * Text-only conferences that must be accepted with the $join function. + */ + TEXT, + /** + * Video conference. The function to accept these is in toxav. + */ + AV, + } + + + /** + * This event is triggered when the client is invited to join a conference. + */ + event invite const { + /** + * The invitation will remain valid until the inviting friend goes offline + * or exits the conference. + * + * @param friend_number The friend who invited us. + * @param type The conference type (text only or audio/video). + * @param cookie A piece of data of variable length required to join the + * conference. + * @param length The length of the cookie. + */ + typedef void(uint32_t friend_number, TYPE type, const uint8_t[length] cookie); + } + + + /** + * This event is triggered when the client receives a conference message. + */ + event message const { + /** + * @param conference_number The conference number of the conference the message is intended for. + * @param peer_number The ID of the peer who sent the message. + * @param type The type of message (normal, action, ...). + * @param message The message data. + * @param length The length of the message. + */ + typedef void(uint32_t conference_number, uint32_t peer_number, MESSAGE_TYPE type, + const uint8_t[length] message); + } + + + /** + * This event is triggered when a peer changes the conference title. + * + * If peer_number == UINT32_MAX, then author is unknown (e.g. initial joining the conference). + */ + event title const { + /** + * @param conference_number The conference number of the conference the title change is intended for. + * @param peer_number The ID of the peer who changed the title. + * @param title The title data. + * @param length The title length. + */ + typedef void(uint32_t conference_number, uint32_t peer_number, const uint8_t[length] title); + } + + /** + * Peer list state change types. + */ + enum class STATE_CHANGE { + /** + * A peer has joined the conference. + */ + PEER_JOIN, + /** + * A peer has exited the conference. + */ + PEER_EXIT, + /** + * A peer has changed their name. + */ + PEER_NAME_CHANGE, + } + + /** + * This event is triggered when the peer list changes (name change, peer join, peer exit). + */ + event namelist_change const { + /** + * @param conference_number The conference number of the conference the title change is intended for. + * @param peer_number The ID of the peer who changed the title. + * @param change The type of change (one of $STATE_CHANGE). + */ + typedef void(uint32_t conference_number, uint32_t peer_number, STATE_CHANGE change); + } + + + /** + * Creates a new conference. + * + * This function creates a new text conference. + * + * @return conference number on success, or UINT32_MAX on failure. + */ + uint32_t new() { + /** + * The conference instance failed to initialize. + */ + INIT, + } + + /** + * This function deletes a conference. + * + * @param conference_number The conference number of the conference to be deleted. + * + * @return true on success. + */ + bool delete(uint32_t conference_number) { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + } + + + namespace peer { + + /** + * Error codes for peer info queries. + */ + error for query { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + /** + * The peer number passed did not designate a valid peer. + */ + PEER_NOT_FOUND, + /** + * The client is not connected to the conference. + */ + NO_CONNECTION, + } + + /** + * Return the number of peers in the conference. Return value is unspecified on failure. + */ + const uint32_t count(uint32_t conference_number) + with error for query; + + uint8_t[size] name { + + /** + * Return the length of the peer's name. Return value is unspecified on failure. + */ + size(uint32_t conference_number, uint32_t peer_number) + with error for query; + + /** + * Copy the name of peer_number who is in conference_number to name. + * name must be at least $MAX_NAME_LENGTH long. + * + * @return true on success. + */ + get(uint32_t conference_number, uint32_t peer_number) + with error for query; + } + + /** + * Copy the public key of peer_number who is in conference_number to public_key. + * public_key must be $PUBLIC_KEY_SIZE long. + * + * @return true on success. + */ + uint8_t[PUBLIC_KEY_SIZE] public_key { + get(uint32_t conference_number, uint32_t peer_number) + with error for query; + } + + /** + * Return true if passed peer_number corresponds to our own. + */ + const bool number_is_ours(uint32_t conference_number, uint32_t peer_number) + with error for query; + + } + + + /** + * Invites a friend to a conference. + * + * @param friend_number The friend number of the friend we want to invite. + * @param conference_number The conference number of the conference we want to invite the friend to. + * + * @return true on success. + */ + bool invite(uint32_t friend_number, uint32_t conference_number) { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + /** + * The invite packet failed to send. + */ + FAIL_SEND, + } + + + /** + * Joins a conference that the client has been invited to. + * + * @param friend_number The friend number of the friend who sent the invite. + * @param cookie Received via the `${event invite}` event. + * @param length The size of cookie. + * + * @return conference number on success, UINT32_MAX on failure. + */ + uint32_t join(uint32_t friend_number, const uint8_t[length] cookie) { + /** + * The cookie passed has an invalid length. + */ + INVALID_LENGTH, + /** + * The conference is not the expected type. This indicates an invalid cookie. + */ + WRONG_TYPE, + /** + * The friend number passed does not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * Client is already in this conference. + */ + DUPLICATE, + /** + * Conference instance failed to initialize. + */ + INIT_FAIL, + /** + * The join packet failed to send. + */ + FAIL_SEND, + } + + + namespace send { + + /** + * Send a text chat message to the conference. + * + * This function creates a conference message packet and pushes it into the send + * queue. + * + * The message length may not exceed $MAX_MESSAGE_LENGTH. Larger messages + * must be split by the client and sent as separate messages. Other clients can + * then reassemble the fragments. + * + * @param conference_number The conference number of the conference the message is intended for. + * @param type Message type (normal, action, ...). + * @param message A non-NULL pointer to the first element of a byte array + * containing the message text. + * @param length Length of the message to be sent. + * + * @return true on success. + */ + bool message(uint32_t conference_number, MESSAGE_TYPE type, const uint8_t[length] message) { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + /** + * The message is too long. + */ + TOO_LONG, + /** + * The client is not connected to the conference. + */ + NO_CONNECTION, + /** + * The message packet failed to send. + */ + FAIL_SEND, + } + } + + error for title { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + /** + * The title is too long or empty. + */ + INVALID_LENGTH, + /** + * The title packet failed to send. + */ + FAIL_SEND, + } + + uint8_t[length <= MAX_NAME_LENGTH] title { + + /** + * Return the length of the conference title. Return value is unspecified on failure. + * + * The return value is equal to the `length` argument received by the last + * `${event title}` callback. + */ + size(uint32_t conference_number) + with error for title; + + /** + * Write the title designated by the given conference number to a byte array. + * + * Call $size to determine the allocation size for the `title` parameter. + * + * The data written to `title` is equal to the data received by the last + * `${event title}` callback. + * + * @param title A valid memory region large enough to store the title. + * If this parameter is NULL, this function has no effect. + * + * @return true on success. + */ + get(uint32_t conference_number) + with error for title; + + /** + * Set the conference title and broadcast it to the rest of the conference. + * + * Title length cannot be longer than $MAX_NAME_LENGTH. + * + * @return true on success. + */ + set(uint32_t conference_number) + with error for title; + } + + + uint32_t[size] chatlist { + /** + * Return the number of conferences in the Tox instance. + * This should be used to determine how much memory to allocate for `$get`. + */ + size(); + + /** + * Copy a list of valid conference IDs into the array chatlist. Determine how much space + * to allocate for the array with the `$size` function. + */ + get(); + } + + + /** + * Returns the type of conference ($TYPE) that conference_number is. Return value is + * unspecified on failure. + */ + TYPE type { + get(uint32_t conference_number) { + /** + * The conference number passed did not designate a valid conference. + */ + CONFERENCE_NOT_FOUND, + } + } + +} + + +/******************************************************************************* + * + * :: Low-level custom packet sending and receiving + * + ******************************************************************************/ + + +namespace friend { + + inline namespace send { + + error for custom_packet { + NULL, + /** + * The friend number did not designate a valid friend. + */ + FRIEND_NOT_FOUND, + /** + * This client is currently not connected to the friend. + */ + FRIEND_NOT_CONNECTED, + /** + * The first byte of data was not in the specified range for the packet type. + * This range is 200-254 for lossy, and 160-191 for lossless packets. + */ + INVALID, + /** + * Attempted to send an empty packet. + */ + EMPTY, + /** + * Packet data length exceeded $MAX_CUSTOM_PACKET_SIZE. + */ + TOO_LONG, + /** + * Packet queue is full. + */ + SENDQ, + } + + /** + * Send a custom lossy packet to a friend. + * + * The first byte of data must be in the range 200-254. Maximum length of a + * custom packet is $MAX_CUSTOM_PACKET_SIZE. + * + * Lossy packets behave like UDP packets, meaning they might never reach the + * other side or might arrive more than once (if someone is messing with the + * connection) or might arrive in the wrong order. + * + * Unless latency is an issue, it is recommended that you use lossless custom + * packets instead. + * + * @param friend_number The friend number of the friend this lossy packet + * should be sent to. + * @param data A byte array containing the packet data. + * @param length The length of the packet data byte array. + * + * @return true on success. + */ + bool lossy_packet(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data) + with error for custom_packet; + + + /** + * Send a custom lossless packet to a friend. + * + * The first byte of data must be in the range 160-191. Maximum length of a + * custom packet is $MAX_CUSTOM_PACKET_SIZE. + * + * Lossless packet behaviour is comparable to TCP (reliability, arrive in order) + * but with packets instead of a stream. + * + * @param friend_number The friend number of the friend this lossless packet + * should be sent to. + * @param data A byte array containing the packet data. + * @param length The length of the packet data byte array. + * + * @return true on success. + */ + bool lossless_packet(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data) + with error for custom_packet; + + } + + + event lossy_packet const { + /** + * @param friend_number The friend number of the friend who sent a lossy packet. + * @param data A byte array containing the received packet data. + * @param length The length of the packet data byte array. + */ + typedef void(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data); + } + + + event lossless_packet const { + /** + * @param friend_number The friend number of the friend who sent the packet. + * @param data A byte array containing the received packet data. + * @param length The length of the packet data byte array. + */ + typedef void(uint32_t friend_number, const uint8_t[length <= MAX_CUSTOM_PACKET_SIZE] data); + } + +} + + + +/******************************************************************************* + * + * :: Low-level network information + * + ******************************************************************************/ + + +inline namespace self { + + uint8_t[PUBLIC_KEY_SIZE] dht_id { + /** + * Writes the temporary DHT public key of this instance to a byte array. + * + * This can be used in combination with an externally accessible IP address and + * the bound port (from ${udp_port.get}) to run a temporary bootstrap node. + * + * Be aware that every time a new instance is created, the DHT public key + * changes, meaning this cannot be used to run a permanent bootstrap node. + * + * @param dht_id A memory region of at least $PUBLIC_KEY_SIZE bytes. If this + * parameter is NULL, this function has no effect. + */ + get(); + } + + + error for get_port { + /** + * The instance was not bound to any port. + */ + NOT_BOUND, + } + + + uint16_t udp_port { + /** + * Return the UDP port this Tox instance is bound to. + */ + get() with error for get_port; + } + + + uint16_t tcp_port { + /** + * Return the TCP port this Tox instance is bound to. This is only relevant if + * the instance is acting as a TCP relay. + */ + get() with error for get_port; + } + +} + +} // class tox + +%{ +#ifdef __cplusplus +} +#endif + +#endif +%} diff --git a/libs/libtox/src/toxcore/tox.c b/libs/libtox/src/toxcore/tox.c new file mode 100644 index 0000000000..12f3762083 --- /dev/null +++ b/libs/libtox/src/toxcore/tox.c @@ -0,0 +1,1551 @@ +/* + * The Tox public API. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _XOPEN_SOURCE 600 + +#define TOX_DEFINED +typedef struct Messenger Tox; +#include "tox.h" + +#include "Messenger.h" +#include "group.h" +#include "logger.h" + +#include "../toxencryptsave/defines.h" + +#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} + +#if TOX_HASH_LENGTH != CRYPTO_SHA256_SIZE +#error TOX_HASH_LENGTH is assumed to be equal to CRYPTO_SHA256_SIZE +#endif + +#if FILE_ID_LENGTH != CRYPTO_SYMMETRIC_KEY_SIZE +#error FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE +#endif + +#if TOX_FILE_ID_LENGTH != CRYPTO_SYMMETRIC_KEY_SIZE +#error TOX_FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE +#endif + +#if TOX_FILE_ID_LENGTH != TOX_HASH_LENGTH +#error TOX_FILE_ID_LENGTH is assumed to be equal to TOX_HASH_LENGTH +#endif + +#if TOX_PUBLIC_KEY_SIZE != CRYPTO_PUBLIC_KEY_SIZE +#error TOX_PUBLIC_KEY_SIZE is assumed to be equal to CRYPTO_PUBLIC_KEY_SIZE +#endif + +#if TOX_SECRET_KEY_SIZE != CRYPTO_SECRET_KEY_SIZE +#error TOX_SECRET_KEY_SIZE is assumed to be equal to CRYPTO_SECRET_KEY_SIZE +#endif + +#if TOX_MAX_NAME_LENGTH != MAX_NAME_LENGTH +#error TOX_MAX_NAME_LENGTH is assumed to be equal to MAX_NAME_LENGTH +#endif + +#if TOX_MAX_STATUS_MESSAGE_LENGTH != MAX_STATUSMESSAGE_LENGTH +#error TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH +#endif + + +bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch) +{ + return TOX_VERSION_IS_API_COMPATIBLE(major, minor, patch); +} + + +Tox *tox_new(const struct Tox_Options *options, TOX_ERR_NEW *error) +{ + Messenger_Options m_options = {0}; + + bool load_savedata_sk = 0, load_savedata_tox = 0; + + if (options == NULL) { + m_options.ipv6enabled = TOX_ENABLE_IPV6_DEFAULT; + } else { + if (tox_options_get_savedata_type(options) != TOX_SAVEDATA_TYPE_NONE) { + if (tox_options_get_savedata_data(options) == NULL || tox_options_get_savedata_length(options) == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); + return NULL; + } + } + + if (tox_options_get_savedata_type(options) == TOX_SAVEDATA_TYPE_SECRET_KEY) { + if (tox_options_get_savedata_length(options) != TOX_SECRET_KEY_SIZE) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); + return NULL; + } + + load_savedata_sk = 1; + } else if (tox_options_get_savedata_type(options) == TOX_SAVEDATA_TYPE_TOX_SAVE) { + if (tox_options_get_savedata_length(options) < TOX_ENC_SAVE_MAGIC_LENGTH) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); + return NULL; + } + + if (crypto_memcmp(tox_options_get_savedata_data(options), TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_ENCRYPTED); + return NULL; + } + + load_savedata_tox = 1; + } + + m_options.ipv6enabled = tox_options_get_ipv6_enabled(options); + m_options.udp_disabled = !tox_options_get_udp_enabled(options); + m_options.port_range[0] = tox_options_get_start_port(options); + m_options.port_range[1] = tox_options_get_end_port(options); + m_options.tcp_server_port = tox_options_get_tcp_port(options); + m_options.hole_punching_enabled = tox_options_get_hole_punching_enabled(options); + m_options.local_discovery_enabled = tox_options_get_local_discovery_enabled(options); + + m_options.log_callback = (logger_cb *)tox_options_get_log_callback(options); + m_options.log_user_data = tox_options_get_log_user_data(options); + + switch (tox_options_get_proxy_type(options)) { + case TOX_PROXY_TYPE_HTTP: + m_options.proxy_info.proxy_type = TCP_PROXY_HTTP; + break; + + case TOX_PROXY_TYPE_SOCKS5: + m_options.proxy_info.proxy_type = TCP_PROXY_SOCKS5; + break; + + case TOX_PROXY_TYPE_NONE: + m_options.proxy_info.proxy_type = TCP_PROXY_NONE; + break; + + default: + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_TYPE); + return NULL; + } + + if (m_options.proxy_info.proxy_type != TCP_PROXY_NONE) { + if (tox_options_get_proxy_port(options) == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_PORT); + return NULL; + } + + ip_init(&m_options.proxy_info.ip_port.ip, m_options.ipv6enabled); + + if (m_options.ipv6enabled) { + m_options.proxy_info.ip_port.ip.family = TOX_AF_UNSPEC; + } + + if (!addr_resolve_or_parse_ip(tox_options_get_proxy_host(options), &m_options.proxy_info.ip_port.ip, NULL)) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PROXY_BAD_HOST); + // TODO(irungentoo): TOX_ERR_NEW_PROXY_NOT_FOUND if domain. + return NULL; + } + + m_options.proxy_info.ip_port.port = net_htons(tox_options_get_proxy_port(options)); + } + } + + unsigned int m_error; + Messenger *m = new_messenger(&m_options, &m_error); + + if (!new_groupchats(m)) { + kill_messenger(m); + + if (m_error == MESSENGER_ERROR_PORT) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC); + } else if (m_error == MESSENGER_ERROR_TCP_SERVER) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_PORT_ALLOC); + } else { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_MALLOC); + } + + return NULL; + } + + if (load_savedata_tox + && messenger_load(m, tox_options_get_savedata_data(options), tox_options_get_savedata_length(options)) == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_LOAD_BAD_FORMAT); + } else if (load_savedata_sk) { + load_secret_key(m->net_crypto, tox_options_get_savedata_data(options)); + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK); + } else { + SET_ERROR_PARAMETER(error, TOX_ERR_NEW_OK); + } + + return m; +} + +void tox_kill(Tox *tox) +{ + if (tox == NULL) { + return; + } + + Messenger *m = tox; + kill_groupchats((Group_Chats *)m->conferences_object); + kill_messenger(m); +} + +size_t tox_get_savedata_size(const Tox *tox) +{ + const Messenger *m = tox; + return messenger_size(m); +} + +void tox_get_savedata(const Tox *tox, uint8_t *savedata) +{ + if (savedata) { + const Messenger *m = tox; + messenger_save(m, savedata); + } +} + +bool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error) +{ + if (!address || !public_key) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL); + return 0; + } + + if (port == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT); + return 0; + } + + IP_Port *root; + + int32_t count = net_getipport(address, &root, TOX_SOCK_DGRAM); + + if (count == -1) { + net_freeipport(root); + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); + return 0; + } + + unsigned int i; + + for (i = 0; i < count; i++) { + root[i].port = net_htons(port); + + Messenger *m = tox; + onion_add_bs_path_node(m->onion_c, root[i], public_key); + DHT_bootstrap(m->dht, root[i], public_key); + } + + net_freeipport(root); + + if (count) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK); + return 1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); + return 0; +} + +bool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, + TOX_ERR_BOOTSTRAP *error) +{ + if (!address || !public_key) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_NULL); + return 0; + } + + if (port == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_PORT); + return 0; + } + + IP_Port *root; + + int32_t count = net_getipport(address, &root, TOX_SOCK_STREAM); + + if (count == -1) { + net_freeipport(root); + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); + return 0; + } + + unsigned int i; + + for (i = 0; i < count; i++) { + root[i].port = net_htons(port); + + Messenger *m = tox; + add_tcp_relay(m->net_crypto, root[i], public_key); + } + + net_freeipport(root); + + if (count) { + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_OK); + return 1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_BOOTSTRAP_BAD_HOST); + return 0; +} + +TOX_CONNECTION tox_self_get_connection_status(const Tox *tox) +{ + const Messenger *m = tox; + + unsigned int ret = onion_connection_status(m->onion_c); + + if (ret == 2) { + return TOX_CONNECTION_UDP; + } + + if (ret == 1) { + return TOX_CONNECTION_TCP; + } + + return TOX_CONNECTION_NONE; +} + + +void tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *callback) +{ + Messenger *m = tox; + m_callback_core_connection(m, (void (*)(Messenger *, unsigned int, void *))callback); +} + +uint32_t tox_iteration_interval(const Tox *tox) +{ + const Messenger *m = tox; + return messenger_run_interval(m); +} + +void tox_iterate(Tox *tox, void *user_data) +{ + Messenger *m = tox; + do_messenger(m, user_data); + do_groupchats((Group_Chats *)m->conferences_object, user_data); +} + +void tox_self_get_address(const Tox *tox, uint8_t *address) +{ + if (address) { + const Messenger *m = tox; + getaddress(m, address); + } +} + +void tox_self_set_nospam(Tox *tox, uint32_t nospam) +{ + Messenger *m = tox; + set_nospam(&(m->fr), net_htonl(nospam)); +} + +uint32_t tox_self_get_nospam(const Tox *tox) +{ + const Messenger *m = tox; + return net_ntohl(get_nospam(&(m->fr))); +} + +void tox_self_get_public_key(const Tox *tox, uint8_t *public_key) +{ + const Messenger *m = tox; + + if (public_key) { + memcpy(public_key, m->net_crypto->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + } +} + +void tox_self_get_secret_key(const Tox *tox, uint8_t *secret_key) +{ + const Messenger *m = tox; + + if (secret_key) { + memcpy(secret_key, m->net_crypto->self_secret_key, CRYPTO_SECRET_KEY_SIZE); + } +} + +bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error) +{ + if (!name && length != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL); + return 0; + } + + Messenger *m = tox; + + if (setname(m, name, length) == 0) { + // TODO(irungentoo): function to set different per group names? + send_name_all_groups((Group_Chats *)m->conferences_object); + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK); + return 1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG); + return 0; +} + +size_t tox_self_get_name_size(const Tox *tox) +{ + const Messenger *m = tox; + return m_get_self_name_size(m); +} + +void tox_self_get_name(const Tox *tox, uint8_t *name) +{ + if (name) { + const Messenger *m = tox; + getself_name(m, name); + } +} + +bool tox_self_set_status_message(Tox *tox, const uint8_t *status_message, size_t length, TOX_ERR_SET_INFO *error) +{ + if (!status_message && length != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_NULL); + return 0; + } + + Messenger *m = tox; + + if (m_set_statusmessage(m, status_message, length) == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_OK); + return 1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_SET_INFO_TOO_LONG); + return 0; +} + +size_t tox_self_get_status_message_size(const Tox *tox) +{ + const Messenger *m = tox; + return m_get_self_statusmessage_size(m); +} + +void tox_self_get_status_message(const Tox *tox, uint8_t *status_message) +{ + if (status_message) { + const Messenger *m = tox; + m_copy_self_statusmessage(m, status_message); + } +} + +void tox_self_set_status(Tox *tox, TOX_USER_STATUS status) +{ + Messenger *m = tox; + m_set_userstatus(m, status); +} + +TOX_USER_STATUS tox_self_get_status(const Tox *tox) +{ + const Messenger *m = tox; + return (TOX_USER_STATUS)m_get_self_userstatus(m); +} + +static void set_friend_error(int32_t ret, TOX_ERR_FRIEND_ADD *error) +{ + switch (ret) { + case FAERR_TOOLONG: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_TOO_LONG); + break; + + case FAERR_NOMESSAGE: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NO_MESSAGE); + break; + + case FAERR_OWNKEY: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OWN_KEY); + break; + + case FAERR_ALREADYSENT: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_ALREADY_SENT); + break; + + case FAERR_BADCHECKSUM: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_BAD_CHECKSUM); + break; + + case FAERR_SETNEWNOSPAM: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM); + break; + + case FAERR_NOMEM: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_MALLOC); + break; + } +} + +uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length, + TOX_ERR_FRIEND_ADD *error) +{ + if (!address || !message) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL); + return UINT32_MAX; + } + + Messenger *m = tox; + int32_t ret = m_addfriend(m, address, message, length); + + if (ret >= 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK); + return ret; + } + + set_friend_error(ret, error); + return UINT32_MAX; +} + +uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error) +{ + if (!public_key) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_NULL); + return UINT32_MAX; + } + + Messenger *m = tox; + int32_t ret = m_addfriend_norequest(m, public_key); + + if (ret >= 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_ADD_OK); + return ret; + } + + set_friend_error(ret, error); + return UINT32_MAX; +} + +bool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error) +{ + Messenger *m = tox; + int ret = m_delfriend(m, friend_number); + + // TODO(irungentoo): handle if realloc fails? + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_DELETE_OK); + return 1; +} + +uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error) +{ + if (!public_key) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL); + return UINT32_MAX; + } + + const Messenger *m = tox; + int32_t ret = getfriend_id(m, public_key); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND); + return UINT32_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK); + return ret; +} + +bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key, + TOX_ERR_FRIEND_GET_PUBLIC_KEY *error) +{ + if (!public_key) { + return 0; + } + + const Messenger *m = tox; + + if (get_real_pk(m, friend_number, public_key) == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK); + return 1; +} + +bool tox_friend_exists(const Tox *tox, uint32_t friend_number) +{ + const Messenger *m = tox; + return m_friend_exists(m, friend_number); +} + +uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_GET_LAST_ONLINE *error) +{ + const Messenger *m = tox; + uint64_t timestamp = m_get_last_online(m, friend_number); + + if (timestamp == UINT64_MAX) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND) + return UINT64_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_GET_LAST_ONLINE_OK); + return timestamp; +} + +size_t tox_self_get_friend_list_size(const Tox *tox) +{ + const Messenger *m = tox; + return count_friendlist(m); +} + +void tox_self_get_friend_list(const Tox *tox, uint32_t *friend_list) +{ + if (friend_list) { + const Messenger *m = tox; + // TODO(irungentoo): size parameter? + copy_friendlist(m, friend_list, tox_self_get_friend_list_size(tox)); + } +} + +size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + int ret = m_get_name_size(m, friend_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return SIZE_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return ret; +} + +bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error) +{ + if (!name) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL); + return 0; + } + + const Messenger *m = tox; + int ret = getname(m, friend_number, name); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return 1; +} + +void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *callback) +{ + Messenger *m = tox; + m_callback_namechange(m, callback); +} + +size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + int ret = m_get_statusmessage_size(m, friend_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return SIZE_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return ret; +} + +bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *status_message, + TOX_ERR_FRIEND_QUERY *error) +{ + if (!status_message) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_NULL); + return 0; + } + + const Messenger *m = tox; + // TODO(irungentoo): size parameter? + int ret = m_copy_statusmessage(m, friend_number, status_message, m_get_statusmessage_size(m, friend_number)); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return 1; +} + +void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *callback) +{ + Messenger *m = tox; + m_callback_statusmessage(m, callback); +} + +TOX_USER_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + + int ret = m_get_userstatus(m, friend_number); + + if (ret == USERSTATUS_INVALID) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return (TOX_USER_STATUS)(TOX_USER_STATUS_BUSY + 1); + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return (TOX_USER_STATUS)ret; +} + +void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *callback) +{ + Messenger *m = tox; + m_callback_userstatus(m, (void (*)(Messenger *, uint32_t, unsigned int, void *))callback); +} + +TOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + + int ret = m_get_friend_connectionstatus(m, friend_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return TOX_CONNECTION_NONE; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return (TOX_CONNECTION)ret; +} + +void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *callback) +{ + Messenger *m = tox; + m_callback_connectionstatus(m, (void (*)(Messenger *, uint32_t, unsigned int, void *))callback); +} + +bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error) +{ + const Messenger *m = tox; + int ret = m_get_istyping(m, friend_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_QUERY_OK); + return !!ret; +} + +void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *callback) +{ + Messenger *m = tox; + m_callback_typingchange(m, callback); +} + +bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool typing, TOX_ERR_SET_TYPING *error) +{ + Messenger *m = tox; + + if (m_set_usertyping(m, friend_number, typing) == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_SET_TYPING_OK); + return 1; +} + +static void set_message_error(int ret, TOX_ERR_FRIEND_SEND_MESSAGE *error) +{ + switch (ret) { + case 0: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_OK); + break; + + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND); + break; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG); + break; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED); + break; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ); + break; + + case -5: + /* can't happen */ + break; + } +} + +uint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, + size_t length, TOX_ERR_FRIEND_SEND_MESSAGE *error) +{ + if (!message) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_NULL); + return 0; + } + + if (!length) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY); + return 0; + } + + Messenger *m = tox; + uint32_t message_id = 0; + set_message_error(m_send_message_generic(m, friend_number, type, message, length, &message_id), error); + return message_id; +} + +void tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *callback) +{ + Messenger *m = tox; + m_callback_read_receipt(m, callback); +} + +void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *callback) +{ + Messenger *m = tox; + m_callback_friendrequest(m, callback); +} + +void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *callback) +{ + Messenger *m = tox; + m_callback_friendmessage(m, (void (*)(Messenger *, uint32_t, unsigned int, const uint8_t *, size_t, void *))callback); +} + +bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length) +{ + if (!hash || (length && !data)) { + return 0; + } + + crypto_sha256(hash, data, length); + return 1; +} + +bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, + TOX_ERR_FILE_CONTROL *error) +{ + Messenger *m = tox; + int ret = file_control(m, friend_number, file_number, control); + + if (ret == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_OK); + return 1; + } + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND); + return 0; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED); + return 0; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_FOUND); + return 0; + + case -4: + /* can't happen */ + return 0; + + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_ALREADY_PAUSED); + return 0; + + case -6: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_DENIED); + return 0; + + case -7: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_NOT_PAUSED); + return 0; + + case -8: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_CONTROL_SENDQ); + return 0; + } + + /* can't happen */ + return 0; +} + +bool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, + TOX_ERR_FILE_SEEK *error) +{ + Messenger *m = tox; + int ret = file_seek(m, friend_number, file_number, position); + + if (ret == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_OK); + return 1; + } + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND); + return 0; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED); + return 0; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_NOT_FOUND); + return 0; + + case -4: // fall-through + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_DENIED); + return 0; + + case -6: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_INVALID_POSITION); + return 0; + + case -8: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEEK_SENDQ); + return 0; + } + + /* can't happen */ + return 0; +} + +void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *callback) +{ + Messenger *m = tox; + callback_file_control(m, (void (*)(Messenger *, uint32_t, uint32_t, unsigned int, void *))callback); +} + +bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id, + TOX_ERR_FILE_GET *error) +{ + if (!file_id) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NULL); + return 0; + } + + const Messenger *m = tox; + int ret = file_get_id(m, friend_number, file_number, file_id); + + if (ret == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_OK); + return 1; + } + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_FRIEND_NOT_FOUND); + } else { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_GET_NOT_FOUND); + } + + return 0; +} + +uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id, + const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error) +{ + if (filename_length && !filename) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NULL); + return UINT32_MAX; + } + + uint8_t f_id[FILE_ID_LENGTH]; + + if (!file_id) { + /* Tox keys are 32 bytes like FILE_ID_LENGTH. */ + new_symmetric_key(f_id); + file_id = f_id; + } + + Messenger *m = tox; + long int file_num = new_filesender(m, friend_number, kind, file_size, file_id, filename, filename_length); + + if (file_num >= 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_OK); + return file_num; + } + + switch (file_num) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND); + return UINT32_MAX; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_NAME_TOO_LONG); + return UINT32_MAX; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_TOO_MANY); + return UINT32_MAX; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED); + return UINT32_MAX; + } + + /* can't happen */ + return UINT32_MAX; +} + +bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data, + size_t length, TOX_ERR_FILE_SEND_CHUNK *error) +{ + Messenger *m = tox; + int ret = file_data(m, friend_number, file_number, position, data, length); + + if (ret == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_OK); + return 1; + } + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND); + return 0; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED); + return 0; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND); + return 0; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING); + return 0; + + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH); + return 0; + + case -6: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_SENDQ); + return 0; + + case -7: + SET_ERROR_PARAMETER(error, TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION); + return 0; + } + + /* can't happen */ + return 0; +} + +void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *callback) +{ + Messenger *m = tox; + callback_file_reqchunk(m, callback); +} + +void tox_callback_file_recv(Tox *tox, tox_file_recv_cb *callback) +{ + Messenger *m = tox; + callback_file_sendrequest(m, callback); +} + +void tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *callback) +{ + Messenger *m = tox; + callback_file_data(m, callback); +} + +void tox_callback_conference_invite(Tox *tox, tox_conference_invite_cb *callback) +{ + Messenger *m = tox; + g_callback_group_invite((Group_Chats *)m->conferences_object, (void (*)(Messenger * m, uint32_t, int, const uint8_t *, + size_t, + void *))callback); +} + +void tox_callback_conference_message(Tox *tox, tox_conference_message_cb *callback) +{ + Messenger *m = tox; + g_callback_group_message((Group_Chats *)m->conferences_object, (void (*)(Messenger * m, uint32_t, uint32_t, int, + const uint8_t *, + size_t, void *))callback); +} + +void tox_callback_conference_title(Tox *tox, tox_conference_title_cb *callback) +{ + Messenger *m = tox; + g_callback_group_title((Group_Chats *)m->conferences_object, callback); +} + +void tox_callback_conference_namelist_change(Tox *tox, tox_conference_namelist_change_cb *callback) +{ + Messenger *m = tox; + g_callback_group_namelistchange((Group_Chats *)m->conferences_object, (void (*)(struct Messenger *, int, int, uint8_t, + void *))callback); +} + +uint32_t tox_conference_new(Tox *tox, TOX_ERR_CONFERENCE_NEW *error) +{ + Messenger *m = tox; + int ret = add_groupchat((Group_Chats *)m->conferences_object, GROUPCHAT_TYPE_TEXT); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_INIT); + return UINT32_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_NEW_OK); + return ret; +} + +bool tox_conference_delete(Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_DELETE *error) +{ + Messenger *m = tox; + int ret = del_groupchat((Group_Chats *)m->conferences_object, conference_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_DELETE_OK); + return true; +} + +uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_number_peers((Group_Chats *)m->conferences_object, conference_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return UINT32_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return ret; +} + +size_t tox_conference_peer_get_name_size(const Tox *tox, uint32_t conference_number, uint32_t peer_number, + TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_peername_size((Group_Chats *)m->conferences_object, conference_number, peer_number); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return -1; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return -1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return ret; +} + +bool tox_conference_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t peer_number, uint8_t *name, + TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_peername((Group_Chats *)m->conferences_object, conference_number, peer_number, name); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return true; +} + +bool tox_conference_peer_get_public_key(const Tox *tox, uint32_t conference_number, uint32_t peer_number, + uint8_t *public_key, TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_peer_pubkey((Group_Chats *)m->conferences_object, conference_number, peer_number, public_key); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return true; +} + +bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_number, uint32_t peer_number, + TOX_ERR_CONFERENCE_PEER_QUERY *error) +{ + const Messenger *m = tox; + int ret = group_peernumber_is_ours((Group_Chats *)m->conferences_object, conference_number, peer_number); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND); + return false; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_NO_CONNECTION); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_PEER_QUERY_OK); + return ret; +} + +bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number, + TOX_ERR_CONFERENCE_INVITE *error) +{ + Messenger *m = tox; + int ret = invite_friend((Group_Chats *)m->conferences_object, friend_number, conference_number); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_FAIL_SEND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_INVITE_OK); + return true; +} + +uint32_t tox_conference_join(Tox *tox, uint32_t friend_number, const uint8_t *cookie, size_t length, + TOX_ERR_CONFERENCE_JOIN *error) +{ + Messenger *m = tox; + int ret = join_groupchat((Group_Chats *)m->conferences_object, friend_number, GROUPCHAT_TYPE_TEXT, cookie, length); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH); + return UINT32_MAX; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE); + return UINT32_MAX; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FRIEND_NOT_FOUND); + return UINT32_MAX; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_DUPLICATE); + return UINT32_MAX; + + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_INIT_FAIL); + return UINT32_MAX; + + case -6: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_FAIL_SEND); + return UINT32_MAX; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_JOIN_OK); + return ret; +} + +bool tox_conference_send_message(Tox *tox, uint32_t conference_number, TOX_MESSAGE_TYPE type, const uint8_t *message, + size_t length, TOX_ERR_CONFERENCE_SEND_MESSAGE *error) +{ + Messenger *m = tox; + int ret = 0; + + if (type == TOX_MESSAGE_TYPE_NORMAL) { + ret = group_message_send((Group_Chats *)m->conferences_object, conference_number, message, length); + } else { + ret = group_action_send((Group_Chats *)m->conferences_object, conference_number, message, length); + } + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_TOO_LONG); + return false; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION); + return false; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_FAIL_SEND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_SEND_MESSAGE_OK); + return true; +} + +size_t tox_conference_get_title_size(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_TITLE *error) +{ + const Messenger *m = tox; + int ret = group_title_get_size((Group_Chats *)m->conferences_object, conference_number); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND); + return -1; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH); + return -1; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK); + return ret; +} + +bool tox_conference_get_title(const Tox *tox, uint32_t conference_number, uint8_t *title, + TOX_ERR_CONFERENCE_TITLE *error) +{ + const Messenger *m = tox; + int ret = group_title_get((Group_Chats *)m->conferences_object, conference_number, title); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK); + return true; +} + +bool tox_conference_set_title(Tox *tox, uint32_t conference_number, const uint8_t *title, size_t length, + TOX_ERR_CONFERENCE_TITLE *error) +{ + Messenger *m = tox; + int ret = group_title_send((Group_Chats *)m->conferences_object, conference_number, title, length); + + switch (ret) { + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND); + return false; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH); + return false; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_FAIL_SEND); + return false; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_TITLE_OK); + return true; +} + +size_t tox_conference_get_chatlist_size(const Tox *tox) +{ + const Messenger *m = tox; + return count_chatlist((Group_Chats *)m->conferences_object); +} + +void tox_conference_get_chatlist(const Tox *tox, uint32_t *chatlist) +{ + const Messenger *m = tox; + size_t list_size = tox_conference_get_chatlist_size(tox); + copy_chatlist((Group_Chats *)m->conferences_object, chatlist, list_size); +} + +TOX_CONFERENCE_TYPE tox_conference_get_type(const Tox *tox, uint32_t conference_number, + TOX_ERR_CONFERENCE_GET_TYPE *error) +{ + const Messenger *m = tox; + int ret = group_get_type((Group_Chats *)m->conferences_object, conference_number); + + if (ret == -1) { + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND); + return (TOX_CONFERENCE_TYPE)ret; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_CONFERENCE_GET_TYPE_OK); + return (TOX_CONFERENCE_TYPE)ret; +} + +static void set_custom_packet_error(int ret, TOX_ERR_FRIEND_CUSTOM_PACKET *error) +{ + switch (ret) { + case 0: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_OK); + break; + + case -1: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND); + break; + + case -2: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG); + break; + + case -3: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID); + break; + + case -4: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED); + break; + + case -5: + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ); + break; + } +} + +bool tox_friend_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + TOX_ERR_FRIEND_CUSTOM_PACKET *error) +{ + if (!data) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL); + return 0; + } + + Messenger *m = tox; + + if (length == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY); + return 0; + } + + if (data[0] < (PACKET_ID_LOSSY_RANGE_START + PACKET_LOSSY_AV_RESERVED)) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID); + return 0; + } + + int ret = m_send_custom_lossy_packet(m, friend_number, data, length); + + set_custom_packet_error(ret, error); + + if (ret == 0) { + return 1; + } + + return 0; +} + +void tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *callback) +{ + Messenger *m = tox; + custom_lossy_packet_registerhandler(m, callback); +} + +bool tox_friend_send_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + TOX_ERR_FRIEND_CUSTOM_PACKET *error) +{ + if (!data) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_NULL); + return 0; + } + + Messenger *m = tox; + + if (length == 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY); + return 0; + } + + int ret = send_custom_lossless_packet(m, friend_number, data, length); + + set_custom_packet_error(ret, error); + + if (ret == 0) { + return 1; + } + + return 0; +} + +void tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *callback) +{ + Messenger *m = tox; + custom_lossless_packet_registerhandler(m, callback); +} + +void tox_self_get_dht_id(const Tox *tox, uint8_t *dht_id) +{ + if (dht_id) { + const Messenger *m = tox; + memcpy(dht_id, m->dht->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); + } +} + +uint16_t tox_self_get_udp_port(const Tox *tox, TOX_ERR_GET_PORT *error) +{ + const Messenger *m = tox; + uint16_t port = net_htons(m->net->port); + + if (port) { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK); + } else { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND); + } + + return port; +} + +uint16_t tox_self_get_tcp_port(const Tox *tox, TOX_ERR_GET_PORT *error) +{ + const Messenger *m = tox; + + if (m->tcp_server) { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_OK); + return m->options.tcp_server_port; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_GET_PORT_NOT_BOUND); + return 0; +} diff --git a/libs/libtox/src/toxcore/tox.h b/libs/libtox/src/toxcore/tox.h new file mode 100644 index 0000000000..30bc950964 --- /dev/null +++ b/libs/libtox/src/toxcore/tox.h @@ -0,0 +1,2947 @@ +/* + * The Tox public API. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef TOX_H +#define TOX_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/******************************************************************************* + * `tox.h` SHOULD *NOT* BE EDITED MANUALLY – any changes should be made to * + * `tox.api.h`, located in `toxcore/`. For instructions on how to * + * generate `tox.h` from `tox.api.h` please refer to `docs/apidsl.md` * + ******************************************************************************/ + + + +/** \page core Public core API for Tox clients. + * + * Every function that can fail takes a function-specific error code pointer + * that can be used to diagnose problems with the Tox state or the function + * arguments. The error code pointer can be NULL, which does not influence the + * function's behaviour, but can be done if the reason for failure is irrelevant + * to the client. + * + * The exception to this rule are simple allocation functions whose only failure + * mode is allocation failure. They return NULL in that case, and do not set an + * error code. + * + * Every error code type has an OK value to which functions will set their error + * code value on success. Clients can keep their error code uninitialised before + * passing it to a function. The library guarantees that after returning, the + * value pointed to by the error code pointer has been initialised. + * + * Functions with pointer parameters often have a NULL error code, meaning they + * could not perform any operation, because one of the required parameters was + * NULL. Some functions operate correctly or are defined as effectless on NULL. + * + * Some functions additionally return a value outside their + * return type domain, or a bool containing true on success and false on + * failure. + * + * All functions that take a Tox instance pointer will cause undefined behaviour + * when passed a NULL Tox pointer. + * + * All integer values are expected in host byte order. + * + * Functions with parameters with enum types cause unspecified behaviour if the + * enumeration value is outside the valid range of the type. If possible, the + * function will try to use a sane default, but there will be no error code, + * and one possible action for the function to take is to have no effect. + * + * Integer constants and the memory layout of publicly exposed structs are not + * part of the ABI. + */ +/** \subsection events Events and callbacks + * + * Events are handled by callbacks. One callback can be registered per event. + * All events have a callback function type named `tox_{event}_cb` and a + * function to register it named `tox_callback_{event}`. Passing a NULL + * callback will result in no callback being registered for that event. Only + * one callback per event can be registered, so if a client needs multiple + * event listeners, it needs to implement the dispatch functionality itself. + * + * The last argument to a callback is the user data pointer. It is passed from + * tox_iterate to each callback in sequence. + * + * The user data pointer is never stored or dereferenced by any library code, so + * can be any pointer, including NULL. Callbacks must all operate on the same + * object type. In the apidsl code (tox.in.h), this is denoted with `any`. The + * `any` in tox_iterate must be the same `any` as in all callbacks. In C, + * lacking parametric polymorphism, this is a pointer to void. + * + * Old style callbacks that are registered together with a user data pointer + * receive that pointer as argument when they are called. They can each have + * their own user data pointer of their own type. + */ +/** \subsection threading Threading implications + * + * It is possible to run multiple concurrent threads with a Tox instance for + * each thread. It is also possible to run all Tox instances in the same thread. + * A common way to run Tox (multiple or single instance) is to have one thread + * running a simple tox_iterate loop, sleeping for tox_iteration_interval + * milliseconds on each iteration. + * + * If you want to access a single Tox instance from multiple threads, access + * to the instance must be synchronised. While multiple threads can concurrently + * access multiple different Tox instances, no more than one API function can + * operate on a single instance at any given time. + * + * Functions that write to variable length byte arrays will always have a size + * function associated with them. The result of this size function is only valid + * until another mutating function (one that takes a pointer to non-const Tox) + * is called. Thus, clients must ensure that no other thread calls a mutating + * function between the call to the size function and the call to the retrieval + * function. + * + * E.g. to get the current nickname, one would write + * + * \code + * size_t length = tox_self_get_name_size(tox); + * uint8_t *name = malloc(length); + * if (!name) abort(); + * tox_self_get_name(tox, name); + * \endcode + * + * If any other thread calls tox_self_set_name while this thread is allocating + * memory, the length may have become invalid, and the call to + * tox_self_get_name may cause undefined behaviour. + */ +/** + * The Tox instance type. All the state associated with a connection is held + * within the instance. Multiple instances can exist and operate concurrently. + * The maximum number of Tox instances that can exist on a single network + * device is limited. Note that this is not just a per-process limit, since the + * limiting factor is the number of usable ports on a device. + */ +#ifndef TOX_DEFINED +#define TOX_DEFINED +typedef struct Tox Tox; +#endif /* TOX_DEFINED */ + + +/******************************************************************************* + * + * :: API version + * + ******************************************************************************/ + + + +/** + * The major version number. Incremented when the API or ABI changes in an + * incompatible way. + * + * The function variants of these constants return the version number of the + * library. They can be used to display the Tox library version or to check + * whether the client is compatible with the dynamically linked version of Tox. + */ +#define TOX_VERSION_MAJOR 0 + +uint32_t tox_version_major(void); + +/** + * The minor version number. Incremented when functionality is added without + * breaking the API or ABI. Set to 0 when the major version number is + * incremented. + */ +#define TOX_VERSION_MINOR 1 + +uint32_t tox_version_minor(void); + +/** + * The patch or revision number. Incremented when bugfixes are applied without + * changing any functionality or API or ABI. + */ +#define TOX_VERSION_PATCH 10 + +uint32_t tox_version_patch(void); + +/** + * A macro to check at preprocessing time whether the client code is compatible + * with the installed version of Tox. Leading zeros in the version number are + * ignored. E.g. 0.1.5 is to 0.1.4 what 1.5 is to 1.4, that is: it can add new + * features, but can't break the API. + */ +#define TOX_VERSION_IS_API_COMPATIBLE(MAJOR, MINOR, PATCH) \ + (TOX_VERSION_MAJOR > 0 && TOX_VERSION_MAJOR == MAJOR) && ( \ + /* 1.x.x, 2.x.x, etc. with matching major version. */ \ + TOX_VERSION_MINOR > MINOR || \ + TOX_VERSION_MINOR == MINOR && TOX_VERSION_PATCH >= PATCH \ + ) || (TOX_VERSION_MAJOR == 0 && MAJOR == 0) && ( \ + /* 0.x.x makes minor behave like major above. */ \ + (TOX_VERSION_MINOR > 0 && TOX_VERSION_MINOR == MINOR) && ( \ + TOX_VERSION_PATCH >= PATCH \ + ) || (TOX_VERSION_MINOR == 0 && MINOR == 0) && ( \ + /* 0.0.x and 0.0.y are only compatible if x == y. */ \ + TOX_VERSION_PATCH == PATCH \ + ) \ + ) + +/** + * Return whether the compiled library version is compatible with the passed + * version numbers. + */ +bool tox_version_is_compatible(uint32_t major, uint32_t minor, uint32_t patch); + +/** + * A convenience macro to call tox_version_is_compatible with the currently + * compiling API version. + */ +#define TOX_VERSION_IS_ABI_COMPATIBLE() \ + tox_version_is_compatible(TOX_VERSION_MAJOR, TOX_VERSION_MINOR, TOX_VERSION_PATCH) + + +/******************************************************************************* + * + * :: Numeric constants + * + * The values of these are not part of the ABI. Prefer to use the function + * versions of them for code that should remain compatible with future versions + * of toxcore. + * + ******************************************************************************/ + + + +/** + * The size of a Tox Public Key in bytes. + */ +#define TOX_PUBLIC_KEY_SIZE 32 + +uint32_t tox_public_key_size(void); + +/** + * The size of a Tox Secret Key in bytes. + */ +#define TOX_SECRET_KEY_SIZE 32 + +uint32_t tox_secret_key_size(void); + +/** + * The size of the nospam in bytes when written in a Tox address. + */ +#define TOX_NOSPAM_SIZE (sizeof(uint32_t)) + +uint32_t tox_nospam_size(void); + +/** + * The size of a Tox address in bytes. Tox addresses are in the format + * [Public Key (TOX_PUBLIC_KEY_SIZE bytes)][nospam (4 bytes)][checksum (2 bytes)]. + * + * The checksum is computed over the Public Key and the nospam value. The first + * byte is an XOR of all the even bytes (0, 2, 4, ...), the second byte is an + * XOR of all the odd bytes (1, 3, 5, ...) of the Public Key and nospam. + */ +#define TOX_ADDRESS_SIZE (TOX_PUBLIC_KEY_SIZE + TOX_NOSPAM_SIZE + sizeof(uint16_t)) + +uint32_t tox_address_size(void); + +/** + * Maximum length of a nickname in bytes. + */ +#define TOX_MAX_NAME_LENGTH 128 + +uint32_t tox_max_name_length(void); + +/** + * Maximum length of a status message in bytes. + */ +#define TOX_MAX_STATUS_MESSAGE_LENGTH 1007 + +uint32_t tox_max_status_message_length(void); + +/** + * Maximum length of a friend request message in bytes. + */ +#define TOX_MAX_FRIEND_REQUEST_LENGTH 1016 + +uint32_t tox_max_friend_request_length(void); + +/** + * Maximum length of a single message after which it should be split. + */ +#define TOX_MAX_MESSAGE_LENGTH 1372 + +uint32_t tox_max_message_length(void); + +/** + * Maximum size of custom packets. TODO(iphydf): should be LENGTH? + */ +#define TOX_MAX_CUSTOM_PACKET_SIZE 1373 + +uint32_t tox_max_custom_packet_size(void); + +/** + * The number of bytes in a hash generated by tox_hash. + */ +#define TOX_HASH_LENGTH 32 + +uint32_t tox_hash_length(void); + +/** + * The number of bytes in a file id. + */ +#define TOX_FILE_ID_LENGTH 32 + +uint32_t tox_file_id_length(void); + +/** + * Maximum file name length for file transfers. + */ +#define TOX_MAX_FILENAME_LENGTH 255 + +uint32_t tox_max_filename_length(void); + + +/******************************************************************************* + * + * :: Global enumerations + * + ******************************************************************************/ + + + +/** + * Represents the possible statuses a client can have. + */ +typedef enum TOX_USER_STATUS { + + /** + * User is online and available. + */ + TOX_USER_STATUS_NONE, + + /** + * User is away. Clients can set this e.g. after a user defined + * inactivity time. + */ + TOX_USER_STATUS_AWAY, + + /** + * User is busy. Signals to other clients that this client does not + * currently wish to communicate. + */ + TOX_USER_STATUS_BUSY, + +} TOX_USER_STATUS; + + +/** + * Represents message types for tox_friend_send_message and conference + * messages. + */ +typedef enum TOX_MESSAGE_TYPE { + + /** + * Normal text message. Similar to PRIVMSG on IRC. + */ + TOX_MESSAGE_TYPE_NORMAL, + + /** + * A message describing an user action. This is similar to /me (CTCP ACTION) + * on IRC. + */ + TOX_MESSAGE_TYPE_ACTION, + +} TOX_MESSAGE_TYPE; + + + +/******************************************************************************* + * + * :: Startup options + * + ******************************************************************************/ + + + +/** + * Type of proxy used to connect to TCP relays. + */ +typedef enum TOX_PROXY_TYPE { + + /** + * Don't use a proxy. + */ + TOX_PROXY_TYPE_NONE, + + /** + * HTTP proxy using CONNECT. + */ + TOX_PROXY_TYPE_HTTP, + + /** + * SOCKS proxy for simple socket pipes. + */ + TOX_PROXY_TYPE_SOCKS5, + +} TOX_PROXY_TYPE; + + +/** + * Type of savedata to create the Tox instance from. + */ +typedef enum TOX_SAVEDATA_TYPE { + + /** + * No savedata. + */ + TOX_SAVEDATA_TYPE_NONE, + + /** + * Savedata is one that was obtained from tox_get_savedata. + */ + TOX_SAVEDATA_TYPE_TOX_SAVE, + + /** + * Savedata is a secret key of length TOX_SECRET_KEY_SIZE. + */ + TOX_SAVEDATA_TYPE_SECRET_KEY, + +} TOX_SAVEDATA_TYPE; + + +/** + * Severity level of log messages. + */ +typedef enum TOX_LOG_LEVEL { + + /** + * Very detailed traces including all network activity. + */ + TOX_LOG_LEVEL_TRACE, + + /** + * Debug messages such as which port we bind to. + */ + TOX_LOG_LEVEL_DEBUG, + + /** + * Informational log messages such as video call status changes. + */ + TOX_LOG_LEVEL_INFO, + + /** + * Warnings about internal inconsistency or logic errors. + */ + TOX_LOG_LEVEL_WARNING, + + /** + * Severe unexpected errors caused by external or internal inconsistency. + */ + TOX_LOG_LEVEL_ERROR, + +} TOX_LOG_LEVEL; + + +/** + * This event is triggered when the toxcore library logs an internal message. + * This is mostly useful for debugging. This callback can be called from any + * function, not just tox_iterate. This means the user data lifetime must at + * least extend between registering and unregistering it or tox_kill. + * + * Other toxcore modules such as toxav may concurrently call this callback at + * any time. Thus, user code must make sure it is equipped to handle concurrent + * execution, e.g. by employing appropriate mutex locking. + * + * @param level The severity of the log message. + * @param file The source file from which the message originated. + * @param line The source line from which the message originated. + * @param func The function from which the message originated. + * @param message The log message. + * @param user_data The user data pointer passed to tox_new in options. + */ +typedef void tox_log_cb(Tox *tox, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func, + const char *message, void *user_data); + + +/** + * This struct contains all the startup options for Tox. You must tox_options_new to + * allocate an object of this type. + * + * WARNING: Although this struct happens to be visible in the API, it is + * effectively private. Do not allocate this yourself or access members + * directly, as it *will* break binary compatibility frequently. + * + * @deprecated The memory layout of this struct (size, alignment, and field + * order) is not part of the ABI. To remain compatible, prefer to use tox_options_new to + * allocate the object and accessor functions to set the members. The struct + * will become opaque (i.e. the definition will become private) in v0.2.0. + */ +struct Tox_Options { + + /** + * The type of socket to create. + * + * If this is set to false, an IPv4 socket is created, which subsequently + * only allows IPv4 communication. + * If it is set to true, an IPv6 socket is created, allowing both IPv4 and + * IPv6 communication. + */ + bool ipv6_enabled; + + + /** + * Enable the use of UDP communication when available. + * + * Setting this to false will force Tox to use TCP only. Communications will + * need to be relayed through a TCP relay node, potentially slowing them down. + * Disabling UDP support is necessary when using anonymous proxies or Tor. + */ + bool udp_enabled; + + + /** + * Enable local network peer discovery. + * + * Disabling this will cause Tox to not look for peers on the local network. + */ + bool local_discovery_enabled; + + + /** + * Pass communications through a proxy. + */ + TOX_PROXY_TYPE proxy_type; + + + /** + * The IP address or DNS name of the proxy to be used. + * + * If used, this must be non-NULL and be a valid DNS name. The name must not + * exceed 255 characters, and be in a NUL-terminated C string format + * (255 chars + 1 NUL byte). + * + * This member is ignored (it can be NULL) if proxy_type is TOX_PROXY_TYPE_NONE. + * + * The data pointed at by this member is owned by the user, so must + * outlive the options object. + */ + const char *proxy_host; + + + /** + * The port to use to connect to the proxy server. + * + * Ports must be in the range (1, 65535). The value is ignored if + * proxy_type is TOX_PROXY_TYPE_NONE. + */ + uint16_t proxy_port; + + + /** + * The start port of the inclusive port range to attempt to use. + * + * If both start_port and end_port are 0, the default port range will be + * used: [33445, 33545]. + * + * If either start_port or end_port is 0 while the other is non-zero, the + * non-zero port will be the only port in the range. + * + * Having start_port > end_port will yield the same behavior as if start_port + * and end_port were swapped. + */ + uint16_t start_port; + + + /** + * The end port of the inclusive port range to attempt to use. + */ + uint16_t end_port; + + + /** + * The port to use for the TCP server (relay). If 0, the TCP server is + * disabled. + * + * Enabling it is not required for Tox to function properly. + * + * When enabled, your Tox instance can act as a TCP relay for other Tox + * instance. This leads to increased traffic, thus when writing a client + * it is recommended to enable TCP server only if the user has an option + * to disable it. + */ + uint16_t tcp_port; + + + /** + * Enables or disables UDP hole-punching in toxcore. (Default: enabled). + */ + bool hole_punching_enabled; + + + /** + * The type of savedata to load from. + */ + TOX_SAVEDATA_TYPE savedata_type; + + + /** + * The savedata. + * + * The data pointed at by this member is owned by the user, so must + * outlive the options object. + */ + const uint8_t *savedata_data; + + + /** + * The length of the savedata. + */ + size_t savedata_length; + + + /** + * Logging callback for the new tox instance. + */ + tox_log_cb *log_callback; + + + /** + * User data pointer passed to the logging callback. + */ + void *log_user_data; + +}; + + +bool tox_options_get_ipv6_enabled(const struct Tox_Options *options); + +void tox_options_set_ipv6_enabled(struct Tox_Options *options, bool ipv6_enabled); + +bool tox_options_get_udp_enabled(const struct Tox_Options *options); + +void tox_options_set_udp_enabled(struct Tox_Options *options, bool udp_enabled); + +bool tox_options_get_local_discovery_enabled(const struct Tox_Options *options); + +void tox_options_set_local_discovery_enabled(struct Tox_Options *options, bool local_discovery_enabled); + +TOX_PROXY_TYPE tox_options_get_proxy_type(const struct Tox_Options *options); + +void tox_options_set_proxy_type(struct Tox_Options *options, TOX_PROXY_TYPE type); + +const char *tox_options_get_proxy_host(const struct Tox_Options *options); + +void tox_options_set_proxy_host(struct Tox_Options *options, const char *host); + +uint16_t tox_options_get_proxy_port(const struct Tox_Options *options); + +void tox_options_set_proxy_port(struct Tox_Options *options, uint16_t port); + +uint16_t tox_options_get_start_port(const struct Tox_Options *options); + +void tox_options_set_start_port(struct Tox_Options *options, uint16_t start_port); + +uint16_t tox_options_get_end_port(const struct Tox_Options *options); + +void tox_options_set_end_port(struct Tox_Options *options, uint16_t end_port); + +uint16_t tox_options_get_tcp_port(const struct Tox_Options *options); + +void tox_options_set_tcp_port(struct Tox_Options *options, uint16_t tcp_port); + +bool tox_options_get_hole_punching_enabled(const struct Tox_Options *options); + +void tox_options_set_hole_punching_enabled(struct Tox_Options *options, bool hole_punching_enabled); + +TOX_SAVEDATA_TYPE tox_options_get_savedata_type(const struct Tox_Options *options); + +void tox_options_set_savedata_type(struct Tox_Options *options, TOX_SAVEDATA_TYPE type); + +const uint8_t *tox_options_get_savedata_data(const struct Tox_Options *options); + +void tox_options_set_savedata_data(struct Tox_Options *options, const uint8_t *data, size_t length); + +size_t tox_options_get_savedata_length(const struct Tox_Options *options); + +void tox_options_set_savedata_length(struct Tox_Options *options, size_t length); + +tox_log_cb *tox_options_get_log_callback(const struct Tox_Options *options); + +void tox_options_set_log_callback(struct Tox_Options *options, tox_log_cb *callback); + +void *tox_options_get_log_user_data(const struct Tox_Options *options); + +void tox_options_set_log_user_data(struct Tox_Options *options, void *user_data); + +/** + * Initialises a Tox_Options object with the default options. + * + * The result of this function is independent of the original options. All + * values will be overwritten, no values will be read (so it is permissible + * to pass an uninitialised object). + * + * If options is NULL, this function has no effect. + * + * @param options An options object to be filled with default options. + */ +void tox_options_default(struct Tox_Options *options); + +typedef enum TOX_ERR_OPTIONS_NEW { + + /** + * The function returned successfully. + */ + TOX_ERR_OPTIONS_NEW_OK, + + /** + * The function failed to allocate enough memory for the options struct. + */ + TOX_ERR_OPTIONS_NEW_MALLOC, + +} TOX_ERR_OPTIONS_NEW; + + +/** + * Allocates a new Tox_Options object and initialises it with the default + * options. This function can be used to preserve long term ABI compatibility by + * giving the responsibility of allocation and deallocation to the Tox library. + * + * Objects returned from this function must be freed using the tox_options_free + * function. + * + * @return A new Tox_Options object with default options or NULL on failure. + */ +struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error); + +/** + * Releases all resources associated with an options objects. + * + * Passing a pointer that was not returned by tox_options_new results in + * undefined behaviour. + */ +void tox_options_free(struct Tox_Options *options); + + +/******************************************************************************* + * + * :: Creation and destruction + * + ******************************************************************************/ + + + +typedef enum TOX_ERR_NEW { + + /** + * The function returned successfully. + */ + TOX_ERR_NEW_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_NEW_NULL, + + /** + * The function was unable to allocate enough memory to store the internal + * structures for the Tox object. + */ + TOX_ERR_NEW_MALLOC, + + /** + * The function was unable to bind to a port. This may mean that all ports + * have already been bound, e.g. by other Tox instances, or it may mean + * a permission error. You may be able to gather more information from errno. + */ + TOX_ERR_NEW_PORT_ALLOC, + + /** + * proxy_type was invalid. + */ + TOX_ERR_NEW_PROXY_BAD_TYPE, + + /** + * proxy_type was valid but the proxy_host passed had an invalid format + * or was NULL. + */ + TOX_ERR_NEW_PROXY_BAD_HOST, + + /** + * proxy_type was valid, but the proxy_port was invalid. + */ + TOX_ERR_NEW_PROXY_BAD_PORT, + + /** + * The proxy address passed could not be resolved. + */ + TOX_ERR_NEW_PROXY_NOT_FOUND, + + /** + * The byte array to be loaded contained an encrypted save. + */ + TOX_ERR_NEW_LOAD_ENCRYPTED, + + /** + * The data format was invalid. This can happen when loading data that was + * saved by an older version of Tox, or when the data has been corrupted. + * When loading from badly formatted data, some data may have been loaded, + * and the rest is discarded. Passing an invalid length parameter also + * causes this error. + */ + TOX_ERR_NEW_LOAD_BAD_FORMAT, + +} TOX_ERR_NEW; + + +/** + * @brief Creates and initialises a new Tox instance with the options passed. + * + * This function will bring the instance into a valid state. Running the event + * loop with a new instance will operate correctly. + * + * If loading failed or succeeded only partially, the new or partially loaded + * instance is returned and an error code is set. + * + * @param options An options object as described above. If this parameter is + * NULL, the default options are used. + * + * @see tox_iterate for the event loop. + * + * @return A new Tox instance pointer on success or NULL on failure. + */ +Tox *tox_new(const struct Tox_Options *options, TOX_ERR_NEW *error); + +/** + * Releases all resources associated with the Tox instance and disconnects from + * the network. + * + * After calling this function, the Tox pointer becomes invalid. No other + * functions can be called, and the pointer value can no longer be read. + */ +void tox_kill(Tox *tox); + +/** + * Calculates the number of bytes required to store the tox instance with + * tox_get_savedata. This function cannot fail. The result is always greater than 0. + * + * @see threading for concurrency implications. + */ +size_t tox_get_savedata_size(const Tox *tox); + +/** + * Store all information associated with the tox instance to a byte array. + * + * @param savedata A memory region large enough to store the tox instance + * data. Call tox_get_savedata_size to find the number of bytes required. If this parameter + * is NULL, this function has no effect. + */ +void tox_get_savedata(const Tox *tox, uint8_t *savedata); + + +/******************************************************************************* + * + * :: Connection lifecycle and event loop + * + ******************************************************************************/ + + + +typedef enum TOX_ERR_BOOTSTRAP { + + /** + * The function returned successfully. + */ + TOX_ERR_BOOTSTRAP_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_BOOTSTRAP_NULL, + + /** + * The address could not be resolved to an IP address, or the IP address + * passed was invalid. + */ + TOX_ERR_BOOTSTRAP_BAD_HOST, + + /** + * The port passed was invalid. The valid port range is (1, 65535). + */ + TOX_ERR_BOOTSTRAP_BAD_PORT, + +} TOX_ERR_BOOTSTRAP; + + +/** + * Sends a "get nodes" request to the given bootstrap node with IP, port, and + * public key to setup connections. + * + * This function will attempt to connect to the node using UDP. You must use + * this function even if Tox_Options.udp_enabled was set to false. + * + * @param address The hostname or IP address (IPv4 or IPv6) of the node. + * @param port The port on the host on which the bootstrap Tox instance is + * listening. + * @param public_key The long term public key of the bootstrap node + * (TOX_PUBLIC_KEY_SIZE bytes). + * @return true on success. + */ +bool tox_bootstrap(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, TOX_ERR_BOOTSTRAP *error); + +/** + * Adds additional host:port pair as TCP relay. + * + * This function can be used to initiate TCP connections to different ports on + * the same bootstrap node, or to add TCP relays without using them as + * bootstrap nodes. + * + * @param address The hostname or IP address (IPv4 or IPv6) of the TCP relay. + * @param port The port on the host on which the TCP relay is listening. + * @param public_key The long term public key of the TCP relay + * (TOX_PUBLIC_KEY_SIZE bytes). + * @return true on success. + */ +bool tox_add_tcp_relay(Tox *tox, const char *address, uint16_t port, const uint8_t *public_key, + TOX_ERR_BOOTSTRAP *error); + +/** + * Protocols that can be used to connect to the network or friends. + */ +typedef enum TOX_CONNECTION { + + /** + * There is no connection. This instance, or the friend the state change is + * about, is now offline. + */ + TOX_CONNECTION_NONE, + + /** + * A TCP connection has been established. For the own instance, this means it + * is connected through a TCP relay, only. For a friend, this means that the + * connection to that particular friend goes through a TCP relay. + */ + TOX_CONNECTION_TCP, + + /** + * A UDP connection has been established. For the own instance, this means it + * is able to send UDP packets to DHT nodes, but may still be connected to + * a TCP relay. For a friend, this means that the connection to that + * particular friend was built using direct UDP packets. + */ + TOX_CONNECTION_UDP, + +} TOX_CONNECTION; + + +/** + * Return whether we are connected to the DHT. The return value is equal to the + * last value received through the `self_connection_status` callback. + */ +TOX_CONNECTION tox_self_get_connection_status(const Tox *tox); + +/** + * @param connection_status Whether we are connected to the DHT. + */ +typedef void tox_self_connection_status_cb(Tox *tox, TOX_CONNECTION connection_status, void *user_data); + + +/** + * Set the callback for the `self_connection_status` event. Pass NULL to unset. + * + * This event is triggered whenever there is a change in the DHT connection + * state. When disconnected, a client may choose to call tox_bootstrap again, to + * reconnect to the DHT. Note that this state may frequently change for short + * amounts of time. Clients should therefore not immediately bootstrap on + * receiving a disconnect. + * + * TODO(iphydf): how long should a client wait before bootstrapping again? + */ +void tox_callback_self_connection_status(Tox *tox, tox_self_connection_status_cb *callback); + +/** + * Return the time in milliseconds before tox_iterate() should be called again + * for optimal performance. + */ +uint32_t tox_iteration_interval(const Tox *tox); + +/** + * The main loop that needs to be run in intervals of tox_iteration_interval() + * milliseconds. + */ +void tox_iterate(Tox *tox, void *user_data); + + +/******************************************************************************* + * + * :: Internal client information (Tox address/id) + * + ******************************************************************************/ + + + +/** + * Writes the Tox friend address of the client to a byte array. The address is + * not in human-readable format. If a client wants to display the address, + * formatting is required. + * + * @param address A memory region of at least TOX_ADDRESS_SIZE bytes. If this + * parameter is NULL, this function has no effect. + * @see TOX_ADDRESS_SIZE for the address format. + */ +void tox_self_get_address(const Tox *tox, uint8_t *address); + +/** + * Set the 4-byte nospam part of the address. This value is expected in host + * byte order. I.e. 0x12345678 will form the bytes [12, 34, 56, 78] in the + * nospam part of the Tox friend address. + * + * @param nospam Any 32 bit unsigned integer. + */ +void tox_self_set_nospam(Tox *tox, uint32_t nospam); + +/** + * Get the 4-byte nospam part of the address. This value is returned in host + * byte order. + */ +uint32_t tox_self_get_nospam(const Tox *tox); + +/** + * Copy the Tox Public Key (long term) from the Tox object. + * + * @param public_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If + * this parameter is NULL, this function has no effect. + */ +void tox_self_get_public_key(const Tox *tox, uint8_t *public_key); + +/** + * Copy the Tox Secret Key from the Tox object. + * + * @param secret_key A memory region of at least TOX_SECRET_KEY_SIZE bytes. If + * this parameter is NULL, this function has no effect. + */ +void tox_self_get_secret_key(const Tox *tox, uint8_t *secret_key); + + +/******************************************************************************* + * + * :: User-visible client information (nickname/status) + * + ******************************************************************************/ + + + +/** + * Common error codes for all functions that set a piece of user-visible + * client information. + */ +typedef enum TOX_ERR_SET_INFO { + + /** + * The function returned successfully. + */ + TOX_ERR_SET_INFO_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_SET_INFO_NULL, + + /** + * Information length exceeded maximum permissible size. + */ + TOX_ERR_SET_INFO_TOO_LONG, + +} TOX_ERR_SET_INFO; + + +/** + * Set the nickname for the Tox client. + * + * Nickname length cannot exceed TOX_MAX_NAME_LENGTH. If length is 0, the name + * parameter is ignored (it can be NULL), and the nickname is set back to empty. + * + * @param name A byte array containing the new nickname. + * @param length The size of the name byte array. + * + * @return true on success. + */ +bool tox_self_set_name(Tox *tox, const uint8_t *name, size_t length, TOX_ERR_SET_INFO *error); + +/** + * Return the length of the current nickname as passed to tox_self_set_name. + * + * If no nickname was set before calling this function, the name is empty, + * and this function returns 0. + * + * @see threading for concurrency implications. + */ +size_t tox_self_get_name_size(const Tox *tox); + +/** + * Write the nickname set by tox_self_set_name to a byte array. + * + * If no nickname was set before calling this function, the name is empty, + * and this function has no effect. + * + * Call tox_self_get_name_size to find out how much memory to allocate for + * the result. + * + * @param name A valid memory location large enough to hold the nickname. + * If this parameter is NULL, the function has no effect. + */ +void tox_self_get_name(const Tox *tox, uint8_t *name); + +/** + * Set the client's status message. + * + * Status message length cannot exceed TOX_MAX_STATUS_MESSAGE_LENGTH. If + * length is 0, the status parameter is ignored (it can be NULL), and the + * user status is set back to empty. + */ +bool tox_self_set_status_message(Tox *tox, const uint8_t *status_message, size_t length, TOX_ERR_SET_INFO *error); + +/** + * Return the length of the current status message as passed to tox_self_set_status_message. + * + * If no status message was set before calling this function, the status + * is empty, and this function returns 0. + * + * @see threading for concurrency implications. + */ +size_t tox_self_get_status_message_size(const Tox *tox); + +/** + * Write the status message set by tox_self_set_status_message to a byte array. + * + * If no status message was set before calling this function, the status is + * empty, and this function has no effect. + * + * Call tox_self_get_status_message_size to find out how much memory to allocate for + * the result. + * + * @param status_message A valid memory location large enough to hold the + * status message. If this parameter is NULL, the function has no effect. + */ +void tox_self_get_status_message(const Tox *tox, uint8_t *status_message); + +/** + * Set the client's user status. + * + * @param status One of the user statuses listed in the enumeration above. + */ +void tox_self_set_status(Tox *tox, TOX_USER_STATUS status); + +/** + * Returns the client's user status. + */ +TOX_USER_STATUS tox_self_get_status(const Tox *tox); + + +/******************************************************************************* + * + * :: Friend list management + * + ******************************************************************************/ + + + +typedef enum TOX_ERR_FRIEND_ADD { + + /** + * The function returned successfully. + */ + TOX_ERR_FRIEND_ADD_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_FRIEND_ADD_NULL, + + /** + * The length of the friend request message exceeded + * TOX_MAX_FRIEND_REQUEST_LENGTH. + */ + TOX_ERR_FRIEND_ADD_TOO_LONG, + + /** + * The friend request message was empty. This, and the TOO_LONG code will + * never be returned from tox_friend_add_norequest. + */ + TOX_ERR_FRIEND_ADD_NO_MESSAGE, + + /** + * The friend address belongs to the sending client. + */ + TOX_ERR_FRIEND_ADD_OWN_KEY, + + /** + * A friend request has already been sent, or the address belongs to a friend + * that is already on the friend list. + */ + TOX_ERR_FRIEND_ADD_ALREADY_SENT, + + /** + * The friend address checksum failed. + */ + TOX_ERR_FRIEND_ADD_BAD_CHECKSUM, + + /** + * The friend was already there, but the nospam value was different. + */ + TOX_ERR_FRIEND_ADD_SET_NEW_NOSPAM, + + /** + * A memory allocation failed when trying to increase the friend list size. + */ + TOX_ERR_FRIEND_ADD_MALLOC, + +} TOX_ERR_FRIEND_ADD; + + +/** + * Add a friend to the friend list and send a friend request. + * + * A friend request message must be at least 1 byte long and at most + * TOX_MAX_FRIEND_REQUEST_LENGTH. + * + * Friend numbers are unique identifiers used in all functions that operate on + * friends. Once added, a friend number is stable for the lifetime of the Tox + * object. After saving the state and reloading it, the friend numbers may not + * be the same as before. Deleting a friend creates a gap in the friend number + * set, which is filled by the next adding of a friend. Any pattern in friend + * numbers should not be relied on. + * + * If more than INT32_MAX friends are added, this function causes undefined + * behaviour. + * + * @param address The address of the friend (returned by tox_self_get_address of + * the friend you wish to add) it must be TOX_ADDRESS_SIZE bytes. + * @param message The message that will be sent along with the friend request. + * @param length The length of the data byte array. + * + * @return the friend number on success, UINT32_MAX on failure. + */ +uint32_t tox_friend_add(Tox *tox, const uint8_t *address, const uint8_t *message, size_t length, + TOX_ERR_FRIEND_ADD *error); + +/** + * Add a friend without sending a friend request. + * + * This function is used to add a friend in response to a friend request. If the + * client receives a friend request, it can be reasonably sure that the other + * client added this client as a friend, eliminating the need for a friend + * request. + * + * This function is also useful in a situation where both instances are + * controlled by the same entity, so that this entity can perform the mutual + * friend adding. In this case, there is no need for a friend request, either. + * + * @param public_key A byte array of length TOX_PUBLIC_KEY_SIZE containing the + * Public Key (not the Address) of the friend to add. + * + * @return the friend number on success, UINT32_MAX on failure. + * @see tox_friend_add for a more detailed description of friend numbers. + */ +uint32_t tox_friend_add_norequest(Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_ADD *error); + +typedef enum TOX_ERR_FRIEND_DELETE { + + /** + * The function returned successfully. + */ + TOX_ERR_FRIEND_DELETE_OK, + + /** + * There was no friend with the given friend number. No friends were deleted. + */ + TOX_ERR_FRIEND_DELETE_FRIEND_NOT_FOUND, + +} TOX_ERR_FRIEND_DELETE; + + +/** + * Remove a friend from the friend list. + * + * This does not notify the friend of their deletion. After calling this + * function, this client will appear offline to the friend and no communication + * can occur between the two. + * + * @param friend_number Friend number for the friend to be deleted. + * + * @return true on success. + */ +bool tox_friend_delete(Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_DELETE *error); + + +/******************************************************************************* + * + * :: Friend list queries + * + ******************************************************************************/ + + + +typedef enum TOX_ERR_FRIEND_BY_PUBLIC_KEY { + + /** + * The function returned successfully. + */ + TOX_ERR_FRIEND_BY_PUBLIC_KEY_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_FRIEND_BY_PUBLIC_KEY_NULL, + + /** + * No friend with the given Public Key exists on the friend list. + */ + TOX_ERR_FRIEND_BY_PUBLIC_KEY_NOT_FOUND, + +} TOX_ERR_FRIEND_BY_PUBLIC_KEY; + + +/** + * Return the friend number associated with that Public Key. + * + * @return the friend number on success, UINT32_MAX on failure. + * @param public_key A byte array containing the Public Key. + */ +uint32_t tox_friend_by_public_key(const Tox *tox, const uint8_t *public_key, TOX_ERR_FRIEND_BY_PUBLIC_KEY *error); + +/** + * Checks if a friend with the given friend number exists and returns true if + * it does. + */ +bool tox_friend_exists(const Tox *tox, uint32_t friend_number); + +/** + * Return the number of friends on the friend list. + * + * This function can be used to determine how much memory to allocate for + * tox_self_get_friend_list. + */ +size_t tox_self_get_friend_list_size(const Tox *tox); + +/** + * Copy a list of valid friend numbers into an array. + * + * Call tox_self_get_friend_list_size to determine the number of elements to allocate. + * + * @param friend_list A memory region with enough space to hold the friend + * list. If this parameter is NULL, this function has no effect. + */ +void tox_self_get_friend_list(const Tox *tox, uint32_t *friend_list); + +typedef enum TOX_ERR_FRIEND_GET_PUBLIC_KEY { + + /** + * The function returned successfully. + */ + TOX_ERR_FRIEND_GET_PUBLIC_KEY_OK, + + /** + * No friend with the given number exists on the friend list. + */ + TOX_ERR_FRIEND_GET_PUBLIC_KEY_FRIEND_NOT_FOUND, + +} TOX_ERR_FRIEND_GET_PUBLIC_KEY; + + +/** + * Copies the Public Key associated with a given friend number to a byte array. + * + * @param friend_number The friend number you want the Public Key of. + * @param public_key A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If + * this parameter is NULL, this function has no effect. + * + * @return true on success. + */ +bool tox_friend_get_public_key(const Tox *tox, uint32_t friend_number, uint8_t *public_key, + TOX_ERR_FRIEND_GET_PUBLIC_KEY *error); + +typedef enum TOX_ERR_FRIEND_GET_LAST_ONLINE { + + /** + * The function returned successfully. + */ + TOX_ERR_FRIEND_GET_LAST_ONLINE_OK, + + /** + * No friend with the given number exists on the friend list. + */ + TOX_ERR_FRIEND_GET_LAST_ONLINE_FRIEND_NOT_FOUND, + +} TOX_ERR_FRIEND_GET_LAST_ONLINE; + + +/** + * Return a unix-time timestamp of the last time the friend associated with a given + * friend number was seen online. This function will return UINT64_MAX on error. + * + * @param friend_number The friend number you want to query. + */ +uint64_t tox_friend_get_last_online(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_GET_LAST_ONLINE *error); + + +/******************************************************************************* + * + * :: Friend-specific state queries (can also be received through callbacks) + * + ******************************************************************************/ + + + +/** + * Common error codes for friend state query functions. + */ +typedef enum TOX_ERR_FRIEND_QUERY { + + /** + * The function returned successfully. + */ + TOX_ERR_FRIEND_QUERY_OK, + + /** + * The pointer parameter for storing the query result (name, message) was + * NULL. Unlike the `_self_` variants of these functions, which have no effect + * when a parameter is NULL, these functions return an error in that case. + */ + TOX_ERR_FRIEND_QUERY_NULL, + + /** + * The friend_number did not designate a valid friend. + */ + TOX_ERR_FRIEND_QUERY_FRIEND_NOT_FOUND, + +} TOX_ERR_FRIEND_QUERY; + + +/** + * Return the length of the friend's name. If the friend number is invalid, the + * return value is unspecified. + * + * The return value is equal to the `length` argument received by the last + * `friend_name` callback. + */ +size_t tox_friend_get_name_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); + +/** + * Write the name of the friend designated by the given friend number to a byte + * array. + * + * Call tox_friend_get_name_size to determine the allocation size for the `name` + * parameter. + * + * The data written to `name` is equal to the data received by the last + * `friend_name` callback. + * + * @param name A valid memory region large enough to store the friend's name. + * + * @return true on success. + */ +bool tox_friend_get_name(const Tox *tox, uint32_t friend_number, uint8_t *name, TOX_ERR_FRIEND_QUERY *error); + +/** + * @param friend_number The friend number of the friend whose name changed. + * @param name A byte array containing the same data as + * tox_friend_get_name would write to its `name` parameter. + * @param length A value equal to the return value of + * tox_friend_get_name_size. + */ +typedef void tox_friend_name_cb(Tox *tox, uint32_t friend_number, const uint8_t *name, size_t length, void *user_data); + + +/** + * Set the callback for the `friend_name` event. Pass NULL to unset. + * + * This event is triggered when a friend changes their name. + */ +void tox_callback_friend_name(Tox *tox, tox_friend_name_cb *callback); + +/** + * Return the length of the friend's status message. If the friend number is + * invalid, the return value is SIZE_MAX. + */ +size_t tox_friend_get_status_message_size(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); + +/** + * Write the status message of the friend designated by the given friend number to a byte + * array. + * + * Call tox_friend_get_status_message_size to determine the allocation size for the `status_name` + * parameter. + * + * The data written to `status_message` is equal to the data received by the last + * `friend_status_message` callback. + * + * @param status_message A valid memory region large enough to store the friend's status message. + */ +bool tox_friend_get_status_message(const Tox *tox, uint32_t friend_number, uint8_t *status_message, + TOX_ERR_FRIEND_QUERY *error); + +/** + * @param friend_number The friend number of the friend whose status message + * changed. + * @param message A byte array containing the same data as + * tox_friend_get_status_message would write to its `status_message` parameter. + * @param length A value equal to the return value of + * tox_friend_get_status_message_size. + */ +typedef void tox_friend_status_message_cb(Tox *tox, uint32_t friend_number, const uint8_t *message, size_t length, + void *user_data); + + +/** + * Set the callback for the `friend_status_message` event. Pass NULL to unset. + * + * This event is triggered when a friend changes their status message. + */ +void tox_callback_friend_status_message(Tox *tox, tox_friend_status_message_cb *callback); + +/** + * Return the friend's user status (away/busy/...). If the friend number is + * invalid, the return value is unspecified. + * + * The status returned is equal to the last status received through the + * `friend_status` callback. + */ +TOX_USER_STATUS tox_friend_get_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); + +/** + * @param friend_number The friend number of the friend whose user status + * changed. + * @param status The new user status. + */ +typedef void tox_friend_status_cb(Tox *tox, uint32_t friend_number, TOX_USER_STATUS status, void *user_data); + + +/** + * Set the callback for the `friend_status` event. Pass NULL to unset. + * + * This event is triggered when a friend changes their user status. + */ +void tox_callback_friend_status(Tox *tox, tox_friend_status_cb *callback); + +/** + * Check whether a friend is currently connected to this client. + * + * The result of this function is equal to the last value received by the + * `friend_connection_status` callback. + * + * @param friend_number The friend number for which to query the connection + * status. + * + * @return the friend's connection status as it was received through the + * `friend_connection_status` event. + */ +TOX_CONNECTION tox_friend_get_connection_status(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); + +/** + * @param friend_number The friend number of the friend whose connection status + * changed. + * @param connection_status The result of calling + * tox_friend_get_connection_status on the passed friend_number. + */ +typedef void tox_friend_connection_status_cb(Tox *tox, uint32_t friend_number, TOX_CONNECTION connection_status, + void *user_data); + + +/** + * Set the callback for the `friend_connection_status` event. Pass NULL to unset. + * + * This event is triggered when a friend goes offline after having been online, + * or when a friend goes online. + * + * This callback is not called when adding friends. It is assumed that when + * adding friends, their connection status is initially offline. + */ +void tox_callback_friend_connection_status(Tox *tox, tox_friend_connection_status_cb *callback); + +/** + * Check whether a friend is currently typing a message. + * + * @param friend_number The friend number for which to query the typing status. + * + * @return true if the friend is typing. + * @return false if the friend is not typing, or the friend number was + * invalid. Inspect the error code to determine which case it is. + */ +bool tox_friend_get_typing(const Tox *tox, uint32_t friend_number, TOX_ERR_FRIEND_QUERY *error); + +/** + * @param friend_number The friend number of the friend who started or stopped + * typing. + * @param is_typing The result of calling tox_friend_get_typing on the passed + * friend_number. + */ +typedef void tox_friend_typing_cb(Tox *tox, uint32_t friend_number, bool is_typing, void *user_data); + + +/** + * Set the callback for the `friend_typing` event. Pass NULL to unset. + * + * This event is triggered when a friend starts or stops typing. + */ +void tox_callback_friend_typing(Tox *tox, tox_friend_typing_cb *callback); + + +/******************************************************************************* + * + * :: Sending private messages + * + ******************************************************************************/ + + + +typedef enum TOX_ERR_SET_TYPING { + + /** + * The function returned successfully. + */ + TOX_ERR_SET_TYPING_OK, + + /** + * The friend number did not designate a valid friend. + */ + TOX_ERR_SET_TYPING_FRIEND_NOT_FOUND, + +} TOX_ERR_SET_TYPING; + + +/** + * Set the client's typing status for a friend. + * + * The client is responsible for turning it on or off. + * + * @param friend_number The friend to which the client is typing a message. + * @param typing The typing status. True means the client is typing. + * + * @return true on success. + */ +bool tox_self_set_typing(Tox *tox, uint32_t friend_number, bool typing, TOX_ERR_SET_TYPING *error); + +typedef enum TOX_ERR_FRIEND_SEND_MESSAGE { + + /** + * The function returned successfully. + */ + TOX_ERR_FRIEND_SEND_MESSAGE_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_FRIEND_SEND_MESSAGE_NULL, + + /** + * The friend number did not designate a valid friend. + */ + TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_FOUND, + + /** + * This client is currently not connected to the friend. + */ + TOX_ERR_FRIEND_SEND_MESSAGE_FRIEND_NOT_CONNECTED, + + /** + * An allocation error occurred while increasing the send queue size. + */ + TOX_ERR_FRIEND_SEND_MESSAGE_SENDQ, + + /** + * Message length exceeded TOX_MAX_MESSAGE_LENGTH. + */ + TOX_ERR_FRIEND_SEND_MESSAGE_TOO_LONG, + + /** + * Attempted to send a zero-length message. + */ + TOX_ERR_FRIEND_SEND_MESSAGE_EMPTY, + +} TOX_ERR_FRIEND_SEND_MESSAGE; + + +/** + * Send a text chat message to an online friend. + * + * This function creates a chat message packet and pushes it into the send + * queue. + * + * The message length may not exceed TOX_MAX_MESSAGE_LENGTH. Larger messages + * must be split by the client and sent as separate messages. Other clients can + * then reassemble the fragments. Messages may not be empty. + * + * The return value of this function is the message ID. If a read receipt is + * received, the triggered `friend_read_receipt` event will be passed this message ID. + * + * Message IDs are unique per friend. The first message ID is 0. Message IDs are + * incremented by 1 each time a message is sent. If UINT32_MAX messages were + * sent, the next message ID is 0. + * + * @param type Message type (normal, action, ...). + * @param friend_number The friend number of the friend to send the message to. + * @param message A non-NULL pointer to the first element of a byte array + * containing the message text. + * @param length Length of the message to be sent. + */ +uint32_t tox_friend_send_message(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, + size_t length, TOX_ERR_FRIEND_SEND_MESSAGE *error); + +/** + * @param friend_number The friend number of the friend who received the message. + * @param message_id The message ID as returned from tox_friend_send_message + * corresponding to the message sent. + */ +typedef void tox_friend_read_receipt_cb(Tox *tox, uint32_t friend_number, uint32_t message_id, void *user_data); + + +/** + * Set the callback for the `friend_read_receipt` event. Pass NULL to unset. + * + * This event is triggered when the friend receives the message sent with + * tox_friend_send_message with the corresponding message ID. + */ +void tox_callback_friend_read_receipt(Tox *tox, tox_friend_read_receipt_cb *callback); + + +/******************************************************************************* + * + * :: Receiving private messages and friend requests + * + ******************************************************************************/ + + + +/** + * @param public_key The Public Key of the user who sent the friend request. + * @param message The message they sent along with the request. + * @param length The size of the message byte array. + */ +typedef void tox_friend_request_cb(Tox *tox, const uint8_t *public_key, const uint8_t *message, size_t length, + void *user_data); + + +/** + * Set the callback for the `friend_request` event. Pass NULL to unset. + * + * This event is triggered when a friend request is received. + */ +void tox_callback_friend_request(Tox *tox, tox_friend_request_cb *callback); + +/** + * @param friend_number The friend number of the friend who sent the message. + * @param message The message data they sent. + * @param length The size of the message byte array. + */ +typedef void tox_friend_message_cb(Tox *tox, uint32_t friend_number, TOX_MESSAGE_TYPE type, const uint8_t *message, + size_t length, void *user_data); + + +/** + * Set the callback for the `friend_message` event. Pass NULL to unset. + * + * This event is triggered when a message from a friend is received. + */ +void tox_callback_friend_message(Tox *tox, tox_friend_message_cb *callback); + + +/******************************************************************************* + * + * :: File transmission: common between sending and receiving + * + ******************************************************************************/ + + + +/** + * Generates a cryptographic hash of the given data. + * + * This function may be used by clients for any purpose, but is provided + * primarily for validating cached avatars. This use is highly recommended to + * avoid unnecessary avatar updates. + * + * If hash is NULL or data is NULL while length is not 0 the function returns false, + * otherwise it returns true. + * + * This function is a wrapper to internal message-digest functions. + * + * @param hash A valid memory location the hash data. It must be at least + * TOX_HASH_LENGTH bytes in size. + * @param data Data to be hashed or NULL. + * @param length Size of the data array or 0. + * + * @return true if hash was not NULL. + */ +bool tox_hash(uint8_t *hash, const uint8_t *data, size_t length); + +enum TOX_FILE_KIND { + + /** + * Arbitrary file data. Clients can choose to handle it based on the file name + * or magic or any other way they choose. + */ + TOX_FILE_KIND_DATA, + + /** + * Avatar file_id. This consists of tox_hash(image). + * Avatar data. This consists of the image data. + * + * Avatars can be sent at any time the client wishes. Generally, a client will + * send the avatar to a friend when that friend comes online, and to all + * friends when the avatar changed. A client can save some traffic by + * remembering which friend received the updated avatar already and only send + * it if the friend has an out of date avatar. + * + * Clients who receive avatar send requests can reject it (by sending + * TOX_FILE_CONTROL_CANCEL before any other controls), or accept it (by + * sending TOX_FILE_CONTROL_RESUME). The file_id of length TOX_HASH_LENGTH bytes + * (same length as TOX_FILE_ID_LENGTH) will contain the hash. A client can compare + * this hash with a saved hash and send TOX_FILE_CONTROL_CANCEL to terminate the avatar + * transfer if it matches. + * + * When file_size is set to 0 in the transfer request it means that the client + * has no avatar. + */ + TOX_FILE_KIND_AVATAR, + +}; + + +typedef enum TOX_FILE_CONTROL { + + /** + * Sent by the receiving side to accept a file send request. Also sent after a + * TOX_FILE_CONTROL_PAUSE command to continue sending or receiving. + */ + TOX_FILE_CONTROL_RESUME, + + /** + * Sent by clients to pause the file transfer. The initial state of a file + * transfer is always paused on the receiving side and running on the sending + * side. If both the sending and receiving side pause the transfer, then both + * need to send TOX_FILE_CONTROL_RESUME for the transfer to resume. + */ + TOX_FILE_CONTROL_PAUSE, + + /** + * Sent by the receiving side to reject a file send request before any other + * commands are sent. Also sent by either side to terminate a file transfer. + */ + TOX_FILE_CONTROL_CANCEL, + +} TOX_FILE_CONTROL; + + +typedef enum TOX_ERR_FILE_CONTROL { + + /** + * The function returned successfully. + */ + TOX_ERR_FILE_CONTROL_OK, + + /** + * The friend_number passed did not designate a valid friend. + */ + TOX_ERR_FILE_CONTROL_FRIEND_NOT_FOUND, + + /** + * This client is currently not connected to the friend. + */ + TOX_ERR_FILE_CONTROL_FRIEND_NOT_CONNECTED, + + /** + * No file transfer with the given file number was found for the given friend. + */ + TOX_ERR_FILE_CONTROL_NOT_FOUND, + + /** + * A RESUME control was sent, but the file transfer is running normally. + */ + TOX_ERR_FILE_CONTROL_NOT_PAUSED, + + /** + * A RESUME control was sent, but the file transfer was paused by the other + * party. Only the party that paused the transfer can resume it. + */ + TOX_ERR_FILE_CONTROL_DENIED, + + /** + * A PAUSE control was sent, but the file transfer was already paused. + */ + TOX_ERR_FILE_CONTROL_ALREADY_PAUSED, + + /** + * Packet queue is full. + */ + TOX_ERR_FILE_CONTROL_SENDQ, + +} TOX_ERR_FILE_CONTROL; + + +/** + * Sends a file control command to a friend for a given file transfer. + * + * @param friend_number The friend number of the friend the file is being + * transferred to or received from. + * @param file_number The friend-specific identifier for the file transfer. + * @param control The control command to send. + * + * @return true on success. + */ +bool tox_file_control(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, + TOX_ERR_FILE_CONTROL *error); + +/** + * When receiving TOX_FILE_CONTROL_CANCEL, the client should release the + * resources associated with the file number and consider the transfer failed. + * + * @param friend_number The friend number of the friend who is sending the file. + * @param file_number The friend-specific file number the data received is + * associated with. + * @param control The file control command received. + */ +typedef void tox_file_recv_control_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, TOX_FILE_CONTROL control, + void *user_data); + + +/** + * Set the callback for the `file_recv_control` event. Pass NULL to unset. + * + * This event is triggered when a file control command is received from a + * friend. + */ +void tox_callback_file_recv_control(Tox *tox, tox_file_recv_control_cb *callback); + +typedef enum TOX_ERR_FILE_SEEK { + + /** + * The function returned successfully. + */ + TOX_ERR_FILE_SEEK_OK, + + /** + * The friend_number passed did not designate a valid friend. + */ + TOX_ERR_FILE_SEEK_FRIEND_NOT_FOUND, + + /** + * This client is currently not connected to the friend. + */ + TOX_ERR_FILE_SEEK_FRIEND_NOT_CONNECTED, + + /** + * No file transfer with the given file number was found for the given friend. + */ + TOX_ERR_FILE_SEEK_NOT_FOUND, + + /** + * File was not in a state where it could be seeked. + */ + TOX_ERR_FILE_SEEK_DENIED, + + /** + * Seek position was invalid + */ + TOX_ERR_FILE_SEEK_INVALID_POSITION, + + /** + * Packet queue is full. + */ + TOX_ERR_FILE_SEEK_SENDQ, + +} TOX_ERR_FILE_SEEK; + + +/** + * Sends a file seek control command to a friend for a given file transfer. + * + * This function can only be called to resume a file transfer right before + * TOX_FILE_CONTROL_RESUME is sent. + * + * @param friend_number The friend number of the friend the file is being + * received from. + * @param file_number The friend-specific identifier for the file transfer. + * @param position The position that the file should be seeked to. + */ +bool tox_file_seek(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, TOX_ERR_FILE_SEEK *error); + +typedef enum TOX_ERR_FILE_GET { + + /** + * The function returned successfully. + */ + TOX_ERR_FILE_GET_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_FILE_GET_NULL, + + /** + * The friend_number passed did not designate a valid friend. + */ + TOX_ERR_FILE_GET_FRIEND_NOT_FOUND, + + /** + * No file transfer with the given file number was found for the given friend. + */ + TOX_ERR_FILE_GET_NOT_FOUND, + +} TOX_ERR_FILE_GET; + + +/** + * Copy the file id associated to the file transfer to a byte array. + * + * @param friend_number The friend number of the friend the file is being + * transferred to or received from. + * @param file_number The friend-specific identifier for the file transfer. + * @param file_id A memory region of at least TOX_FILE_ID_LENGTH bytes. If + * this parameter is NULL, this function has no effect. + * + * @return true on success. + */ +bool tox_file_get_file_id(const Tox *tox, uint32_t friend_number, uint32_t file_number, uint8_t *file_id, + TOX_ERR_FILE_GET *error); + + +/******************************************************************************* + * + * :: File transmission: sending + * + ******************************************************************************/ + + + +typedef enum TOX_ERR_FILE_SEND { + + /** + * The function returned successfully. + */ + TOX_ERR_FILE_SEND_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_FILE_SEND_NULL, + + /** + * The friend_number passed did not designate a valid friend. + */ + TOX_ERR_FILE_SEND_FRIEND_NOT_FOUND, + + /** + * This client is currently not connected to the friend. + */ + TOX_ERR_FILE_SEND_FRIEND_NOT_CONNECTED, + + /** + * Filename length exceeded TOX_MAX_FILENAME_LENGTH bytes. + */ + TOX_ERR_FILE_SEND_NAME_TOO_LONG, + + /** + * Too many ongoing transfers. The maximum number of concurrent file transfers + * is 256 per friend per direction (sending and receiving). + */ + TOX_ERR_FILE_SEND_TOO_MANY, + +} TOX_ERR_FILE_SEND; + + +/** + * Send a file transmission request. + * + * Maximum filename length is TOX_MAX_FILENAME_LENGTH bytes. The filename + * should generally just be a file name, not a path with directory names. + * + * If a non-UINT64_MAX file size is provided, it can be used by both sides to + * determine the sending progress. File size can be set to UINT64_MAX for streaming + * data of unknown size. + * + * File transmission occurs in chunks, which are requested through the + * `file_chunk_request` event. + * + * When a friend goes offline, all file transfers associated with the friend are + * purged from core. + * + * If the file contents change during a transfer, the behaviour is unspecified + * in general. What will actually happen depends on the mode in which the file + * was modified and how the client determines the file size. + * + * - If the file size was increased + * - and sending mode was streaming (file_size = UINT64_MAX), the behaviour + * will be as expected. + * - and sending mode was file (file_size != UINT64_MAX), the + * file_chunk_request callback will receive length = 0 when Core thinks + * the file transfer has finished. If the client remembers the file size as + * it was when sending the request, it will terminate the transfer normally. + * If the client re-reads the size, it will think the friend cancelled the + * transfer. + * - If the file size was decreased + * - and sending mode was streaming, the behaviour is as expected. + * - and sending mode was file, the callback will return 0 at the new + * (earlier) end-of-file, signalling to the friend that the transfer was + * cancelled. + * - If the file contents were modified + * - at a position before the current read, the two files (local and remote) + * will differ after the transfer terminates. + * - at a position after the current read, the file transfer will succeed as + * expected. + * - In either case, both sides will regard the transfer as complete and + * successful. + * + * @param friend_number The friend number of the friend the file send request + * should be sent to. + * @param kind The meaning of the file to be sent. + * @param file_size Size in bytes of the file the client wants to send, UINT64_MAX if + * unknown or streaming. + * @param file_id A file identifier of length TOX_FILE_ID_LENGTH that can be used to + * uniquely identify file transfers across core restarts. If NULL, a random one will + * be generated by core. It can then be obtained by using tox_file_get_file_id(). + * @param filename Name of the file. Does not need to be the actual name. This + * name will be sent along with the file send request. + * @param filename_length Size in bytes of the filename. + * + * @return A file number used as an identifier in subsequent callbacks. This + * number is per friend. File numbers are reused after a transfer terminates. + * On failure, this function returns UINT32_MAX. Any pattern in file numbers + * should not be relied on. + */ +uint32_t tox_file_send(Tox *tox, uint32_t friend_number, uint32_t kind, uint64_t file_size, const uint8_t *file_id, + const uint8_t *filename, size_t filename_length, TOX_ERR_FILE_SEND *error); + +typedef enum TOX_ERR_FILE_SEND_CHUNK { + + /** + * The function returned successfully. + */ + TOX_ERR_FILE_SEND_CHUNK_OK, + + /** + * The length parameter was non-zero, but data was NULL. + */ + TOX_ERR_FILE_SEND_CHUNK_NULL, + + /** + * The friend_number passed did not designate a valid friend. + */ + TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_FOUND, + + /** + * This client is currently not connected to the friend. + */ + TOX_ERR_FILE_SEND_CHUNK_FRIEND_NOT_CONNECTED, + + /** + * No file transfer with the given file number was found for the given friend. + */ + TOX_ERR_FILE_SEND_CHUNK_NOT_FOUND, + + /** + * File transfer was found but isn't in a transferring state: (paused, done, + * broken, etc...) (happens only when not called from the request chunk callback). + */ + TOX_ERR_FILE_SEND_CHUNK_NOT_TRANSFERRING, + + /** + * Attempted to send more or less data than requested. The requested data size is + * adjusted according to maximum transmission unit and the expected end of + * the file. Trying to send less or more than requested will return this error. + */ + TOX_ERR_FILE_SEND_CHUNK_INVALID_LENGTH, + + /** + * Packet queue is full. + */ + TOX_ERR_FILE_SEND_CHUNK_SENDQ, + + /** + * Position parameter was wrong. + */ + TOX_ERR_FILE_SEND_CHUNK_WRONG_POSITION, + +} TOX_ERR_FILE_SEND_CHUNK; + + +/** + * Send a chunk of file data to a friend. + * + * This function is called in response to the `file_chunk_request` callback. The + * length parameter should be equal to the one received though the callback. + * If it is zero, the transfer is assumed complete. For files with known size, + * Core will know that the transfer is complete after the last byte has been + * received, so it is not necessary (though not harmful) to send a zero-length + * chunk to terminate. For streams, core will know that the transfer is finished + * if a chunk with length less than the length requested in the callback is sent. + * + * @param friend_number The friend number of the receiving friend for this file. + * @param file_number The file transfer identifier returned by tox_file_send. + * @param position The file or stream position from which to continue reading. + * @return true on success. + */ +bool tox_file_send_chunk(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, const uint8_t *data, + size_t length, TOX_ERR_FILE_SEND_CHUNK *error); + +/** + * If the length parameter is 0, the file transfer is finished, and the client's + * resources associated with the file number should be released. After a call + * with zero length, the file number can be reused for future file transfers. + * + * If the requested position is not equal to the client's idea of the current + * file or stream position, it will need to seek. In case of read-once streams, + * the client should keep the last read chunk so that a seek back can be + * supported. A seek-back only ever needs to read from the last requested chunk. + * This happens when a chunk was requested, but the send failed. A seek-back + * request can occur an arbitrary number of times for any given chunk. + * + * In response to receiving this callback, the client should call the function + * `tox_file_send_chunk` with the requested chunk. If the number of bytes sent + * through that function is zero, the file transfer is assumed complete. A + * client must send the full length of data requested with this callback. + * + * @param friend_number The friend number of the receiving friend for this file. + * @param file_number The file transfer identifier returned by tox_file_send. + * @param position The file or stream position from which to continue reading. + * @param length The number of bytes requested for the current chunk. + */ +typedef void tox_file_chunk_request_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, + size_t length, void *user_data); + + +/** + * Set the callback for the `file_chunk_request` event. Pass NULL to unset. + * + * This event is triggered when Core is ready to send more file data. + */ +void tox_callback_file_chunk_request(Tox *tox, tox_file_chunk_request_cb *callback); + + +/******************************************************************************* + * + * :: File transmission: receiving + * + ******************************************************************************/ + + + +/** + * The client should acquire resources to be associated with the file transfer. + * Incoming file transfers start in the PAUSED state. After this callback + * returns, a transfer can be rejected by sending a TOX_FILE_CONTROL_CANCEL + * control command before any other control commands. It can be accepted by + * sending TOX_FILE_CONTROL_RESUME. + * + * @param friend_number The friend number of the friend who is sending the file + * transfer request. + * @param file_number The friend-specific file number the data received is + * associated with. + * @param kind The meaning of the file to be sent. + * @param file_size Size in bytes of the file the client wants to send, + * UINT64_MAX if unknown or streaming. + * @param filename Name of the file. Does not need to be the actual name. This + * name will be sent along with the file send request. + * @param filename_length Size in bytes of the filename. + */ +typedef void tox_file_recv_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint32_t kind, uint64_t file_size, + const uint8_t *filename, size_t filename_length, void *user_data); + + +/** + * Set the callback for the `file_recv` event. Pass NULL to unset. + * + * This event is triggered when a file transfer request is received. + */ +void tox_callback_file_recv(Tox *tox, tox_file_recv_cb *callback); + +/** + * When length is 0, the transfer is finished and the client should release the + * resources it acquired for the transfer. After a call with length = 0, the + * file number can be reused for new file transfers. + * + * If position is equal to file_size (received in the file_receive callback) + * when the transfer finishes, the file was received completely. Otherwise, if + * file_size was UINT64_MAX, streaming ended successfully when length is 0. + * + * @param friend_number The friend number of the friend who is sending the file. + * @param file_number The friend-specific file number the data received is + * associated with. + * @param position The file position of the first byte in data. + * @param data A byte array containing the received chunk. + * @param length The length of the received chunk. + */ +typedef void tox_file_recv_chunk_cb(Tox *tox, uint32_t friend_number, uint32_t file_number, uint64_t position, + const uint8_t *data, size_t length, void *user_data); + + +/** + * Set the callback for the `file_recv_chunk` event. Pass NULL to unset. + * + * This event is first triggered when a file transfer request is received, and + * subsequently when a chunk of file data for an accepted request was received. + */ +void tox_callback_file_recv_chunk(Tox *tox, tox_file_recv_chunk_cb *callback); + + +/******************************************************************************* + * + * :: Conference management + * + ******************************************************************************/ + + + +/** + * Conference types for the conference_invite event. + */ +typedef enum TOX_CONFERENCE_TYPE { + + /** + * Text-only conferences that must be accepted with the tox_conference_join function. + */ + TOX_CONFERENCE_TYPE_TEXT, + + /** + * Video conference. The function to accept these is in toxav. + */ + TOX_CONFERENCE_TYPE_AV, + +} TOX_CONFERENCE_TYPE; + + +/** + * The invitation will remain valid until the inviting friend goes offline + * or exits the conference. + * + * @param friend_number The friend who invited us. + * @param type The conference type (text only or audio/video). + * @param cookie A piece of data of variable length required to join the + * conference. + * @param length The length of the cookie. + */ +typedef void tox_conference_invite_cb(Tox *tox, uint32_t friend_number, TOX_CONFERENCE_TYPE type, const uint8_t *cookie, + size_t length, void *user_data); + + +/** + * Set the callback for the `conference_invite` event. Pass NULL to unset. + * + * This event is triggered when the client is invited to join a conference. + */ +void tox_callback_conference_invite(Tox *tox, tox_conference_invite_cb *callback); + +/** + * @param conference_number The conference number of the conference the message is intended for. + * @param peer_number The ID of the peer who sent the message. + * @param type The type of message (normal, action, ...). + * @param message The message data. + * @param length The length of the message. + */ +typedef void tox_conference_message_cb(Tox *tox, uint32_t conference_number, uint32_t peer_number, + TOX_MESSAGE_TYPE type, const uint8_t *message, size_t length, void *user_data); + + +/** + * Set the callback for the `conference_message` event. Pass NULL to unset. + * + * This event is triggered when the client receives a conference message. + */ +void tox_callback_conference_message(Tox *tox, tox_conference_message_cb *callback); + +/** + * @param conference_number The conference number of the conference the title change is intended for. + * @param peer_number The ID of the peer who changed the title. + * @param title The title data. + * @param length The title length. + */ +typedef void tox_conference_title_cb(Tox *tox, uint32_t conference_number, uint32_t peer_number, const uint8_t *title, + size_t length, void *user_data); + + +/** + * Set the callback for the `conference_title` event. Pass NULL to unset. + * + * This event is triggered when a peer changes the conference title. + * + * If peer_number == UINT32_MAX, then author is unknown (e.g. initial joining the conference). + */ +void tox_callback_conference_title(Tox *tox, tox_conference_title_cb *callback); + +/** + * Peer list state change types. + */ +typedef enum TOX_CONFERENCE_STATE_CHANGE { + + /** + * A peer has joined the conference. + */ + TOX_CONFERENCE_STATE_CHANGE_PEER_JOIN, + + /** + * A peer has exited the conference. + */ + TOX_CONFERENCE_STATE_CHANGE_PEER_EXIT, + + /** + * A peer has changed their name. + */ + TOX_CONFERENCE_STATE_CHANGE_PEER_NAME_CHANGE, + +} TOX_CONFERENCE_STATE_CHANGE; + + +/** + * @param conference_number The conference number of the conference the title change is intended for. + * @param peer_number The ID of the peer who changed the title. + * @param change The type of change (one of TOX_CONFERENCE_STATE_CHANGE). + */ +typedef void tox_conference_namelist_change_cb(Tox *tox, uint32_t conference_number, uint32_t peer_number, + TOX_CONFERENCE_STATE_CHANGE change, void *user_data); + + +/** + * Set the callback for the `conference_namelist_change` event. Pass NULL to unset. + * + * This event is triggered when the peer list changes (name change, peer join, peer exit). + */ +void tox_callback_conference_namelist_change(Tox *tox, tox_conference_namelist_change_cb *callback); + +typedef enum TOX_ERR_CONFERENCE_NEW { + + /** + * The function returned successfully. + */ + TOX_ERR_CONFERENCE_NEW_OK, + + /** + * The conference instance failed to initialize. + */ + TOX_ERR_CONFERENCE_NEW_INIT, + +} TOX_ERR_CONFERENCE_NEW; + + +/** + * Creates a new conference. + * + * This function creates a new text conference. + * + * @return conference number on success, or UINT32_MAX on failure. + */ +uint32_t tox_conference_new(Tox *tox, TOX_ERR_CONFERENCE_NEW *error); + +typedef enum TOX_ERR_CONFERENCE_DELETE { + + /** + * The function returned successfully. + */ + TOX_ERR_CONFERENCE_DELETE_OK, + + /** + * The conference number passed did not designate a valid conference. + */ + TOX_ERR_CONFERENCE_DELETE_CONFERENCE_NOT_FOUND, + +} TOX_ERR_CONFERENCE_DELETE; + + +/** + * This function deletes a conference. + * + * @param conference_number The conference number of the conference to be deleted. + * + * @return true on success. + */ +bool tox_conference_delete(Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_DELETE *error); + +/** + * Error codes for peer info queries. + */ +typedef enum TOX_ERR_CONFERENCE_PEER_QUERY { + + /** + * The function returned successfully. + */ + TOX_ERR_CONFERENCE_PEER_QUERY_OK, + + /** + * The conference number passed did not designate a valid conference. + */ + TOX_ERR_CONFERENCE_PEER_QUERY_CONFERENCE_NOT_FOUND, + + /** + * The peer number passed did not designate a valid peer. + */ + TOX_ERR_CONFERENCE_PEER_QUERY_PEER_NOT_FOUND, + + /** + * The client is not connected to the conference. + */ + TOX_ERR_CONFERENCE_PEER_QUERY_NO_CONNECTION, + +} TOX_ERR_CONFERENCE_PEER_QUERY; + + +/** + * Return the number of peers in the conference. Return value is unspecified on failure. + */ +uint32_t tox_conference_peer_count(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_PEER_QUERY *error); + +/** + * Return the length of the peer's name. Return value is unspecified on failure. + */ +size_t tox_conference_peer_get_name_size(const Tox *tox, uint32_t conference_number, uint32_t peer_number, + TOX_ERR_CONFERENCE_PEER_QUERY *error); + +/** + * Copy the name of peer_number who is in conference_number to name. + * name must be at least TOX_MAX_NAME_LENGTH long. + * + * @return true on success. + */ +bool tox_conference_peer_get_name(const Tox *tox, uint32_t conference_number, uint32_t peer_number, uint8_t *name, + TOX_ERR_CONFERENCE_PEER_QUERY *error); + +/** + * Copy the public key of peer_number who is in conference_number to public_key. + * public_key must be TOX_PUBLIC_KEY_SIZE long. + * + * @return true on success. + */ +bool tox_conference_peer_get_public_key(const Tox *tox, uint32_t conference_number, uint32_t peer_number, + uint8_t *public_key, TOX_ERR_CONFERENCE_PEER_QUERY *error); + +/** + * Return true if passed peer_number corresponds to our own. + */ +bool tox_conference_peer_number_is_ours(const Tox *tox, uint32_t conference_number, uint32_t peer_number, + TOX_ERR_CONFERENCE_PEER_QUERY *error); + +typedef enum TOX_ERR_CONFERENCE_INVITE { + + /** + * The function returned successfully. + */ + TOX_ERR_CONFERENCE_INVITE_OK, + + /** + * The conference number passed did not designate a valid conference. + */ + TOX_ERR_CONFERENCE_INVITE_CONFERENCE_NOT_FOUND, + + /** + * The invite packet failed to send. + */ + TOX_ERR_CONFERENCE_INVITE_FAIL_SEND, + +} TOX_ERR_CONFERENCE_INVITE; + + +/** + * Invites a friend to a conference. + * + * @param friend_number The friend number of the friend we want to invite. + * @param conference_number The conference number of the conference we want to invite the friend to. + * + * @return true on success. + */ +bool tox_conference_invite(Tox *tox, uint32_t friend_number, uint32_t conference_number, + TOX_ERR_CONFERENCE_INVITE *error); + +typedef enum TOX_ERR_CONFERENCE_JOIN { + + /** + * The function returned successfully. + */ + TOX_ERR_CONFERENCE_JOIN_OK, + + /** + * The cookie passed has an invalid length. + */ + TOX_ERR_CONFERENCE_JOIN_INVALID_LENGTH, + + /** + * The conference is not the expected type. This indicates an invalid cookie. + */ + TOX_ERR_CONFERENCE_JOIN_WRONG_TYPE, + + /** + * The friend number passed does not designate a valid friend. + */ + TOX_ERR_CONFERENCE_JOIN_FRIEND_NOT_FOUND, + + /** + * Client is already in this conference. + */ + TOX_ERR_CONFERENCE_JOIN_DUPLICATE, + + /** + * Conference instance failed to initialize. + */ + TOX_ERR_CONFERENCE_JOIN_INIT_FAIL, + + /** + * The join packet failed to send. + */ + TOX_ERR_CONFERENCE_JOIN_FAIL_SEND, + +} TOX_ERR_CONFERENCE_JOIN; + + +/** + * Joins a conference that the client has been invited to. + * + * @param friend_number The friend number of the friend who sent the invite. + * @param cookie Received via the `conference_invite` event. + * @param length The size of cookie. + * + * @return conference number on success, UINT32_MAX on failure. + */ +uint32_t tox_conference_join(Tox *tox, uint32_t friend_number, const uint8_t *cookie, size_t length, + TOX_ERR_CONFERENCE_JOIN *error); + +typedef enum TOX_ERR_CONFERENCE_SEND_MESSAGE { + + /** + * The function returned successfully. + */ + TOX_ERR_CONFERENCE_SEND_MESSAGE_OK, + + /** + * The conference number passed did not designate a valid conference. + */ + TOX_ERR_CONFERENCE_SEND_MESSAGE_CONFERENCE_NOT_FOUND, + + /** + * The message is too long. + */ + TOX_ERR_CONFERENCE_SEND_MESSAGE_TOO_LONG, + + /** + * The client is not connected to the conference. + */ + TOX_ERR_CONFERENCE_SEND_MESSAGE_NO_CONNECTION, + + /** + * The message packet failed to send. + */ + TOX_ERR_CONFERENCE_SEND_MESSAGE_FAIL_SEND, + +} TOX_ERR_CONFERENCE_SEND_MESSAGE; + + +/** + * Send a text chat message to the conference. + * + * This function creates a conference message packet and pushes it into the send + * queue. + * + * The message length may not exceed TOX_MAX_MESSAGE_LENGTH. Larger messages + * must be split by the client and sent as separate messages. Other clients can + * then reassemble the fragments. + * + * @param conference_number The conference number of the conference the message is intended for. + * @param type Message type (normal, action, ...). + * @param message A non-NULL pointer to the first element of a byte array + * containing the message text. + * @param length Length of the message to be sent. + * + * @return true on success. + */ +bool tox_conference_send_message(Tox *tox, uint32_t conference_number, TOX_MESSAGE_TYPE type, const uint8_t *message, + size_t length, TOX_ERR_CONFERENCE_SEND_MESSAGE *error); + +typedef enum TOX_ERR_CONFERENCE_TITLE { + + /** + * The function returned successfully. + */ + TOX_ERR_CONFERENCE_TITLE_OK, + + /** + * The conference number passed did not designate a valid conference. + */ + TOX_ERR_CONFERENCE_TITLE_CONFERENCE_NOT_FOUND, + + /** + * The title is too long or empty. + */ + TOX_ERR_CONFERENCE_TITLE_INVALID_LENGTH, + + /** + * The title packet failed to send. + */ + TOX_ERR_CONFERENCE_TITLE_FAIL_SEND, + +} TOX_ERR_CONFERENCE_TITLE; + + +/** + * Return the length of the conference title. Return value is unspecified on failure. + * + * The return value is equal to the `length` argument received by the last + * `conference_title` callback. + */ +size_t tox_conference_get_title_size(const Tox *tox, uint32_t conference_number, TOX_ERR_CONFERENCE_TITLE *error); + +/** + * Write the title designated by the given conference number to a byte array. + * + * Call tox_conference_get_title_size to determine the allocation size for the `title` parameter. + * + * The data written to `title` is equal to the data received by the last + * `conference_title` callback. + * + * @param title A valid memory region large enough to store the title. + * If this parameter is NULL, this function has no effect. + * + * @return true on success. + */ +bool tox_conference_get_title(const Tox *tox, uint32_t conference_number, uint8_t *title, + TOX_ERR_CONFERENCE_TITLE *error); + +/** + * Set the conference title and broadcast it to the rest of the conference. + * + * Title length cannot be longer than TOX_MAX_NAME_LENGTH. + * + * @return true on success. + */ +bool tox_conference_set_title(Tox *tox, uint32_t conference_number, const uint8_t *title, size_t length, + TOX_ERR_CONFERENCE_TITLE *error); + +/** + * Return the number of conferences in the Tox instance. + * This should be used to determine how much memory to allocate for `tox_conference_get_chatlist`. + */ +size_t tox_conference_get_chatlist_size(const Tox *tox); + +/** + * Copy a list of valid conference IDs into the array chatlist. Determine how much space + * to allocate for the array with the `tox_conference_get_chatlist_size` function. + */ +void tox_conference_get_chatlist(const Tox *tox, uint32_t *chatlist); + +/** + * Returns the type of conference (TOX_CONFERENCE_TYPE) that conference_number is. Return value is + * unspecified on failure. + */ +typedef enum TOX_ERR_CONFERENCE_GET_TYPE { + + /** + * The function returned successfully. + */ + TOX_ERR_CONFERENCE_GET_TYPE_OK, + + /** + * The conference number passed did not designate a valid conference. + */ + TOX_ERR_CONFERENCE_GET_TYPE_CONFERENCE_NOT_FOUND, + +} TOX_ERR_CONFERENCE_GET_TYPE; + + +TOX_CONFERENCE_TYPE tox_conference_get_type(const Tox *tox, uint32_t conference_number, + TOX_ERR_CONFERENCE_GET_TYPE *error); + + +/******************************************************************************* + * + * :: Low-level custom packet sending and receiving + * + ******************************************************************************/ + + + +typedef enum TOX_ERR_FRIEND_CUSTOM_PACKET { + + /** + * The function returned successfully. + */ + TOX_ERR_FRIEND_CUSTOM_PACKET_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_FRIEND_CUSTOM_PACKET_NULL, + + /** + * The friend number did not designate a valid friend. + */ + TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_FOUND, + + /** + * This client is currently not connected to the friend. + */ + TOX_ERR_FRIEND_CUSTOM_PACKET_FRIEND_NOT_CONNECTED, + + /** + * The first byte of data was not in the specified range for the packet type. + * This range is 200-254 for lossy, and 160-191 for lossless packets. + */ + TOX_ERR_FRIEND_CUSTOM_PACKET_INVALID, + + /** + * Attempted to send an empty packet. + */ + TOX_ERR_FRIEND_CUSTOM_PACKET_EMPTY, + + /** + * Packet data length exceeded TOX_MAX_CUSTOM_PACKET_SIZE. + */ + TOX_ERR_FRIEND_CUSTOM_PACKET_TOO_LONG, + + /** + * Packet queue is full. + */ + TOX_ERR_FRIEND_CUSTOM_PACKET_SENDQ, + +} TOX_ERR_FRIEND_CUSTOM_PACKET; + + +/** + * Send a custom lossy packet to a friend. + * + * The first byte of data must be in the range 200-254. Maximum length of a + * custom packet is TOX_MAX_CUSTOM_PACKET_SIZE. + * + * Lossy packets behave like UDP packets, meaning they might never reach the + * other side or might arrive more than once (if someone is messing with the + * connection) or might arrive in the wrong order. + * + * Unless latency is an issue, it is recommended that you use lossless custom + * packets instead. + * + * @param friend_number The friend number of the friend this lossy packet + * should be sent to. + * @param data A byte array containing the packet data. + * @param length The length of the packet data byte array. + * + * @return true on success. + */ +bool tox_friend_send_lossy_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + TOX_ERR_FRIEND_CUSTOM_PACKET *error); + +/** + * Send a custom lossless packet to a friend. + * + * The first byte of data must be in the range 160-191. Maximum length of a + * custom packet is TOX_MAX_CUSTOM_PACKET_SIZE. + * + * Lossless packet behaviour is comparable to TCP (reliability, arrive in order) + * but with packets instead of a stream. + * + * @param friend_number The friend number of the friend this lossless packet + * should be sent to. + * @param data A byte array containing the packet data. + * @param length The length of the packet data byte array. + * + * @return true on success. + */ +bool tox_friend_send_lossless_packet(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + TOX_ERR_FRIEND_CUSTOM_PACKET *error); + +/** + * @param friend_number The friend number of the friend who sent a lossy packet. + * @param data A byte array containing the received packet data. + * @param length The length of the packet data byte array. + */ +typedef void tox_friend_lossy_packet_cb(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + void *user_data); + + +/** + * Set the callback for the `friend_lossy_packet` event. Pass NULL to unset. + * + */ +void tox_callback_friend_lossy_packet(Tox *tox, tox_friend_lossy_packet_cb *callback); + +/** + * @param friend_number The friend number of the friend who sent the packet. + * @param data A byte array containing the received packet data. + * @param length The length of the packet data byte array. + */ +typedef void tox_friend_lossless_packet_cb(Tox *tox, uint32_t friend_number, const uint8_t *data, size_t length, + void *user_data); + + +/** + * Set the callback for the `friend_lossless_packet` event. Pass NULL to unset. + * + */ +void tox_callback_friend_lossless_packet(Tox *tox, tox_friend_lossless_packet_cb *callback); + + +/******************************************************************************* + * + * :: Low-level network information + * + ******************************************************************************/ + + + +/** + * Writes the temporary DHT public key of this instance to a byte array. + * + * This can be used in combination with an externally accessible IP address and + * the bound port (from tox_self_get_udp_port) to run a temporary bootstrap node. + * + * Be aware that every time a new instance is created, the DHT public key + * changes, meaning this cannot be used to run a permanent bootstrap node. + * + * @param dht_id A memory region of at least TOX_PUBLIC_KEY_SIZE bytes. If this + * parameter is NULL, this function has no effect. + */ +void tox_self_get_dht_id(const Tox *tox, uint8_t *dht_id); + +typedef enum TOX_ERR_GET_PORT { + + /** + * The function returned successfully. + */ + TOX_ERR_GET_PORT_OK, + + /** + * The instance was not bound to any port. + */ + TOX_ERR_GET_PORT_NOT_BOUND, + +} TOX_ERR_GET_PORT; + + +/** + * Return the UDP port this Tox instance is bound to. + */ +uint16_t tox_self_get_udp_port(const Tox *tox, TOX_ERR_GET_PORT *error); + +/** + * Return the TCP port this Tox instance is bound to. This is only relevant if + * the instance is acting as a TCP relay. + */ +uint16_t tox_self_get_tcp_port(const Tox *tox, TOX_ERR_GET_PORT *error); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libtox/src/toxcore/tox_api.c b/libs/libtox/src/toxcore/tox_api.c new file mode 100644 index 0000000000..b6c8c38618 --- /dev/null +++ b/libs/libtox/src/toxcore/tox_api.c @@ -0,0 +1,97 @@ +#include "tox.h" + +#include +#include + +#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} + + +#define CONST_FUNCTION(lowercase, uppercase) \ +uint32_t tox_##lowercase(void) \ +{ \ + return TOX_##uppercase; \ +} + +CONST_FUNCTION(version_major, VERSION_MAJOR) +CONST_FUNCTION(version_minor, VERSION_MINOR) +CONST_FUNCTION(version_patch, VERSION_PATCH) +CONST_FUNCTION(public_key_size, PUBLIC_KEY_SIZE) +CONST_FUNCTION(secret_key_size, SECRET_KEY_SIZE) +CONST_FUNCTION(address_size, ADDRESS_SIZE) +CONST_FUNCTION(max_name_length, MAX_NAME_LENGTH) +CONST_FUNCTION(max_status_message_length, MAX_STATUS_MESSAGE_LENGTH) +CONST_FUNCTION(max_friend_request_length, MAX_FRIEND_REQUEST_LENGTH) +CONST_FUNCTION(max_message_length, MAX_MESSAGE_LENGTH) +CONST_FUNCTION(max_custom_packet_size, MAX_CUSTOM_PACKET_SIZE) +CONST_FUNCTION(hash_length, HASH_LENGTH) +CONST_FUNCTION(file_id_length, FILE_ID_LENGTH) +CONST_FUNCTION(max_filename_length, MAX_FILENAME_LENGTH) + + +#define ACCESSORS(type, ns, name) \ +type tox_options_get_##ns##name(const struct Tox_Options *options) \ +{ \ + return options->ns##name; \ +} \ +void tox_options_set_##ns##name(struct Tox_Options *options, type name) \ +{ \ + options->ns##name = name; \ +} + +ACCESSORS(bool, , ipv6_enabled) +ACCESSORS(bool, , udp_enabled) +ACCESSORS(TOX_PROXY_TYPE, proxy_ , type) +ACCESSORS(const char *, proxy_ , host) +ACCESSORS(uint16_t, proxy_ , port) +ACCESSORS(uint16_t, , start_port) +ACCESSORS(uint16_t, , end_port) +ACCESSORS(uint16_t, , tcp_port) +ACCESSORS(bool, , hole_punching_enabled) +ACCESSORS(TOX_SAVEDATA_TYPE, savedata_, type) +ACCESSORS(size_t, savedata_, length) +ACCESSORS(tox_log_cb *, log_, callback) +ACCESSORS(void *, log_, user_data) +ACCESSORS(bool, , local_discovery_enabled) + +const uint8_t *tox_options_get_savedata_data(const struct Tox_Options *options) +{ + return options->savedata_data; +} + +void tox_options_set_savedata_data(struct Tox_Options *options, const uint8_t *data, size_t length) +{ + options->savedata_data = data; + options->savedata_length = length; +} + +void tox_options_default(struct Tox_Options *options) +{ + if (options) { + struct Tox_Options default_options = { 0 }; + *options = default_options; + tox_options_set_ipv6_enabled(options, true); + tox_options_set_udp_enabled(options, true); + tox_options_set_proxy_type(options, TOX_PROXY_TYPE_NONE); + tox_options_set_hole_punching_enabled(options, true); + tox_options_set_local_discovery_enabled(options, true); + } +} + +struct Tox_Options *tox_options_new(TOX_ERR_OPTIONS_NEW *error) +{ + struct Tox_Options *options = (struct Tox_Options *)malloc(sizeof(struct Tox_Options)); + + if (options) { + tox_options_default(options); + SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_OK); + return options; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_OPTIONS_NEW_MALLOC); + return NULL; +} + +void tox_options_free(struct Tox_Options *options) +{ + free(options); +} diff --git a/libs/libtox/src/toxcore/util.c b/libs/libtox/src/toxcore/util.c new file mode 100644 index 0000000000..5202598518 --- /dev/null +++ b/libs/libtox/src/toxcore/util.c @@ -0,0 +1,194 @@ +/* + * Utilities. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * Copyright © 2013 plutooo + * + * This file is part of Tox, the free peer to peer instant messenger. + * This file is donated to the Tox Project. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _XOPEN_SOURCE 600 + +#include "util.h" + +#include "crypto_core.h" /* for CRYPTO_PUBLIC_KEY_SIZE */ +#include "network.h" /* for current_time_monotonic */ + +#include + + +/* don't call into system billions of times for no reason */ +static uint64_t unix_time_value; +static uint64_t unix_base_time_value; + +/* XXX: note that this is not thread-safe; if multiple threads call unix_time_update() concurrently, the return value of + * unix_time() may fail to increase monotonically with increasing time */ +void unix_time_update(void) +{ + if (unix_base_time_value == 0) { + unix_base_time_value = ((uint64_t)time(NULL) - (current_time_monotonic() / 1000ULL)); + } + + unix_time_value = (current_time_monotonic() / 1000ULL) + unix_base_time_value; +} + +uint64_t unix_time(void) +{ + return unix_time_value; +} + +int is_timeout(uint64_t timestamp, uint64_t timeout) +{ + return timestamp + timeout <= unix_time(); +} + + +/* id functions */ +bool id_equal(const uint8_t *dest, const uint8_t *src) +{ + return public_key_cmp(dest, src) == 0; +} + +uint32_t id_copy(uint8_t *dest, const uint8_t *src) +{ + memcpy(dest, src, CRYPTO_PUBLIC_KEY_SIZE); + return CRYPTO_PUBLIC_KEY_SIZE; +} + +void host_to_net(uint8_t *num, uint16_t numbytes) +{ +#ifndef WORDS_BIGENDIAN + uint32_t i; + VLA(uint8_t, buff, numbytes); + + for (i = 0; i < numbytes; ++i) { + buff[i] = num[numbytes - i - 1]; + } + + memcpy(num, buff, numbytes); +#endif +} + +uint16_t lendian_to_host16(uint16_t lendian) +{ +#ifdef WORDS_BIGENDIAN + return (lendian << 8) | (lendian >> 8); +#else + return lendian; +#endif +} + +void host_to_lendian32(uint8_t *dest, uint32_t num) +{ +#ifdef WORDS_BIGENDIAN + num = ((num << 8) & 0xFF00FF00) | ((num >> 8) & 0xFF00FF); + num = (num << 16) | (num >> 16); +#endif + memcpy(dest, &num, sizeof(uint32_t)); +} + +void lendian_to_host32(uint32_t *dest, const uint8_t *lendian) +{ + uint32_t d; + memcpy(&d, lendian, sizeof(uint32_t)); +#ifdef WORDS_BIGENDIAN + d = ((d << 8) & 0xFF00FF00) | ((d >> 8) & 0xFF00FF); + d = (d << 16) | (d >> 16); +#endif + *dest = d; +} + +/* state load/save */ +int load_state(load_state_callback_func load_state_callback, Logger *log, void *outer, + const uint8_t *data, uint32_t length, uint16_t cookie_inner) +{ + if (!load_state_callback || !data) { + LOGGER_ERROR(log, "load_state() called with invalid args.\n"); + return -1; + } + + + uint16_t type; + uint32_t length_sub, cookie_type; + uint32_t size_head = sizeof(uint32_t) * 2; + + while (length >= size_head) { + lendian_to_host32(&length_sub, data); + lendian_to_host32(&cookie_type, data + sizeof(length_sub)); + data += size_head; + length -= size_head; + + if (length < length_sub) { + /* file truncated */ + LOGGER_ERROR(log, "state file too short: %u < %u\n", length, length_sub); + return -1; + } + + if (lendian_to_host16((cookie_type >> 16)) != cookie_inner) { + /* something is not matching up in a bad way, give up */ + LOGGER_ERROR(log, "state file garbled: %04x != %04x\n", (cookie_type >> 16), cookie_inner); + return -1; + } + + type = lendian_to_host16(cookie_type & 0xFFFF); + + int ret = load_state_callback(outer, data, length_sub, type); + + if (ret == -1) { + return -1; + } + + /* -2 means end of save. */ + if (ret == -2) { + return 0; + } + + data += length_sub; + length -= length_sub; + } + + return length == 0 ? 0 : -1; +} + +int create_recursive_mutex(pthread_mutex_t *mutex) +{ + pthread_mutexattr_t attr; + + if (pthread_mutexattr_init(&attr) != 0) { + return -1; + } + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0) { + pthread_mutexattr_destroy(&attr); + return -1; + } + + if (pthread_mutex_init(mutex, &attr) != 0) { + pthread_mutexattr_destroy(&attr); + return -1; + } + + pthread_mutexattr_destroy(&attr); + + return 0; +} diff --git a/libs/libtox/src/toxcore/util.h b/libs/libtox/src/toxcore/util.h new file mode 100644 index 0000000000..6ef9a75f8c --- /dev/null +++ b/libs/libtox/src/toxcore/util.h @@ -0,0 +1,64 @@ +/* + * Utilities. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * Copyright © 2013 plutooo + * + * This file is part of Tox, the free peer to peer instant messenger. + * This file is donated to the Tox Project. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef UTIL_H +#define UTIL_H + +#include +#include +#include + +#include "logger.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define PAIR(TYPE1__, TYPE2__) struct { TYPE1__ first; TYPE2__ second; } + +void unix_time_update(void); +uint64_t unix_time(void); +int is_timeout(uint64_t timestamp, uint64_t timeout); + + +/* id functions */ +bool id_equal(const uint8_t *dest, const uint8_t *src); +uint32_t id_copy(uint8_t *dest, const uint8_t *src); /* return value is CLIENT_ID_SIZE */ + +void host_to_net(uint8_t *num, uint16_t numbytes); +#define net_to_host(x, y) host_to_net(x, y) + +uint16_t lendian_to_host16(uint16_t lendian); +#define host_tolendian16(x) lendian_to_host16(x) + +void host_to_lendian32(uint8_t *dest, uint32_t num); +void lendian_to_host32(uint32_t *dest, const uint8_t *lendian); + +/* state load/save */ +typedef int (*load_state_callback_func)(void *outer, const uint8_t *data, uint32_t len, uint16_t type); +int load_state(load_state_callback_func load_state_callback, Logger *log, void *outer, + const uint8_t *data, uint32_t length, uint16_t cookie_inner); + +/* Returns -1 if failed or 0 if success */ +//int create_recursive_mutex(pthread_mutex_t *mutex); + +#endif /* UTIL_H */ diff --git a/libs/libtox/src/toxdns/Makefile.inc b/libs/libtox/src/toxdns/Makefile.inc new file mode 100644 index 0000000000..5b7c012320 --- /dev/null +++ b/libs/libtox/src/toxdns/Makefile.inc @@ -0,0 +1,35 @@ +lib_LTLIBRARIES += libtoxdns.la + +libtoxdns_la_include_HEADERS = \ + ../toxdns/toxdns.h + +libtoxdns_la_includedir = $(includedir)/tox + +libtoxdns_la_SOURCES = ../toxdns/toxdns.h \ + ../toxdns/toxdns.c + +libtoxdns_la_CFLAGS = -I$(top_srcdir) \ + -I$(top_srcdir)/toxcore \ + $(LIBSODIUM_CFLAGS) \ + $(NACL_CFLAGS) \ + $(PTHREAD_CFLAGS) + +libtoxdns_la_LDFLAGS = $(LT_LDFLAGS) \ + $(EXTRA_LT_LDFLAGS) \ + $(LIBSODIUM_LDFLAGS) \ + $(NACL_LDFLAGS) \ + $(MATH_LDFLAGS) \ + $(RT_LIBS) \ + $(WINSOCK2_LIBS) + +libtoxdns_la_LIBADD = $(LIBSODIUM_LIBS) \ + $(NACL_OBJECTS) \ + $(NAC_LIBS) \ + $(PTHREAD_LIBS) \ + libtoxcore.la + +if SET_SO_VERSION + +EXTRA_libtoxdns_la_DEPENDENCIES = ../so.version + +endif diff --git a/libs/libtox/src/toxdns/toxdns.c b/libs/libtox/src/toxdns/toxdns.c new file mode 100644 index 0000000000..96f3081f80 --- /dev/null +++ b/libs/libtox/src/toxdns/toxdns.c @@ -0,0 +1,243 @@ +/* + * Tox secure username DNS toxid resolving functions. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../toxcore/Messenger.h" +#include "../toxcore/logger.h" +#include "toxdns.h" + +static const char base32[32] = { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', +}; + +#define _encode(a, b, c) \ +{ \ + uint8_t _i = 0; \ + while (_i != c) { \ + *a++ = base32[((b[0] >> bits) | (b[1] << (8 - bits))) & 0x1F]; \ + bits += 5; \ + if(bits >= 8) { \ + bits -= 8; \ + b++; \ + _i++; \ + } \ + } \ +} + +typedef struct { + uint8_t temp_pk[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t temp_sk[CRYPTO_SECRET_KEY_SIZE]; + uint8_t server_public_key[CRYPTO_PUBLIC_KEY_SIZE]; + uint8_t shared_key[CRYPTO_SYMMETRIC_KEY_SIZE]; + uint32_t nonce; + uint32_t nonce_start; +} DNS_Object; + +static void dns_new_temp_keys(DNS_Object *d) +{ + d->nonce = d->nonce_start = random_int(); + crypto_new_keypair(d->temp_pk, d->temp_sk); + encrypt_precompute(d->server_public_key, d->temp_sk, d->shared_key); +} + +/* Create a new tox_dns3 object for server with server_public_key. + * + * return Null on failure. + * return pointer object on success. + */ +void *tox_dns3_new(uint8_t *server_public_key) +{ + DNS_Object *d = (DNS_Object *)malloc(sizeof(DNS_Object)); + + if (d == NULL) { + return NULL; + } + + memcpy(d->server_public_key, server_public_key, CRYPTO_PUBLIC_KEY_SIZE); + dns_new_temp_keys(d); + return d; +} + +/* Destroy the tox dns3 object. + */ +void tox_dns3_kill(void *dns3_object) +{ + memset(dns3_object, 0, sizeof(DNS_Object)); + free(dns3_object); +} + +/* Generate a dns3 string of string_max_len used to query the dns server referred to by to + * dns3_object for a tox id registered to user with name of name_len. + * + * the uint32_t pointed by request_id will be set to the request id which must be passed to + * tox_decrypt_dns3_TXT() to correctly decode the response. + * + * This is what the string returned looks like: + * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc + * + * returns length of string on success. + * returns -1 on failure. + */ +int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, + uint8_t *name, uint8_t name_len) +{ +#define DOT_INTERVAL (6 * 5) + int base = (sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE + name_len + CRYPTO_MAC_SIZE); + int end_len = ((base * 8) / 5) + (base / DOT_INTERVAL) + !!(base % 5); + end_len -= !(base % DOT_INTERVAL); + + if (end_len > string_max_len) { + return -1; + } + + DNS_Object *d = (DNS_Object *)dns3_object; + uint8_t buffer[1024]; + uint8_t nonce[CRYPTO_NONCE_SIZE] = {0}; + memcpy(nonce, &d->nonce, sizeof(uint32_t)); + memcpy(buffer, &d->nonce, sizeof(uint32_t)); + memcpy(buffer + sizeof(uint32_t), d->temp_pk, CRYPTO_PUBLIC_KEY_SIZE); + int len = encrypt_data_symmetric(d->shared_key, nonce, name, name_len, + buffer + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE); + + if (len == -1) { + return -1; + } + + int total_len = len + sizeof(uint32_t) + CRYPTO_PUBLIC_KEY_SIZE; + uint8_t *buff = buffer, *old_str = string; + buffer[total_len] = 0; + uint8_t bits = 0; + int i; + + for (i = !(total_len % DOT_INTERVAL); i < (total_len / DOT_INTERVAL); ++i) { + _encode(string, buff, DOT_INTERVAL); + *string = '.'; + ++string; + } + + int left = total_len - (buff - buffer); + _encode(string, buff, left); +#undef DOT_INTERVAL + *request_id = d->nonce; + ++d->nonce; + + if (d->nonce == d->nonce_start) { + dns_new_temp_keys(d); + } + + if (end_len != string - old_str) { + // TODO(iphydf): This currently has no access to a logger. + LOGGER_ERROR(NULL, "tox_generate_dns3_string Fail, %u != %lu\n", end_len, string - old_str); + return -1; + } + + return string - old_str; +} + + +static int decode(uint8_t *dest, uint8_t *src) +{ + uint8_t *p = src, *op = dest, bits = 0; + *op = 0; + + while (*p) { + uint8_t ch = *p++; + + if ('A' <= ch && ch <= 'Z') { + ch = ch - 'A'; + } else if ('a' <= ch && ch <= 'z') { + ch = ch - 'a'; + } else if ('0' <= ch && ch <= '5') { + ch = ch - '0' + 26; + } else { + return - 1; + } + + *op |= (ch << bits); + bits += 5; + + if (bits >= 8) { + bits -= 8; + ++op; + *op = (ch >> (5 - bits)); + } + } + + return op - dest; +} + +/* Decode and decrypt the id_record returned of length id_record_len into + * tox_id (needs to be at least TOX_FRIEND_ADDRESS_SIZE). + * + * request_id is the request id given by tox_generate_dns3_string() when creating the request. + * + * the id_record passed to this function should look somewhat like this: + * 2vgcxuycbuctvauik3plsv3d3aadv4zfjfhi3thaizwxinelrvigchv0ah3qjcsx5qhmaksb2lv2hm5cwbtx0yp + * + * returns -1 on failure. + * returns 0 on success. + * + */ +int tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len, + uint32_t request_id) +{ + DNS_Object *d = (DNS_Object *)dns3_object; + + if (id_record_len != 87) { + return -1; + } + +#if 0 + + if (id_record_len > 255 || id_record_len <= (sizeof(uint32_t) + CRYPTO_MAC_SIZE)) { + return -1; + } + +#endif + + VLA(uint8_t, id_record_null, id_record_len + 1); + memcpy(id_record_null, id_record, id_record_len); + id_record_null[id_record_len] = 0; + VLA(uint8_t, data, id_record_len); + int length = decode(data, id_record_null); + + if (length == -1) { + return -1; + } + + uint8_t nonce[CRYPTO_NONCE_SIZE] = {0}; + memcpy(nonce, &request_id, sizeof(uint32_t)); + nonce[sizeof(uint32_t)] = 1; + int len = decrypt_data_symmetric(d->shared_key, nonce, data, length, tox_id); + + if (len != FRIEND_ADDRESS_SIZE) { + return -1; + } + + return 0; +} diff --git a/libs/libtox/src/toxdns/toxdns.h b/libs/libtox/src/toxdns/toxdns.h new file mode 100644 index 0000000000..b280925eb1 --- /dev/null +++ b/libs/libtox/src/toxdns/toxdns.h @@ -0,0 +1,96 @@ +/* + * Tox secure username DNS toxid resolving functions. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2014 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef TOXDNS_H +#define TOXDNS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Clients are encouraged to set this as the maximum length names can have. */ +#define TOXDNS_MAX_RECOMMENDED_NAME_LENGTH 32 + +/* How to use this api to make secure tox dns3 requests: + * + * 1. Get the public key of a server that supports tox dns3. + * 2. use tox_dns3_new() to create a new object to create DNS requests + * and handle responses for that server. + * 3. Use tox_generate_dns3_string() to generate a string based on the name we want to query and a request_id + * that must be stored somewhere for when we want to decrypt the response. + * 4. take the string and use it for your DNS request like this: + * _4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc._tox.utox.org + * 5. The TXT in the DNS you receive should look like this: + * v=tox3;id=2vgcxuycbuctvauik3plsv3d3aadv4zfjfhi3thaizwxinelrvigchv0ah3qjcsx5qhmaksb2lv2hm5cwbtx0yp + * 6. Take the id string and use it with tox_decrypt_dns3_TXT() and the request_id corresponding to the + * request we stored earlier to get the Tox id returned by the DNS server. + */ + +/* Create a new tox_dns3 object for server with server_public_key of size TOX_CLIENT_ID_SIZE. + * + * return Null on failure. + * return pointer object on success. + */ +void *tox_dns3_new(uint8_t *server_public_key); + +/* Destroy the tox dns3 object. + */ +void tox_dns3_kill(void *dns3_object); + +/* Generate a dns3 string of string_max_len used to query the dns server referred to by to + * dns3_object for a tox id registered to user with name of name_len. + * + * the uint32_t pointed by request_id will be set to the request id which must be passed to + * tox_decrypt_dns3_TXT() to correctly decode the response. + * + * This is what the string returned looks like: + * 4haaaaipr1o3mz0bxweox541airydbovqlbju51mb4p0ebxq.rlqdj4kkisbep2ks3fj2nvtmk4daduqiueabmexqva1jc + * + * returns length of string on success. + * returns -1 on failure. + */ +int tox_generate_dns3_string(void *dns3_object, uint8_t *string, uint16_t string_max_len, uint32_t *request_id, + uint8_t *name, uint8_t name_len); + +/* Decode and decrypt the id_record returned of length id_record_len into + * tox_id (needs to be at least TOX_FRIEND_ADDRESS_SIZE). + * + * request_id is the request id given by tox_generate_dns3_string() when creating the request. + * + * the id_record passed to this function should look somewhat like this: + * 2vgcxuycbuctvauik3plsv3d3aadv4zfjfhi3thaizwxinelrvigchv0ah3qjcsx5qhmaksb2lv2hm5cwbtx0yp + * + * returns -1 on failure. + * returns 0 on success. + * + */ +int tox_decrypt_dns3_TXT(void *dns3_object, uint8_t *tox_id, uint8_t *id_record, uint32_t id_record_len, + uint32_t request_id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/libtox/src/toxencryptsave/Makefile.inc b/libs/libtox/src/toxencryptsave/Makefile.inc new file mode 100644 index 0000000000..bde026cdaf --- /dev/null +++ b/libs/libtox/src/toxencryptsave/Makefile.inc @@ -0,0 +1,55 @@ +lib_LTLIBRARIES += libtoxencryptsave.la + +libtoxencryptsave_la_include_HEADERS = \ + ../toxencryptsave/toxencryptsave.h + +libtoxencryptsave_la_includedir = $(includedir)/tox + +libtoxencryptsave_la_SOURCES = ../toxencryptsave/toxencryptsave.h \ + ../toxencryptsave/toxencryptsave.c \ + ../toxencryptsave/defines.h + + +if WITH_NACL +libtoxencryptsave_la_SOURCES += ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c \ + ../toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c +endif + +libtoxencryptsave_la_CFLAGS = -I$(top_srcdir) \ + -I$(top_srcdir)/toxcore \ + $(LIBSODIUM_CFLAGS) \ + $(NACL_CFLAGS) \ + $(PTHREAD_CFLAGS) + +libtoxencryptsave_la_LDFLAGS = $(LT_LDFLAGS) \ + $(EXTRA_LT_LDFLAGS) \ + $(LIBSODIUM_LDFLAGS) \ + $(NACL_LDFLAGS) \ + $(MATH_LDFLAGS) \ + $(RT_LIBS) \ + $(WINSOCK2_LIBS) + +libtoxencryptsave_la_LIBADD = $(LIBSODIUM_LIBS) \ + $(NACL_OBJECTS) \ + $(NAC_LIBS) \ + $(PTHREAD_LIBS) \ + libtoxcore.la + +if SET_SO_VERSION + +EXTRA_libtoxencryptsave_la_DEPENDENCIES = ../so.version + +endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h new file mode 100644 index 0000000000..5cb32f8dcf --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h @@ -0,0 +1,92 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef crypto_pwhash_scryptsalsa208sha256_H +#define crypto_pwhash_scryptsalsa208sha256_H + +#include +#include + +#include "export.h" + +#ifdef __cplusplus +# if __GNUC__ +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +extern "C" { +#endif + +#define crypto_pwhash_scryptsalsa208sha256_SALTBYTES 32U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_saltbytes(void); + +#define crypto_pwhash_scryptsalsa208sha256_STRBYTES 102U +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_strbytes(void); + +#define crypto_pwhash_scryptsalsa208sha256_STRPREFIX "$7$" +SODIUM_EXPORT +const char *crypto_pwhash_scryptsalsa208sha256_strprefix(void); + +#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE 524288ULL +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void); + +#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE 16777216ULL +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void); + +#define crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE 33554432ULL +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void); + +#define crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE 1073741824ULL +SODIUM_EXPORT +size_t crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, + unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, + size_t memlimit); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, + size_t memlimit); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen); + +SODIUM_EXPORT +int crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen); + +#ifdef __cplusplus +} +#endif + +/* Backward compatibility with version 0.5.0 */ + +#define crypto_pwhash_scryptxsalsa208sha256_SALTBYTES crypto_pwhash_scryptsalsa208sha256_SALTBYTES +#define crypto_pwhash_scryptxsalsa208sha256_saltbytes crypto_pwhash_scryptsalsa208sha256_saltbytes +#define crypto_pwhash_scryptxsalsa208sha256_STRBYTES crypto_pwhash_scryptsalsa208sha256_STRBYTES +#define crypto_pwhash_scryptxsalsa208sha256_strbytes crypto_pwhash_scryptsalsa208sha256_strbytes +#define crypto_pwhash_scryptxsalsa208sha256 crypto_pwhash_scryptsalsa208sha256 +#define crypto_pwhash_scryptxsalsa208sha256_str crypto_pwhash_scryptsalsa208sha256_str +#define crypto_pwhash_scryptxsalsa208sha256_str_verify crypto_pwhash_scryptsalsa208sha256_str_verify + +#endif + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c new file mode 100644 index 0000000000..5a5c5525f3 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt-common.c @@ -0,0 +1,257 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "crypto_scrypt.h" +#include "runtime.h" +#include "utils.h" + +static const char * const itoa64 = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static uint8_t * +encode64_uint32(uint8_t * dst, size_t dstlen, uint32_t src, uint32_t srcbits) +{ + uint32_t bit; + + for (bit = 0; bit < srcbits; bit += 6) { + if (dstlen < 1) { + return NULL; + } + *dst++ = itoa64[src & 0x3f]; + dstlen--; + src >>= 6; + } + + return dst; +} + +static uint8_t * +encode64(uint8_t * dst, size_t dstlen, const uint8_t * src, size_t srclen) +{ + size_t i; + + for (i = 0; i < srclen; ) { + uint8_t * dnext; + uint32_t value = 0, bits = 0; + do { + value |= (uint32_t)src[i++] << bits; + bits += 8; + } while (bits < 24 && i < srclen); + dnext = encode64_uint32(dst, dstlen, value, bits); + if (!dnext) { + return NULL; + } + dstlen -= dnext - dst; + dst = dnext; + } + + return dst; +} + +static int +decode64_one(uint32_t * dst, uint8_t src) +{ + const char *ptr = strchr(itoa64, src); + + if (ptr) { + *dst = ptr - itoa64; + return 0; + } + *dst = 0; + return -1; +} + +static const uint8_t * +decode64_uint32(uint32_t * dst, uint32_t dstbits, const uint8_t * src) +{ + uint32_t bit; + uint32_t value; + + value = 0; + for (bit = 0; bit < dstbits; bit += 6) { + uint32_t one; + if (decode64_one(&one, *src)) { + *dst = 0; + return NULL; + } + src++; + value |= one << bit; + } + + *dst = value; + return src; +} + +uint8_t * +escrypt_r(escrypt_local_t * local, const uint8_t * passwd, size_t passwdlen, + const uint8_t * setting, uint8_t * buf, size_t buflen) +{ + uint8_t hash[crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES]; + escrypt_kdf_t escrypt_kdf; + const uint8_t *src; + const uint8_t *salt; + uint8_t *dst; + size_t prefixlen; + size_t saltlen; + size_t need; + uint64_t N; + uint32_t N_log2; + uint32_t r; + uint32_t p; + + if (setting[0] != '$' || setting[1] != '7' || setting[2] != '$') { + return NULL; + } + src = setting + 3; + + if (decode64_one(&N_log2, *src)) { + return NULL; + } + src++; + N = (uint64_t)1 << N_log2; + + src = decode64_uint32(&r, 30, src); + if (!src) { + return NULL; + } + src = decode64_uint32(&p, 30, src); + if (!src) { + return NULL; + } + prefixlen = src - setting; + + salt = src; + src = (uint8_t *) strrchr((char *)salt, '$'); + if (src) { + saltlen = src - salt; + } else { + saltlen = strlen((char *)salt); + } + need = prefixlen + saltlen + 1 + + crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1; + if (need > buflen || need < saltlen) { + return NULL; + } +#if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) + escrypt_kdf = + sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; +#else + escrypt_kdf = escrypt_kdf_nosse; +#endif + if (escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + N, r, p, hash, sizeof(hash))) { + return NULL; + } + + dst = buf; + memcpy(dst, setting, prefixlen + saltlen); + dst += prefixlen + saltlen; + *dst++ = '$'; + + dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash)); + sodium_memzero(hash, sizeof hash); + if (!dst || dst >= buf + buflen) { /* Can't happen */ + return NULL; + } + *dst = 0; /* NUL termination */ + + return buf; +} + +uint8_t * +escrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, + const uint8_t * src, size_t srclen, + uint8_t * buf, size_t buflen) +{ + uint8_t *dst; + size_t prefixlen = + (sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */); + size_t saltlen = BYTES2CHARS(srclen); + size_t need; + + need = prefixlen + saltlen + 1; + if (need > buflen || need < saltlen || saltlen < srclen) { + return NULL; + } + if (N_log2 > 63 || ((uint64_t)r * (uint64_t)p >= (1U << 30))) { + return NULL; + } + dst = buf; + *dst++ = '$'; + *dst++ = '7'; + *dst++ = '$'; + + *dst++ = itoa64[N_log2]; + + dst = encode64_uint32(dst, buflen - (dst - buf), r, 30); + if (!dst) { /* Can't happen */ + return NULL; + } + dst = encode64_uint32(dst, buflen - (dst - buf), p, 30); + if (!dst) { /* Can't happen */ + return NULL; + } + dst = encode64(dst, buflen - (dst - buf), src, srclen); + if (!dst || dst >= buf + buflen) { /* Can't happen */ + return NULL; + } + *dst = 0; /* NUL termination */ + + return buf; +} + +int +crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t r, uint32_t p, + uint8_t * buf, size_t buflen) +{ + escrypt_kdf_t escrypt_kdf; + escrypt_local_t local; + int retval; + + if (escrypt_init_local(&local)) { + return -1; + } +#if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) + escrypt_kdf = + sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; +#else + escrypt_kdf = escrypt_kdf_nosse; +#endif + retval = escrypt_kdf(&local, + passwd, passwdlen, salt, saltlen, + N, r, p, buf, buflen); + if (escrypt_free_local(&local)) { + return -1; + } + return retval; +} + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h new file mode 100644 index 0000000000..3f0b7d72f5 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/crypto_scrypt.h @@ -0,0 +1,93 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2009 Colin Percival + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#ifndef _CRYPTO_SCRYPT_H_ +#define _CRYPTO_SCRYPT_H_ + +#include + +#define crypto_pwhash_scryptsalsa208sha256_STRPREFIXBYTES 14 +#define crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES 57 +#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES 32 +#define crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES_ENCODED 43 +#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES 32 +#define crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED 43 + +#define BYTES2CHARS(bytes) ((((bytes) * 8) + 5) / 6) + +typedef struct { + void * base, * aligned; + size_t size; +} escrypt_region_t; + +typedef escrypt_region_t escrypt_local_t; + +extern int escrypt_init_local(escrypt_local_t * __local); + +extern int escrypt_free_local(escrypt_local_t * __local); + +extern void *alloc_region(escrypt_region_t * region, size_t size); +extern int free_region(escrypt_region_t * region); + +typedef int (*escrypt_kdf_t)(escrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, + uint8_t * __buf, size_t __buflen); + +extern int escrypt_kdf_nosse(escrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, + uint8_t * __buf, size_t __buflen); + +extern int escrypt_kdf_sse(escrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __salt, size_t __saltlen, + uint64_t __N, uint32_t __r, uint32_t __p, + uint8_t * __buf, size_t __buflen); + +extern uint8_t * escrypt_r(escrypt_local_t * __local, + const uint8_t * __passwd, size_t __passwdlen, + const uint8_t * __setting, + uint8_t * __buf, size_t __buflen); + +extern uint8_t * escrypt_gensalt_r( + uint32_t __N_log2, uint32_t __r, uint32_t __p, + const uint8_t * __src, size_t __srclen, + uint8_t * __buf, size_t __buflen); + +#endif /* !_CRYPTO_SCRYPT_H_ */ + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h new file mode 100644 index 0000000000..ee5b30f7f1 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/export.h @@ -0,0 +1,38 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef __SODIUM_EXPORT_H__ +#define __SODIUM_EXPORT_H__ + +#ifndef __GNUC__ +# ifdef __attribute__ +# undef __attribute__ +# endif +# define __attribute__(a) +#endif + +#ifdef SODIUM_STATIC +# define SODIUM_EXPORT +#else +# if defined(_MSC_VER) +# ifdef DLL_EXPORT +# define SODIUM_EXPORT __declspec(dllexport) +# else +# define SODIUM_EXPORT __declspec(dllimport) +# endif +# else +# if defined(__SUNPRO_C) +# define SODIUM_EXPORT __attribute__ __global +# elif defined(_MSG_VER) +# define SODIUM_EXPORT extern __declspec(dllexport) +# else +# define SODIUM_EXPORT __attribute__ ((visibility ("default"))) +# endif +# endif +#endif + +#endif + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c new file mode 100644 index 0000000000..97d9ba6878 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/nosse/pwhash_scryptsalsa208sha256_nosse.c @@ -0,0 +1,309 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2009 Colin Percival + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include +#include +#include +#include + +#include "../pbkdf2-sha256.h" +#include "../sysendian.h" +#include "../crypto_scrypt.h" + +static inline void +blkcpy(void * dest, const void * src, size_t len) +{ + size_t * D = (size_t *) dest; + const size_t * S = (const size_t *) src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static inline void +blkxor(void * dest, const void * src, size_t len) +{ + size_t * D = (size_t *) dest; + const size_t * S = (const size_t *) src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] ^= S[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + uint32_t x[16]; + size_t i; + + blkcpy(x, B, 64); + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(const uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 16], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16 + 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8 + r * 16], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint64_t +integerify(const void * B, size_t r) +{ + const uint32_t * X = (const uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY) +{ + uint32_t * X = XY; + uint32_t * Y = &XY[32 * r]; + uint32_t * Z = &XY[64 * r]; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) + X[k] = le32dec(&B[4 * k]); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (32 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) + le32enc(&B[4 * k], X[k]); +} + +/** + * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + * N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +escrypt_kdf_nosse(escrypt_local_t * local, + const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t _r, uint32_t _p, + uint8_t * buf, size_t buflen) +{ + size_t B_size, V_size, XY_size, need; + uint8_t * B; + uint32_t * V, * XY; + size_t r = _r, p = _p; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + return -1; + } + if (r == 0 || p == 0) { + errno = EINVAL; + return -1; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } + + /* Allocate memory. */ + B_size = (size_t)128 * r * p; + V_size = (size_t)128 * r * N; + need = B_size + V_size; + if (need < V_size) { + errno = ENOMEM; + return -1; + } + XY_size = (size_t)256 * r + 64; + need += XY_size; + if (need < XY_size) { + errno = ENOMEM; + return -1; + } + if (local->size < need) { + if (free_region(local)) + return -1; + if (!alloc_region(local, need)) + return -1; + } + B = (uint8_t *)local->aligned; + V = (uint32_t *)((uint8_t *)B + B_size); + XY = (uint32_t *)((uint8_t *)V + V_size); + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[(size_t)128 * i * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); + + /* Success! */ + return 0; +} + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt new file mode 100644 index 0000000000..66bbfe2db9 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/note_to_maintainers.txt @@ -0,0 +1,14 @@ +This folder is only meant for use with nacl, i.e. when sodium is unavailable. + + +The files in this folder were mostly copied from +https://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/crypto_pwhash/scryptsalsa208sha256, +with #ifdef VANILLA_NACL added around each of them as required for this module. + +export.h, utils.h, and runtime.h were copied from +https://github.com/jedisct1/libsodium/tree/0.7.0/src/libsodium/include/sodium. +utils.h was significantly truncated. + +utils.c and runtime.c were copied from +https://github.com/jedisct1/libsodium/blob/0.7.0/src/libsodium/sodium. +utils.c was also significantly truncated. diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c new file mode 100644 index 0000000000..3dfe54db5f --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.c @@ -0,0 +1,97 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +#include +#include + +#include "pbkdf2-sha256.h" +#include "sysendian.h" +#include "utils.h" + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void +PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, + size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) +{ + uint8_t key[32] = {0}; + size_t i; + uint8_t salt_and_ivec[saltlen + 4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + if (passwdlen > 32) { + /* For some reason libsodium allows 64byte keys meaning keys + * between 32byte and 64bytes are not compatible with libsodium. + toxencryptsave should only give 32byte passwds so this isn't an issue here.*/ + crypto_hash_sha256(key, passwd, passwdlen); + } else { + memcpy(key, passwd, passwdlen); + } + + memcpy(salt_and_ivec, salt, saltlen); + + for (i = 0; i * 32 < dkLen; i++) { + be32enc(salt_and_ivec + saltlen, (uint32_t)(i + 1)); + crypto_auth_hmacsha256(U, salt_and_ivec, sizeof(salt_and_ivec), key); + + memcpy(T, U, 32); + + for (j = 2; j <= c; j++) { + crypto_auth_hmacsha256(U, U, 32, key); + + for (k = 0; k < 32; k++) { + T[k] ^= U[k]; + } + } + + clen = dkLen - i * 32; + if (clen > 32) { + clen = 32; + } + memcpy(&buf[i * 32], T, clen); + } + sodium_memzero((void *) key, sizeof(key)); +} + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h new file mode 100644 index 0000000000..b74bc6a340 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pbkdf2-sha256.h @@ -0,0 +1,52 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2005,2007,2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include + +#include + +#include "crypto_auth_hmacsha256.h" + +/** + * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): + * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and + * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). + */ +void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, + uint64_t, uint8_t *, size_t); + +#endif /* !_SHA256_H_ */ + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c new file mode 100644 index 0000000000..52c51abc3b --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/pwhash_scryptsalsa208sha256.c @@ -0,0 +1,211 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#include +#include +#include +#include +#include +//#include + +#include "crypto_pwhash_scryptsalsa208sha256.h" +#include "crypto_scrypt.h" +#include "randombytes.h" +#include "utils.h" + +#define SETTING_SIZE(saltbytes) \ + (sizeof "$7$" - 1U) + \ + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */) + BYTES2CHARS(saltbytes) + +static int +pickparams(unsigned long long opslimit, const size_t memlimit, + uint32_t * const N_log2, uint32_t * const p, uint32_t * const r) +{ + unsigned long long maxN; + unsigned long long maxrp; + + if (opslimit < 32768) { + opslimit = 32768; + } + *r = 8; + if (opslimit < memlimit / 32) { + *p = 1; + maxN = opslimit / (*r * 4); + for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { + if ((uint64_t)(1) << *N_log2 > maxN / 2) { + break; + } + } + } else { + maxN = memlimit / (*r * 128); + for (*N_log2 = 1; *N_log2 < 63; *N_log2 += 1) { + if ((uint64_t) (1) << *N_log2 > maxN / 2) { + break; + } + } + maxrp = (opslimit / 4) / ((uint64_t) (1) << *N_log2); + if (maxrp > 0x3fffffff) { + maxrp = 0x3fffffff; + } + *p = (uint32_t) (maxrp) / *r; + } + return 0; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_saltbytes(void) +{ + return crypto_pwhash_scryptsalsa208sha256_SALTBYTES; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_strbytes(void) +{ + return crypto_pwhash_scryptsalsa208sha256_STRBYTES; +} + +const char * +crypto_pwhash_scryptsalsa208sha256_strprefix(void) +{ + return crypto_pwhash_scryptsalsa208sha256_STRPREFIX; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_interactive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_interactive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_SENSITIVE; +} + +size_t +crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive(void) +{ + return crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_SENSITIVE; +} + +int +crypto_pwhash_scryptsalsa208sha256(unsigned char * const out, + unsigned long long outlen, + const char * const passwd, + unsigned long long passwdlen, + const unsigned char * const salt, + unsigned long long opslimit, + size_t memlimit) +{ + //fprintf(stderr, "Doing that dirty thang!!!!\n"); + uint32_t N_log2; + uint32_t p; + uint32_t r; + + memset(out, 0, outlen); + if (passwdlen > SIZE_MAX || outlen > SIZE_MAX) { + errno = EFBIG; + return -1; + } + if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; + return -1; + } + return crypto_pwhash_scryptsalsa208sha256_ll((const uint8_t *) passwd, + (size_t) passwdlen, + (const uint8_t *) salt, + crypto_pwhash_scryptsalsa208sha256_SALTBYTES, + (uint64_t) (1) << N_log2, r, p, + out, (size_t) outlen); +} + +int +crypto_pwhash_scryptsalsa208sha256_str(char out[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen, + unsigned long long opslimit, + size_t memlimit) +{ + uint8_t salt[crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES]; + char setting[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U]; + escrypt_local_t escrypt_local; + uint32_t N_log2; + uint32_t p; + uint32_t r; + + memset(out, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES); + if (passwdlen > SIZE_MAX) { + errno = EFBIG; + return -1; + } + if (pickparams(opslimit, memlimit, &N_log2, &p, &r) != 0) { + errno = EINVAL; + return -1; + } + randombytes(salt, sizeof salt); + if (escrypt_gensalt_r(N_log2, r, p, salt, sizeof salt, + (uint8_t *) setting, sizeof setting) == NULL) { + errno = EINVAL; + return -1; + } + if (escrypt_init_local(&escrypt_local) != 0) { + return -1; + } + if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, + (const uint8_t *) setting, (uint8_t *) out, + crypto_pwhash_scryptsalsa208sha256_STRBYTES) == NULL) { + escrypt_free_local(&escrypt_local); + errno = EINVAL; + return -1; + } + escrypt_free_local(&escrypt_local); + + (void) sizeof + (int[SETTING_SIZE(crypto_pwhash_scryptsalsa208sha256_STRSALTBYTES) + == crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES ? 1 : -1]); + (void) sizeof + (int[crypto_pwhash_scryptsalsa208sha256_STRSETTINGBYTES + 1U + + crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1U + == crypto_pwhash_scryptsalsa208sha256_STRBYTES ? 1 : -1]); + + return 0; +} + +int +crypto_pwhash_scryptsalsa208sha256_str_verify(const char str[crypto_pwhash_scryptsalsa208sha256_STRBYTES], + const char * const passwd, + unsigned long long passwdlen) +{ + char wanted[crypto_pwhash_scryptsalsa208sha256_STRBYTES]; + escrypt_local_t escrypt_local; + int ret = -1; + + if (memchr(str, 0, crypto_pwhash_scryptsalsa208sha256_STRBYTES) != + &str[crypto_pwhash_scryptsalsa208sha256_STRBYTES - 1U]) { + return -1; + } + if (escrypt_init_local(&escrypt_local) != 0) { + return -1; + } + if (escrypt_r(&escrypt_local, (const uint8_t *) passwd, (size_t) passwdlen, + (const uint8_t *) str, (uint8_t *) wanted, + sizeof wanted) == NULL) { + escrypt_free_local(&escrypt_local); + return -1; + } + escrypt_free_local(&escrypt_local); + ret = sodium_memcmp(wanted, str, sizeof wanted); + sodium_memzero(wanted, sizeof wanted); + + return ret; +} + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c new file mode 100644 index 0000000000..9b5c513193 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.c @@ -0,0 +1,140 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifdef HAVE_ANDROID_GETCPUFEATURES +# include +#endif + +#include "runtime.h" + +typedef struct CPUFeatures_ { + int initialized; + int has_neon; + int has_sse2; + int has_sse3; +} CPUFeatures; + +static CPUFeatures _cpu_features; + +#define CPUID_SSE2 0x04000000 +#define CPUIDECX_SSE3 0x00000001 + +static int +_sodium_runtime_arm_cpu_features(CPUFeatures * const cpu_features) +{ +#ifndef __arm__ + cpu_features->has_neon = 0; + return -1; +#else +# ifdef __APPLE__ +# ifdef __ARM_NEON__ + cpu_features->has_neon = 1; +# else + cpu_features->has_neon = 0; +# endif +# elif defined(HAVE_ANDROID_GETCPUFEATURES) && defined(ANDROID_CPU_ARM_FEATURE_NEON) + cpu_features->has_neon = + (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0x0; +# else + cpu_features->has_neon = 0; +# endif + return 0; +#endif +} + +static void +_cpuid(unsigned int cpu_info[4U], const unsigned int cpu_info_type) +{ +#ifdef _MSC_VER + __cpuidex((int *) cpu_info, cpu_info_type, 0); +#elif defined(HAVE_CPUID) + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; +# ifdef __i386__ + __asm__ __volatile__ ("pushfl; pushfl; " + "popl %0; " + "movl %0, %1; xorl %2, %0; " + "pushl %0; " + "popfl; pushfl; popl %0; popfl" : + "=&r" (cpu_info[0]), "=&r" (cpu_info[1]) : + "i" (0x200000)); + if (((cpu_info[0] ^ cpu_info[1]) & 0x200000) == 0x0) { + return; + } +# endif +# ifdef __i386__ + __asm__ __volatile__ ("xchgl %%ebx, %k1; cpuid; xchgl %%ebx, %k1" : + "=a" (cpu_info[0]), "=&r" (cpu_info[1]), + "=c" (cpu_info[2]), "=d" (cpu_info[3]) : + "0" (cpu_info_type), "2" (0U)); +# elif defined(__x86_64__) + __asm__ __volatile__ ("xchgq %%rbx, %q1; cpuid; xchgq %%rbx, %q1" : + "=a" (cpu_info[0]), "=&r" (cpu_info[1]), + "=c" (cpu_info[2]), "=d" (cpu_info[3]) : + "0" (cpu_info_type), "2" (0U)); +# else + __asm__ __volatile__ ("cpuid" : + "=a" (cpu_info[0]), "=b" (cpu_info[1]), + "=c" (cpu_info[2]), "=d" (cpu_info[3]) : + "0" (cpu_info_type), "2" (0U)); +# endif +#else + cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0; +#endif +} + +static int +_sodium_runtime_intel_cpu_features(CPUFeatures * const cpu_features) +{ + unsigned int cpu_info[4]; + unsigned int id; + + _cpuid(cpu_info, 0x0); + if ((id = cpu_info[0]) == 0U) { + return -1; + } + _cpuid(cpu_info, 0x00000001); +#ifndef HAVE_EMMINTRIN_H + cpu_features->has_sse2 = 0; +#else + cpu_features->has_sse2 = ((cpu_info[3] & CPUID_SSE2) != 0x0); +#endif + +#ifndef HAVE_PMMINTRIN_H + cpu_features->has_sse3 = 0; +#else + cpu_features->has_sse3 = ((cpu_info[2] & CPUIDECX_SSE3) != 0x0); +#endif + + return 0; +} + +int +sodium_runtime_get_cpu_features(void) +{ + int ret = -1; + + ret &= _sodium_runtime_arm_cpu_features(&_cpu_features); + ret &= _sodium_runtime_intel_cpu_features(&_cpu_features); + _cpu_features.initialized = 1; + + return ret; +} + +int +sodium_runtime_has_neon(void) { + return _cpu_features.has_neon; +} + +int +sodium_runtime_has_sse2(void) { + return _cpu_features.has_sse2; +} + +int +sodium_runtime_has_sse3(void) { + return _cpu_features.has_sse3; +} + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h new file mode 100644 index 0000000000..874915ef42 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/runtime.h @@ -0,0 +1,33 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef __SODIUM_RUNTIME_H__ +#define __SODIUM_RUNTIME_H__ 1 + +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +SODIUM_EXPORT +int sodium_runtime_get_cpu_features(void); + +SODIUM_EXPORT +int sodium_runtime_has_neon(void); + +SODIUM_EXPORT +int sodium_runtime_has_sse2(void); + +SODIUM_EXPORT +int sodium_runtime_has_sse3(void); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c new file mode 100644 index 0000000000..5819651454 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/scrypt_platform.c @@ -0,0 +1,107 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef HAVE_SYS_MMAN_H +# include +#endif +#include +#include + +#include "crypto_scrypt.h" +#include "runtime.h" + +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +# define MAP_ANON MAP_ANONYMOUS +#endif + +void * +alloc_region(escrypt_region_t * region, size_t size) +{ + uint8_t * base, * aligned; +#ifdef MAP_ANON + if ((base = (uint8_t *) mmap(NULL, size, PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + base = NULL; + aligned = base; +#elif defined(HAVE_POSIX_MEMALIGN) + if ((errno = posix_memalign((void **) &base, 64, size)) != 0) + base = NULL; + aligned = base; +#else + base = aligned = NULL; + if (size + 63 < size) + errno = ENOMEM; + else if ((base = (uint8_t *) malloc(size + 63)) != NULL) { + aligned = base + 63; + aligned -= (uintptr_t)aligned & 63; + } +#endif + region->base = base; + region->aligned = aligned; + region->size = base ? size : 0; + return aligned; +} + +static inline void +init_region(escrypt_region_t * region) +{ + region->base = region->aligned = NULL; + region->size = 0; +} + +int +free_region(escrypt_region_t * region) +{ + if (region->base) { +#ifdef MAP_ANON + if (munmap(region->base, region->size)) + return -1; +#else + free(region->base); +#endif + } + init_region(region); + return 0; +} + +int +escrypt_init_local(escrypt_local_t * local) +{ + init_region(local); + return 0; +} + +int +escrypt_free_local(escrypt_local_t * local) +{ + return free_region(local); +} + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c new file mode 100644 index 0000000000..856a655e3f --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sse/pwhash_scryptsalsa208sha256_sse.c @@ -0,0 +1,398 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +/*- + * Copyright 2009 Colin Percival + * Copyright 2012,2013 Alexander Peslyak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) +#if __GNUC__ +# pragma GCC target("sse2") +#endif +#include +#if defined(__XOP__) && defined(DISABLED) +# include +#endif + +#include +#include +#include +#include +#include + +#include "../pbkdf2-sha256.h" +#include "../sysendian.h" +#include "../crypto_scrypt.h" + +#if defined(__XOP__) && defined(DISABLED) +#define ARX(out, in1, in2, s) \ + out = _mm_xor_si128(out, _mm_roti_epi32(_mm_add_epi32(in1, in2), s)); +#else +#define ARX(out, in1, in2, s) \ + { \ + __m128i T = _mm_add_epi32(in1, in2); \ + out = _mm_xor_si128(out, _mm_slli_epi32(T, s)); \ + out = _mm_xor_si128(out, _mm_srli_epi32(T, 32-s)); \ + } +#endif + +#define SALSA20_2ROUNDS \ + /* Operate on "columns". */ \ + ARX(X1, X0, X3, 7) \ + ARX(X2, X1, X0, 9) \ + ARX(X3, X2, X1, 13) \ + ARX(X0, X3, X2, 18) \ +\ + /* Rearrange data. */ \ + X1 = _mm_shuffle_epi32(X1, 0x93); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x39); \ +\ + /* Operate on "rows". */ \ + ARX(X3, X0, X1, 7) \ + ARX(X2, X3, X0, 9) \ + ARX(X1, X2, X3, 13) \ + ARX(X0, X1, X2, 18) \ +\ + /* Rearrange data. */ \ + X1 = _mm_shuffle_epi32(X1, 0x39); \ + X2 = _mm_shuffle_epi32(X2, 0x4E); \ + X3 = _mm_shuffle_epi32(X3, 0x93); + +/** + * Apply the salsa20/8 core to the block provided in (X0 ... X3) ^ (Z0 ... Z3). + */ +#define SALSA20_8_XOR(in, out) \ + { \ + __m128i Y0 = X0 = _mm_xor_si128(X0, (in)[0]); \ + __m128i Y1 = X1 = _mm_xor_si128(X1, (in)[1]); \ + __m128i Y2 = X2 = _mm_xor_si128(X2, (in)[2]); \ + __m128i Y3 = X3 = _mm_xor_si128(X3, (in)[3]); \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + SALSA20_2ROUNDS \ + (out)[0] = X0 = _mm_add_epi32(X0, Y0); \ + (out)[1] = X1 = _mm_add_epi32(X1, Y1); \ + (out)[2] = X2 = _mm_add_epi32(X2, Y2); \ + (out)[3] = X3 = _mm_add_epi32(X3, Y3); \ + } + +/** + * blockmix_salsa8(Bin, Bout, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. + */ +static inline void +blockmix_salsa8(const __m128i * Bin, __m128i * Bout, size_t r) +{ + __m128i X0, X1, X2, X3; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + X0 = Bin[8 * r - 4]; + X1 = Bin[8 * r - 3]; + X2 = Bin[8 * r - 2]; + X3 = Bin[8 * r - 1]; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(Bin, Bout) + + /* 2: for i = 0 to 2r - 1 do */ + r--; + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8], &Bout[i * 4]) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + SALSA20_8_XOR(&Bin[i * 8 + 4], &Bout[(r + i) * 4 + 4]) +} + +#define XOR4(in) \ + X0 = _mm_xor_si128(X0, (in)[0]); \ + X1 = _mm_xor_si128(X1, (in)[1]); \ + X2 = _mm_xor_si128(X2, (in)[2]); \ + X3 = _mm_xor_si128(X3, (in)[3]); + +#define XOR4_2(in1, in2) \ + X0 = _mm_xor_si128((in1)[0], (in2)[0]); \ + X1 = _mm_xor_si128((in1)[1], (in2)[1]); \ + X2 = _mm_xor_si128((in1)[2], (in2)[2]); \ + X3 = _mm_xor_si128((in1)[3], (in2)[3]); + +static inline uint32_t +blockmix_salsa8_xor(const __m128i * Bin1, const __m128i * Bin2, __m128i * Bout, + size_t r) +{ + __m128i X0, X1, X2, X3; + size_t i; + + /* 1: X <-- B_{2r - 1} */ + XOR4_2(&Bin1[8 * r - 4], &Bin2[8 * r - 4]) + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(Bin1) + SALSA20_8_XOR(Bin2, Bout) + + /* 2: for i = 0 to 2r - 1 do */ + r--; + for (i = 0; i < r;) { + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8 + 4]) + SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + i++; + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8]) + SALSA20_8_XOR(&Bin2[i * 8], &Bout[i * 4]) + } + + /* 3: X <-- H(X \xor B_i) */ + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + XOR4(&Bin1[i * 8 + 4]) + SALSA20_8_XOR(&Bin2[i * 8 + 4], &Bout[(r + i) * 4 + 4]) + + return _mm_cvtsi128_si32(X0); +} + +#undef ARX +#undef SALSA20_2ROUNDS +#undef SALSA20_8_XOR +#undef XOR4 +#undef XOR4_2 + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static inline uint32_t +integerify(const void * B, size_t r) +{ + return *(const uint32_t *)((uintptr_t)(B) + (2 * r - 1) * 64); +} + +/** + * smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +static void +smix(uint8_t * B, size_t r, uint32_t N, void * V, void * XY) +{ + size_t s = 128 * r; + __m128i * X = (__m128i *) V, * Y; + uint32_t * X32 = (uint32_t *) V; + uint32_t i, j; + size_t k; + + /* 1: X <-- B */ + /* 3: V_i <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + X32[k * 16 + i] = + le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + /* 2: for i = 0 to N - 1 do */ + for (i = 1; i < N - 1; i += 2) { + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = (__m128i *)((uintptr_t)(V) + i * s); + blockmix_salsa8(X, Y, r); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = (__m128i *)((uintptr_t)(V) + (i + 1) * s); + blockmix_salsa8(Y, X, r); + } + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + Y = (__m128i *)((uintptr_t)(V) + i * s); + blockmix_salsa8(X, Y, r); + + /* 4: X <-- H(X) */ + /* 3: V_i <-- X */ + X = (__m128i *) XY; + blockmix_salsa8(Y, X, r); + + X32 = (uint32_t *) XY; + Y = (__m128i *)((uintptr_t)(XY) + s); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + __m128i * V_j = (__m128i *)((uintptr_t)(V) + j * s); + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_salsa8_xor(X, V_j, Y, r) & (N - 1); + V_j = (__m128i *)((uintptr_t)(V) + j * s); + + /* 8: X <-- H(X \xor V_j) */ + /* 7: j <-- Integerify(X) mod N */ + j = blockmix_salsa8_xor(Y, V_j, X, r) & (N - 1); + } + + /* 10: B' <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], + X32[k * 16 + i]); + } + } +} + +/** + * escrypt_kdf(local, passwd, passwdlen, salt, saltlen, + * N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +escrypt_kdf_sse(escrypt_local_t * local, + const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, + uint64_t N, uint32_t _r, uint32_t _p, + uint8_t * buf, size_t buflen) +{ + size_t B_size, V_size, XY_size, need; + uint8_t * B; + uint32_t * V, * XY; + size_t r = _r, p = _p; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + return -1; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + return -1; + } + if (N > UINT32_MAX) { + errno = EFBIG; + return -1; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + return -1; + } + if (r == 0 || p == 0) { + errno = EINVAL; + return -1; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > SIZE_MAX / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + return -1; + } + + /* Allocate memory. */ + B_size = (size_t)128 * r * p; + V_size = (size_t)128 * r * N; + need = B_size + V_size; + if (need < V_size) { + errno = ENOMEM; + return -1; + } + XY_size = (size_t)256 * r + 64; + need += XY_size; + if (need < XY_size) { + errno = ENOMEM; + return -1; + } + if (local->size < need) { + if (free_region(local)) + return -1; + if (!alloc_region(local, need)) + return -1; + } + B = (uint8_t *)local->aligned; + V = (uint32_t *)((uint8_t *)B + B_size); + XY = (uint32_t *)((uint8_t *)V + V_size); + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, B_size); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + smix(&B[(size_t)128 * i * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf, buflen); + + /* Success! */ + return 0; +} +#endif + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h new file mode 100644 index 0000000000..04e5c1ed45 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/sysendian.h @@ -0,0 +1,153 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef _SYSENDIAN_H_ +#define _SYSENDIAN_H_ + +#include + +/* Avoid namespace collisions with BSD . */ +#define be16dec scrypt_be16dec +#define be16enc scrypt_be16enc +#define be32dec scrypt_be32dec +#define be32enc scrypt_be32enc +#define be64dec scrypt_be64dec +#define be64enc scrypt_be64enc +#define le16dec scrypt_le16dec +#define le16enc scrypt_le16enc +#define le32dec scrypt_le32dec +#define le32enc scrypt_le32enc +#define le64dec scrypt_le64dec +#define le64enc scrypt_le64enc + +static inline uint16_t +be16dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint16_t)(p[1]) + ((uint16_t)(p[0]) << 8)); +} + +static inline void +be16enc(void *pp, uint16_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[1] = x & 0xff; + p[0] = (x >> 8) & 0xff; +} + +static inline uint32_t +be32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); +} + +static inline void +be32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[3] = x & 0xff; + p[2] = (x >> 8) & 0xff; + p[1] = (x >> 16) & 0xff; + p[0] = (x >> 24) & 0xff; +} + +static inline uint64_t +be64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); +} + +static inline void +be64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[7] = x & 0xff; + p[6] = (x >> 8) & 0xff; + p[5] = (x >> 16) & 0xff; + p[4] = (x >> 24) & 0xff; + p[3] = (x >> 32) & 0xff; + p[2] = (x >> 40) & 0xff; + p[1] = (x >> 48) & 0xff; + p[0] = (x >> 56) & 0xff; +} + +static inline uint16_t +le16dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint16_t)(p[0]) + ((uint16_t)(p[1]) << 8)); +} + +static inline void +le16enc(void *pp, uint16_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; +} + +static inline uint32_t +le32dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); +} + +static inline void +le32enc(void *pp, uint32_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; +} + +static inline uint64_t +le64dec(const void *pp) +{ + const uint8_t *p = (uint8_t const *)pp; + + return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + + ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + + ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + + ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); +} + +static inline void +le64enc(void *pp, uint64_t x) +{ + uint8_t * p = (uint8_t *)pp; + + p[0] = x & 0xff; + p[1] = (x >> 8) & 0xff; + p[2] = (x >> 16) & 0xff; + p[3] = (x >> 24) & 0xff; + p[4] = (x >> 32) & 0xff; + p[5] = (x >> 40) & 0xff; + p[6] = (x >> 48) & 0xff; + p[7] = (x >> 56) & 0xff; +} + +#endif /* !_SYSENDIAN_H_ */ + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c new file mode 100644 index 0000000000..e61ccf3ecf --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.c @@ -0,0 +1,78 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef __STDC_WANT_LIB_EXT1__ +# define __STDC_WANT_LIB_EXT1__ 1 +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_MMAN_H +# include +#endif + +#include "utils.h" + +#ifdef _WIN32 +# include +# include +#else +# include +#endif + +#ifdef HAVE_WEAK_SYMBOLS +__attribute__((weak)) void +__sodium_dummy_symbol_to_prevent_lto(void * const pnt, const size_t len) +{ + (void) pnt; + (void) len; +} +#endif + +void +sodium_memzero(void * const pnt, const size_t len) +{ +#ifdef _WIN32 + SecureZeroMemory(pnt, len); +#elif defined(HAVE_MEMSET_S) + if (memset_s(pnt, (rsize_t) len, 0, (rsize_t) len) != 0) { + abort(); + } +#elif defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(pnt, len); +#elif HAVE_WEAK_SYMBOLS + memset(pnt, 0, len); + __sodium_dummy_symbol_to_prevent_lto(pnt, len); +#else + volatile unsigned char *pnt_ = (volatile unsigned char *) pnt; + size_t i = (size_t) 0U; + + while (i < len) { + pnt_[i++] = 0U; + } +#endif +} + +int +sodium_memcmp(const void * const b1_, const void * const b2_, size_t len) +{ + const unsigned char *b1 = (const unsigned char *) b1_; + const unsigned char *b2 = (const unsigned char *) b2_; + size_t i; + unsigned char d = (unsigned char) 0U; + + for (i = 0U; i < len; i++) { + d |= b1[i] ^ b2[i]; + } + return (int) ((1 & ((d - 1) >> 8)) - 1); +} + +#endif diff --git a/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h new file mode 100644 index 0000000000..fb2020c35d --- /dev/null +++ b/libs/libtox/src/toxencryptsave/crypto_pwhash_scryptsalsa208sha256/utils.h @@ -0,0 +1,40 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef VANILLA_NACL /* toxcore only uses this when libsodium is unavailable */ + +#ifndef __SODIUM_UTILS_H__ +#define __SODIUM_UTILS_H__ + +#include + +#include "export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__cplusplus) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L +# define _SODIUM_C99(X) +#else +# define _SODIUM_C99(X) X +#endif + +SODIUM_EXPORT +void sodium_memzero(void * const pnt, const size_t len); + +/* WARNING: sodium_memcmp() must be used to verify if two secret keys + * are equal, in constant time. + * It returns 0 if the keys are equal, and -1 if they differ. + * This function is not designed for lexicographical comparisons. + */ +SODIUM_EXPORT +int sodium_memcmp(const void * const b1_, const void * const b2_, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/libs/libtox/src/toxencryptsave/defines.h b/libs/libtox/src/toxencryptsave/defines.h new file mode 100644 index 0000000000..e3fca073e3 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/defines.h @@ -0,0 +1,2 @@ +#define TOX_ENC_SAVE_MAGIC_NUMBER "toxEsave" +#define TOX_ENC_SAVE_MAGIC_LENGTH 8 diff --git a/libs/libtox/src/toxencryptsave/toxencryptsave.api.h b/libs/libtox/src/toxencryptsave/toxencryptsave.api.h new file mode 100644 index 0000000000..61f685f86b --- /dev/null +++ b/libs/libtox/src/toxencryptsave/toxencryptsave.api.h @@ -0,0 +1,327 @@ +%{ +/* + * Batch encryption functions. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013-2016 Tox Developers. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef TOXENCRYPTSAVE_H +#define TOXENCRYPTSAVE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +%} + +/******************************************************************************* + * + * This module is organized into two parts. + * + * 1. A simple API operating on plain text/cipher text data and a password to + * encrypt or decrypt it. + * 2. A more advanced API that splits key derivation and encryption into two + * separate function calls. + * + * The first part is implemented in terms of the second part and simply calls + * the separate functions in sequence. Since key derivation is very expensive + * compared to the actual encryption, clients that do a lot of crypto should + * prefer the advanced API and reuse pass-key objects. + * + * To use the second part, first derive an encryption key from a password with + * ${tox.pass_Key.derive}, then use the derived key to encrypt the data. + * + * The encrypted data is prepended with a magic number, to aid validity + * checking (no guarantees are made of course). Any data to be decrypted must + * start with the magic number. + * + * Clients should consider alerting their users that, unlike plain data, if + * even one bit becomes corrupted, the data will be entirely unrecoverable. + * Ditto if they forget their password, there is no way to recover the data. + * + *******************************************************************************/ + +class tox { + +/** + * The size of the salt part of a pass-key. + */ +const PASS_SALT_LENGTH = 32; +/** + * The size of the key part of a pass-key. + */ +const PASS_KEY_LENGTH = 32; +/** + * The amount of additional data required to store any encrypted byte array. + * Encrypting an array of N bytes requires N + $PASS_ENCRYPTION_EXTRA_LENGTH + * bytes in the encrypted byte array. + */ +const PASS_ENCRYPTION_EXTRA_LENGTH = 80; + +error for key_derivation { + NULL, + /** + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. + */ + FAILED, +} + +error for encryption { + NULL, + /** + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. + */ + KEY_DERIVATION_FAILED, + /** + * The encryption itself failed. + */ + FAILED, +} + +error for decryption { + NULL, + /** + * The input data was shorter than $PASS_ENCRYPTION_EXTRA_LENGTH bytes + */ + INVALID_LENGTH, + /** + * The input data is missing the magic number (i.e. wasn't created by this + * module, or is corrupted). + */ + BAD_FORMAT, + /** + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. + */ + KEY_DERIVATION_FAILED, + /** + * The encrypted byte array could not be decrypted. Either the data was + * corrupted or the password/key was incorrect. + */ + FAILED, +} + + +/******************************************************************************* + * + * BEGIN PART 1 + * + * The simple API is presented first. If your code spends too much time using + * these functions, consider using the advanced functions instead and caching + * the generated pass-key. + * + *******************************************************************************/ + +/** + * Encrypts the given data with the given passphrase. + * + * The output array must be at least `plaintext_len + $PASS_ENCRYPTION_EXTRA_LENGTH` + * bytes long. This delegates to ${pass_Key.derive} and + * ${pass_Key.encrypt}. + * + * @param plaintext A byte array of length `plaintext_len`. + * @param plaintext_len The length of the plain text array. Bigger than 0. + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * @param ciphertext The cipher text array to write the encrypted data to. + * + * @return true on success. + */ +static bool pass_encrypt(const uint8_t[plaintext_len] plaintext, const uint8_t[passphrase_len] passphrase, uint8_t *ciphertext) + with error for encryption; + + +/** + * Decrypts the given data with the given passphrase. + * + * The output array must be at least `ciphertext_len - $PASS_ENCRYPTION_EXTRA_LENGTH` + * bytes long. This delegates to ${pass_Key.decrypt}. + * + * @param ciphertext A byte array of length `ciphertext_len`. + * @param ciphertext_len The length of the cipher text array. At least $PASS_ENCRYPTION_EXTRA_LENGTH. + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * @param plaintext The plain text array to write the decrypted data to. + * + * @return true on success. + */ +static bool pass_decrypt(const uint8_t[ciphertext_len] ciphertext, const uint8_t[passphrase_len] passphrase, uint8_t *plaintext) + with error for decryption; + + +/******************************************************************************* + * + * BEGIN PART 2 + * + * And now part 2, which does the actual encryption, and can be used to write + * less CPU intensive client code than part one. + * + *******************************************************************************/ + +class pass_Key { + /** + * This type represents a pass-key. + * + * A pass-key and a password are two different concepts: a password is given + * by the user in plain text. A pass-key is the generated symmetric key used + * for encryption and decryption. It is derived from a salt and the user- + * provided password. + * + * The $this structure is hidden in the implementation. It can be allocated + * using $new and must be deallocated using $free. + */ + struct this; + + /** + * Create a new $this. The initial value of it is indeterminate. To + * initialise it, use one of the derive_* functions below. + * + * In case of failure, this function returns NULL. The only failure mode at + * this time is memory allocation failure, so this function has no error code. + */ + static this new(); + + /** + * Deallocate a $this. This function behaves like free(), so NULL is an + * acceptable argument value. + */ + void free(); + + /** + * Generates a secret symmetric key from the given passphrase. + * + * Be sure to not compromise the key! Only keep it in memory, do not write + * it to disk. + * + * Note that this function is not deterministic; to derive the same key from + * a password, you also must know the random salt that was used. A + * deterministic version of this function is $derive_with_salt. + * + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * + * @return true on success. + */ + bool derive(const uint8_t[passphrase_len] passphrase) + with error for key_derivation; + + /** + * Same as above, except use the given salt for deterministic key derivation. + * + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * @param salt An array of at least $PASS_SALT_LENGTH bytes. + * + * @return true on success. + */ + bool derive_with_salt(const uint8_t[passphrase_len] passphrase, const uint8_t[PASS_SALT_LENGTH] salt) + with error for key_derivation; + + /** + * Encrypt a plain text with a key produced by $derive or $derive_with_salt. + * + * The output array must be at least `plaintext_len + $PASS_ENCRYPTION_EXTRA_LENGTH` + * bytes long. + * + * @param plaintext A byte array of length `plaintext_len`. + * @param plaintext_len The length of the plain text array. Bigger than 0. + * @param ciphertext The cipher text array to write the encrypted data to. + * + * @return true on success. + */ + const bool encrypt(const uint8_t[plaintext_len] plaintext, uint8_t *ciphertext) + with error for encryption; + + /** + * This is the inverse of $encrypt, also using only keys produced by + * $derive or $derive_with_salt. + * + * @param ciphertext A byte array of length `ciphertext_len`. + * @param ciphertext_len The length of the cipher text array. At least $PASS_ENCRYPTION_EXTRA_LENGTH. + * @param plaintext The plain text array to write the decrypted data to. + * + * @return true on success. + */ + const bool decrypt(const uint8_t[ciphertext_len] ciphertext, uint8_t *plaintext) + with error for decryption; +} + +/** + * Retrieves the salt used to encrypt the given data. + * + * The retrieved salt can then be passed to ${pass_Key.derive_with_salt} to + * produce the same key as was previously used. Any data encrypted with this + * module can be used as input. + * + * The cipher text must be at least $PASS_ENCRYPTION_EXTRA_LENGTH bytes in length. + * The salt must be $PASS_SALT_LENGTH bytes in length. + * If the passed byte arrays are smaller than required, the behaviour is + * undefined. + * + * If the cipher text pointer or the salt is NULL, this function returns false. + * + * Success does not say anything about the validity of the data, only that + * data of the appropriate size was copied. + * + * @return true on success. + */ +static bool get_salt(const uint8_t *ciphertext, uint8_t[PASS_SALT_LENGTH] salt) { + NULL, + /** + * The input data is missing the magic number (i.e. wasn't created by this + * module, or is corrupted). + */ + BAD_FORMAT, +} + +/** + * Determines whether or not the given data is encrypted by this module. + * + * It does this check by verifying that the magic number is the one put in + * place by the encryption functions. + * + * The data must be at least $PASS_ENCRYPTION_EXTRA_LENGTH bytes in length. + * If the passed byte array is smaller than required, the behaviour is + * undefined. + * + * If the data pointer is NULL, the behaviour is undefined + * + * @return true if the data is encrypted by this module. + */ +static bool is_data_encrypted(const uint8_t *data); + +} + +%{ + +#ifdef __cplusplus +} +#endif + +#endif +%} diff --git a/libs/libtox/src/toxencryptsave/toxencryptsave.c b/libs/libtox/src/toxencryptsave/toxencryptsave.c new file mode 100644 index 0000000000..5640e82fc7 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/toxencryptsave.c @@ -0,0 +1,338 @@ +/* + * Batch encryption functions. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013 Tox project. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "../toxcore/crypto_core.h" +#include "defines.h" +#include "toxencryptsave.h" +#define SET_ERROR_PARAMETER(param, x) {if(param) {*param = x;}} + +#ifdef VANILLA_NACL +#include +#include +#include "crypto_pwhash_scryptsalsa208sha256/crypto_pwhash_scryptsalsa208sha256.h" +#define crypto_box_MACBYTES (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) +#else +#include +#endif + +#include + +#if TOX_PASS_SALT_LENGTH != crypto_pwhash_scryptsalsa208sha256_SALTBYTES +#error TOX_PASS_SALT_LENGTH is assumed to be equal to crypto_pwhash_scryptsalsa208sha256_SALTBYTES +#endif + +#if TOX_PASS_KEY_LENGTH != CRYPTO_SHARED_KEY_SIZE +#error TOX_PASS_KEY_LENGTH is assumed to be equal to CRYPTO_SHARED_KEY_SIZE +#endif + +#if TOX_PASS_ENCRYPTION_EXTRA_LENGTH != (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) +#error TOX_PASS_ENCRYPTION_EXTRA_LENGTH is assumed to be equal to (crypto_box_MACBYTES + crypto_box_NONCEBYTES + crypto_pwhash_scryptsalsa208sha256_SALTBYTES + TOX_ENC_SAVE_MAGIC_LENGTH) +#endif + +uint32_t tox_pass_salt_length(void) +{ + return TOX_PASS_SALT_LENGTH; +} +uint32_t tox_pass_key_length(void) +{ + return TOX_PASS_KEY_LENGTH; +} +uint32_t tox_pass_encryption_extra_length(void) +{ + return TOX_PASS_ENCRYPTION_EXTRA_LENGTH; +} + +struct Tox_Pass_Key { + uint8_t salt[TOX_PASS_SALT_LENGTH]; + uint8_t key[TOX_PASS_KEY_LENGTH]; +}; + +Tox_Pass_Key *tox_pass_key_new(void) +{ + return (Tox_Pass_Key *)malloc(sizeof(Tox_Pass_Key)); +} + +void tox_pass_key_free(Tox_Pass_Key *pass_key) +{ + free(pass_key); +} + +/* Clients should consider alerting their users that, unlike plain data, if even one bit + * becomes corrupted, the data will be entirely unrecoverable. + * Ditto if they forget their password, there is no way to recover the data. + */ + +/* This retrieves the salt used to encrypt the given data, which can then be passed to + * tox_pass_key_derive_with_salt to produce the same key as was previously used. Any encrpyted + * data with this module can be used as input. + * + * returns true if magic number matches + * success does not say anything about the validity of the data, only that data of + * the appropriate size was copied + */ +bool tox_get_salt(const uint8_t *data, uint8_t *salt, TOX_ERR_GET_SALT *error) +{ + if (!data || !salt) { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_SALT_NULL); + return false; + } + + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_GET_SALT_BAD_FORMAT); + return false; + } + + data += TOX_ENC_SAVE_MAGIC_LENGTH; + memcpy(salt, data, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + SET_ERROR_PARAMETER(error, TOX_ERR_GET_SALT_OK); + return true; +} + +/* Generates a secret symmetric key from the given passphrase. out_key must be at least + * TOX_PASS_KEY_LENGTH bytes long. + * Be sure to not compromise the key! Only keep it in memory, do not write to disk. + * The password is zeroed after key derivation. + * The key should only be used with the other functions in this module, as it + * includes a salt. + * Note that this function is not deterministic; to derive the same key from a + * password, you also must know the random salt that was used. See below. + * + * returns true on success + */ +bool tox_pass_key_derive(Tox_Pass_Key *out_key, const uint8_t *passphrase, size_t pplength, + TOX_ERR_KEY_DERIVATION *error) +{ + uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; + randombytes(salt, sizeof salt); + return tox_pass_key_derive_with_salt(out_key, passphrase, pplength, salt, error); +} + +/* Same as above, except with use the given salt for deterministic key derivation. + * The salt must be TOX_PASS_SALT_LENGTH bytes in length. + */ +bool tox_pass_key_derive_with_salt(Tox_Pass_Key *out_key, const uint8_t *passphrase, size_t pplength, + const uint8_t *salt, TOX_ERR_KEY_DERIVATION *error) +{ + if (!salt || !out_key || (!passphrase && pplength != 0)) { + SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_NULL); + return 0; + } + + uint8_t passkey[crypto_hash_sha256_BYTES]; + crypto_hash_sha256(passkey, passphrase, pplength); + + uint8_t key[CRYPTO_SHARED_KEY_SIZE]; + + /* Derive a key from the password */ + /* http://doc.libsodium.org/key_derivation/README.html */ + /* note that, according to the documentation, a generic pwhash interface will be created + * once the pwhash competition (https://password-hashing.net/) is over */ + if (crypto_pwhash_scryptsalsa208sha256( + key, sizeof(key), (char *)passkey, sizeof(passkey), salt, + crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE * 2, /* slightly stronger */ + crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) != 0) { + /* out of memory most likely */ + SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_FAILED); + return 0; + } + + sodium_memzero(passkey, crypto_hash_sha256_BYTES); /* wipe plaintext pw */ + memcpy(out_key->salt, salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + memcpy(out_key->key, key, CRYPTO_SHARED_KEY_SIZE); + SET_ERROR_PARAMETER(error, TOX_ERR_KEY_DERIVATION_OK); + return 1; +} + +/* Encrypt arbitrary with a key produced by tox_derive_key_*. The output + * array must be at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. + * key must be TOX_PASS_KEY_LENGTH bytes. + * If you already have a symmetric key from somewhere besides this module, simply + * call encrypt_data_symmetric in toxcore/crypto_core directly. + * + * returns true on success + */ +bool tox_pass_key_encrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t data_len, uint8_t *out, + TOX_ERR_ENCRYPTION *error) +{ + if (data_len == 0 || !data || !key || !out) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL); + return 0; + } + + /* the output data consists of, in order: + * salt, nonce, mac, enc_data + * where the mac is automatically prepended by the encrypt() + * the salt+nonce is called the prefix + * I'm not sure what else I'm supposed to do with the salt and nonce, since we + * need them to decrypt the data + */ + + /* first add the magic number */ + memcpy(out, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH); + out += TOX_ENC_SAVE_MAGIC_LENGTH; + + /* then add the rest prefix */ + memcpy(out, key->salt, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + out += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; + + uint8_t nonce[crypto_box_NONCEBYTES]; + random_nonce(nonce); + memcpy(out, nonce, crypto_box_NONCEBYTES); + out += crypto_box_NONCEBYTES; + + /* now encrypt */ + if (encrypt_data_symmetric(key->key, nonce, data, data_len, out) + != data_len + crypto_box_MACBYTES) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_FAILED); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_OK); + return 1; +} + +/* Encrypts the given data with the given passphrase. The output array must be + * at least data_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates + * to tox_derive_key and tox_pass_key_encrypt. + * + * returns true on success + */ +bool tox_pass_encrypt(const uint8_t *data, size_t data_len, const uint8_t *passphrase, size_t pplength, uint8_t *out, + TOX_ERR_ENCRYPTION *error) +{ + Tox_Pass_Key key; + TOX_ERR_KEY_DERIVATION _error; + + if (!tox_pass_key_derive(&key, passphrase, pplength, &_error)) { + if (_error == TOX_ERR_KEY_DERIVATION_NULL) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_NULL); + } else if (_error == TOX_ERR_KEY_DERIVATION_FAILED) { + SET_ERROR_PARAMETER(error, TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED); + } + + return 0; + } + + return tox_pass_key_encrypt(&key, data, data_len, out, error); +} + +/* This is the inverse of tox_pass_key_encrypt, also using only keys produced by + * tox_derive_key. + * + * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH + * + * returns true on success + */ +bool tox_pass_key_decrypt(const Tox_Pass_Key *key, const uint8_t *data, size_t length, uint8_t *out, + TOX_ERR_DECRYPTION *error) +{ + if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH); + return 0; + } + + if (!data || !key || !out) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL); + return 0; + } + + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT); + return 0; + } + + data += TOX_ENC_SAVE_MAGIC_LENGTH; + data += crypto_pwhash_scryptsalsa208sha256_SALTBYTES; // salt only affects key derivation + + size_t decrypt_length = length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH; + + uint8_t nonce[crypto_box_NONCEBYTES]; + memcpy(nonce, data, crypto_box_NONCEBYTES); + data += crypto_box_NONCEBYTES; + + /* decrypt the data */ + if (decrypt_data_symmetric(key->key, nonce, data, decrypt_length + crypto_box_MACBYTES, out) + != decrypt_length) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_FAILED); + return 0; + } + + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_OK); + return 1; +} + +/* Decrypts the given data with the given passphrase. The output array must be + * at least data_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes long. This delegates + * to tox_pass_key_decrypt. + * + * the output data has size data_length - TOX_PASS_ENCRYPTION_EXTRA_LENGTH + * + * returns true on success + */ +bool tox_pass_decrypt(const uint8_t *data, size_t length, const uint8_t *passphrase, size_t pplength, uint8_t *out, + TOX_ERR_DECRYPTION *error) +{ + if (length <= TOX_PASS_ENCRYPTION_EXTRA_LENGTH) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_INVALID_LENGTH); + return 0; + } + + if (!data || !passphrase || !out) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_NULL); + return 0; + } + + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) != 0) { + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_BAD_FORMAT); + return 0; + } + + uint8_t salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; + memcpy(salt, data + TOX_ENC_SAVE_MAGIC_LENGTH, crypto_pwhash_scryptsalsa208sha256_SALTBYTES); + + /* derive the key */ + Tox_Pass_Key key; + + if (!tox_pass_key_derive_with_salt(&key, passphrase, pplength, salt, NULL)) { + /* out of memory most likely */ + SET_ERROR_PARAMETER(error, TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED); + return 0; + } + + return tox_pass_key_decrypt(&key, data, length, out, error); +} + +/* Determines whether or not the given data is encrypted (by checking the magic number) + */ +bool tox_is_data_encrypted(const uint8_t *data) +{ + if (memcmp(data, TOX_ENC_SAVE_MAGIC_NUMBER, TOX_ENC_SAVE_MAGIC_LENGTH) == 0) { + return 1; + } + + return 0; +} diff --git a/libs/libtox/src/toxencryptsave/toxencryptsave.h b/libs/libtox/src/toxencryptsave/toxencryptsave.h new file mode 100644 index 0000000000..ef1ab15289 --- /dev/null +++ b/libs/libtox/src/toxencryptsave/toxencryptsave.h @@ -0,0 +1,388 @@ +/* + * Batch encryption functions. + */ + +/* + * Copyright © 2016-2017 The TokTok team. + * Copyright © 2013-2016 Tox Developers. + * + * This file is part of Tox, the free peer to peer instant messenger. + * + * Tox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tox is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tox. If not, see . + */ +#ifndef TOXENCRYPTSAVE_H +#define TOXENCRYPTSAVE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + + +/******************************************************************************* + * + * This module is organized into two parts. + * + * 1. A simple API operating on plain text/cipher text data and a password to + * encrypt or decrypt it. + * 2. A more advanced API that splits key derivation and encryption into two + * separate function calls. + * + * The first part is implemented in terms of the second part and simply calls + * the separate functions in sequence. Since key derivation is very expensive + * compared to the actual encryption, clients that do a lot of crypto should + * prefer the advanced API and reuse pass-key objects. + * + * To use the second part, first derive an encryption key from a password with + * tox_pass_key_derive, then use the derived key to encrypt the data. + * + * The encrypted data is prepended with a magic number, to aid validity + * checking (no guarantees are made of course). Any data to be decrypted must + * start with the magic number. + * + * Clients should consider alerting their users that, unlike plain data, if + * even one bit becomes corrupted, the data will be entirely unrecoverable. + * Ditto if they forget their password, there is no way to recover the data. + * + ******************************************************************************/ + + + +/** + * The size of the salt part of a pass-key. + */ +#define TOX_PASS_SALT_LENGTH 32 + +uint32_t tox_pass_salt_length(void); + +/** + * The size of the key part of a pass-key. + */ +#define TOX_PASS_KEY_LENGTH 32 + +uint32_t tox_pass_key_length(void); + +/** + * The amount of additional data required to store any encrypted byte array. + * Encrypting an array of N bytes requires N + TOX_PASS_ENCRYPTION_EXTRA_LENGTH + * bytes in the encrypted byte array. + */ +#define TOX_PASS_ENCRYPTION_EXTRA_LENGTH 80 + +uint32_t tox_pass_encryption_extra_length(void); + +typedef enum TOX_ERR_KEY_DERIVATION { + + /** + * The function returned successfully. + */ + TOX_ERR_KEY_DERIVATION_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_KEY_DERIVATION_NULL, + + /** + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. + */ + TOX_ERR_KEY_DERIVATION_FAILED, + +} TOX_ERR_KEY_DERIVATION; + + +typedef enum TOX_ERR_ENCRYPTION { + + /** + * The function returned successfully. + */ + TOX_ERR_ENCRYPTION_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_ENCRYPTION_NULL, + + /** + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. + */ + TOX_ERR_ENCRYPTION_KEY_DERIVATION_FAILED, + + /** + * The encryption itself failed. + */ + TOX_ERR_ENCRYPTION_FAILED, + +} TOX_ERR_ENCRYPTION; + + +typedef enum TOX_ERR_DECRYPTION { + + /** + * The function returned successfully. + */ + TOX_ERR_DECRYPTION_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_DECRYPTION_NULL, + + /** + * The input data was shorter than TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes + */ + TOX_ERR_DECRYPTION_INVALID_LENGTH, + + /** + * The input data is missing the magic number (i.e. wasn't created by this + * module, or is corrupted). + */ + TOX_ERR_DECRYPTION_BAD_FORMAT, + + /** + * The crypto lib was unable to derive a key from the given passphrase, + * which is usually a lack of memory issue. The functions accepting keys + * do not produce this error. + */ + TOX_ERR_DECRYPTION_KEY_DERIVATION_FAILED, + + /** + * The encrypted byte array could not be decrypted. Either the data was + * corrupted or the password/key was incorrect. + */ + TOX_ERR_DECRYPTION_FAILED, + +} TOX_ERR_DECRYPTION; + + + +/******************************************************************************* + * + * BEGIN PART 1 + * + * The simple API is presented first. If your code spends too much time using + * these functions, consider using the advanced functions instead and caching + * the generated pass-key. + * + ******************************************************************************/ + + + +/** + * Encrypts the given data with the given passphrase. + * + * The output array must be at least `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` + * bytes long. This delegates to tox_pass_key_derive and + * tox_pass_key_encrypt. + * + * @param plaintext A byte array of length `plaintext_len`. + * @param plaintext_len The length of the plain text array. Bigger than 0. + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * @param ciphertext The cipher text array to write the encrypted data to. + * + * @return true on success. + */ +bool tox_pass_encrypt(const uint8_t *plaintext, size_t plaintext_len, const uint8_t *passphrase, size_t passphrase_len, + uint8_t *ciphertext, TOX_ERR_ENCRYPTION *error); + +/** + * Decrypts the given data with the given passphrase. + * + * The output array must be at least `ciphertext_len - TOX_PASS_ENCRYPTION_EXTRA_LENGTH` + * bytes long. This delegates to tox_pass_key_decrypt. + * + * @param ciphertext A byte array of length `ciphertext_len`. + * @param ciphertext_len The length of the cipher text array. At least TOX_PASS_ENCRYPTION_EXTRA_LENGTH. + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * @param plaintext The plain text array to write the decrypted data to. + * + * @return true on success. + */ +bool tox_pass_decrypt(const uint8_t *ciphertext, size_t ciphertext_len, const uint8_t *passphrase, + size_t passphrase_len, uint8_t *plaintext, TOX_ERR_DECRYPTION *error); + + +/******************************************************************************* + * + * BEGIN PART 2 + * + * And now part 2, which does the actual encryption, and can be used to write + * less CPU intensive client code than part one. + * + ******************************************************************************/ + + + +/** + * This type represents a pass-key. + * + * A pass-key and a password are two different concepts: a password is given + * by the user in plain text. A pass-key is the generated symmetric key used + * for encryption and decryption. It is derived from a salt and the user- + * provided password. + * + * The Tox_Pass_Key structure is hidden in the implementation. It can be allocated + * using tox_pass_key_new and must be deallocated using tox_pass_key_free. + */ +#ifndef TOX_PASS_KEY_DEFINED +#define TOX_PASS_KEY_DEFINED +typedef struct Tox_Pass_Key Tox_Pass_Key; +#endif /* TOX_PASS_KEY_DEFINED */ + +/** + * Create a new Tox_Pass_Key. The initial value of it is indeterminate. To + * initialise it, use one of the derive_* functions below. + * + * In case of failure, this function returns NULL. The only failure mode at + * this time is memory allocation failure, so this function has no error code. + */ +struct Tox_Pass_Key *tox_pass_key_new(void); + +/** + * Deallocate a Tox_Pass_Key. This function behaves like free(), so NULL is an + * acceptable argument value. + */ +void tox_pass_key_free(struct Tox_Pass_Key *_key); + +/** + * Generates a secret symmetric key from the given passphrase. + * + * Be sure to not compromise the key! Only keep it in memory, do not write + * it to disk. + * + * Note that this function is not deterministic; to derive the same key from + * a password, you also must know the random salt that was used. A + * deterministic version of this function is tox_pass_key_derive_with_salt. + * + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * + * @return true on success. + */ +bool tox_pass_key_derive(struct Tox_Pass_Key *_key, const uint8_t *passphrase, size_t passphrase_len, + TOX_ERR_KEY_DERIVATION *error); + +/** + * Same as above, except use the given salt for deterministic key derivation. + * + * @param passphrase The user-provided password. Can be empty. + * @param passphrase_len The length of the password. + * @param salt An array of at least TOX_PASS_SALT_LENGTH bytes. + * + * @return true on success. + */ +bool tox_pass_key_derive_with_salt(struct Tox_Pass_Key *_key, const uint8_t *passphrase, size_t passphrase_len, + const uint8_t *salt, TOX_ERR_KEY_DERIVATION *error); + +/** + * Encrypt a plain text with a key produced by tox_pass_key_derive or tox_pass_key_derive_with_salt. + * + * The output array must be at least `plaintext_len + TOX_PASS_ENCRYPTION_EXTRA_LENGTH` + * bytes long. + * + * @param plaintext A byte array of length `plaintext_len`. + * @param plaintext_len The length of the plain text array. Bigger than 0. + * @param ciphertext The cipher text array to write the encrypted data to. + * + * @return true on success. + */ +bool tox_pass_key_encrypt(const struct Tox_Pass_Key *_key, const uint8_t *plaintext, size_t plaintext_len, + uint8_t *ciphertext, TOX_ERR_ENCRYPTION *error); + +/** + * This is the inverse of tox_pass_key_encrypt, also using only keys produced by + * tox_pass_key_derive or tox_pass_key_derive_with_salt. + * + * @param ciphertext A byte array of length `ciphertext_len`. + * @param ciphertext_len The length of the cipher text array. At least TOX_PASS_ENCRYPTION_EXTRA_LENGTH. + * @param plaintext The plain text array to write the decrypted data to. + * + * @return true on success. + */ +bool tox_pass_key_decrypt(const struct Tox_Pass_Key *_key, const uint8_t *ciphertext, size_t ciphertext_len, + uint8_t *plaintext, TOX_ERR_DECRYPTION *error); + +typedef enum TOX_ERR_GET_SALT { + + /** + * The function returned successfully. + */ + TOX_ERR_GET_SALT_OK, + + /** + * One of the arguments to the function was NULL when it was not expected. + */ + TOX_ERR_GET_SALT_NULL, + + /** + * The input data is missing the magic number (i.e. wasn't created by this + * module, or is corrupted). + */ + TOX_ERR_GET_SALT_BAD_FORMAT, + +} TOX_ERR_GET_SALT; + + +/** + * Retrieves the salt used to encrypt the given data. + * + * The retrieved salt can then be passed to tox_pass_key_derive_with_salt to + * produce the same key as was previously used. Any data encrypted with this + * module can be used as input. + * + * The cipher text must be at least TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes in length. + * The salt must be TOX_PASS_SALT_LENGTH bytes in length. + * If the passed byte arrays are smaller than required, the behaviour is + * undefined. + * + * If the cipher text pointer or the salt is NULL, this function returns false. + * + * Success does not say anything about the validity of the data, only that + * data of the appropriate size was copied. + * + * @return true on success. + */ +bool tox_get_salt(const uint8_t *ciphertext, uint8_t *salt, TOX_ERR_GET_SALT *error); + +/** + * Determines whether or not the given data is encrypted by this module. + * + * It does this check by verifying that the magic number is the one put in + * place by the encryption functions. + * + * The data must be at least TOX_PASS_ENCRYPTION_EXTRA_LENGTH bytes in length. + * If the passed byte array is smaller than required, the behaviour is + * undefined. + * + * If the data pointer is NULL, the behaviour is undefined + * + * @return true if the data is encrypted by this module. + */ +bool tox_is_data_encrypted(const uint8_t *data); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/pthreads/docs/ANNOUNCE b/libs/pthreads/docs/ANNOUNCE new file mode 100644 index 0000000000..950c86ff03 --- /dev/null +++ b/libs/pthreads/docs/ANNOUNCE @@ -0,0 +1,483 @@ +PTHREADS-WIN32 RELEASE 2.9.0 (2012-05-25) +----------------------------------------- +Web Site: http://sourceware.org/pthreads-win32/ +FTP Site: ftp://sourceware.org/pub/pthreads-win32 +Maintainer: Ross Johnson + + +We are pleased to announce the availability of a new release of +Pthreads-win32, an Open Source Software implementation of the +Threads component of the POSIX 1003.1 2001 Standard for Microsoft's +Win32 environment. Some functions from other sections of POSIX +1003.1 2001 are also supported including semaphores and scheduling +functions. + +Some common non-portable functions are also implemented for +additional compatibility, as are a few functions specific +to pthreads-win32 for easier integration with Win32 applications. + +Pthreads-win32 is free software, distributed under the GNU Lesser +General Public License (LGPL). + + +Acknowledgements +---------------- +This library is based originally on a Win32 pthreads +implementation contributed by John Bossom. + +The implementation of Condition Variables uses algorithms developed +by Alexander Terekhov and Louis Thomas. + +The implementation of POSIX mutexes has been improved by Thomas Pfaff +and later by Alexander Terekhov. + +The implementation of Spinlocks and Barriers was contributed +by Ross Johnson. + +The implementation of read/write locks was contributed by +Aurelio Medina and improved by Alexander Terekhov. + +Many others have contributed significant time and effort to solve crutial +problems in order to make the library workable, robust and reliable. + +Thanks to Xavier Leroy for granting permission to use and modify his +LinuxThreads manual pages. + +Thanks to The Open Group for making the Single Unix Specification +publicly available - many of the manual pages included in the package +were extracted from it. + +There is also a separate CONTRIBUTORS file. This file and others are +on the web site: + + http://sourceware.org/pthreads-win32 + +As much as possible, the ChangeLog file acknowledges contributions to the +code base in more detail. + + +Changes since the last release +------------------------------ +These are now documented in the NEWS file. +See the ChangeLog file also. + + +Known Bugs +---------- +These are now documented in the BUGS file. + + +Level of standards conformance +------------------------------ + +The following POSIX 1003.1 2001 options are defined and set to 200112L: + + _POSIX_THREADS + _POSIX_THREAD_SAFE_FUNCTIONS + _POSIX_THREAD_ATTR_STACKSIZE + _POSIX_THREAD_PRIORITY_SCHEDULING + _POSIX_SEMAPHORES + _POSIX_READER_WRITER_LOCKS + _POSIX_SPIN_LOCKS + _POSIX_BARRIERS + + +The following POSIX 1003.1 2001 options are defined and set to -1: + + _POSIX_THREAD_ATTR_STACKADDR + _POSIX_THREAD_PRIO_INHERIT + _POSIX_THREAD_PRIO_PROTECT + _POSIX_THREAD_PROCESS_SHARED + + +The following POSIX 1003.1 2001 limits are defined and set: + + _POSIX_THREAD_THREADS_MAX + _POSIX_SEM_VALUE_MAX + _POSIX_SEM_NSEMS_MAX + _POSIX_THREAD_KEYS_MAX + _POSIX_THREAD_DESTRUCTOR_ITERATIONS + PTHREAD_STACK_MIN + PTHREAD_THREADS_MAX + SEM_VALUE_MAX + SEM_NSEMS_MAX + PTHREAD_KEYS_MAX + PTHREAD_DESTRUCTOR_ITERATIONS + + +The following functions are implemented: + + --------------------------- + PThreads + --------------------------- + pthread_attr_init + pthread_attr_destroy + pthread_attr_getdetachstate + pthread_attr_getstackaddr + pthread_attr_getstacksize + pthread_attr_setdetachstate + pthread_attr_setstackaddr + pthread_attr_setstacksize + + pthread_create + pthread_detach + pthread_equal + pthread_exit + pthread_join + pthread_once + pthread_self + + pthread_cancel + pthread_cleanup_pop + pthread_cleanup_push + pthread_setcancelstate + pthread_setcanceltype + pthread_testcancel + + --------------------------- + Thread Specific Data + --------------------------- + pthread_key_create + pthread_key_delete + pthread_setspecific + pthread_getspecific + + --------------------------- + Mutexes + --------------------------- + pthread_mutexattr_init + pthread_mutexattr_destroy + pthread_mutexattr_getpshared + pthread_mutexattr_setpshared + pthread_mutexattr_gettype + pthread_mutexattr_settype (types: PTHREAD_MUTEX_DEFAULT + PTHREAD_MUTEX_NORMAL + PTHREAD_MUTEX_ERRORCHECK + PTHREAD_MUTEX_RECURSIVE ) + pthread_mutexattr_getrobust + pthread_mutexattr_setrobust (values: PTHREAD_MUTEX_STALLED + PTHREAD_MUTEX_ROBUST) + pthread_mutex_init + pthread_mutex_destroy + pthread_mutex_lock + pthread_mutex_trylock + pthread_mutex_timedlock + pthread_mutex_unlock + pthread_mutex_consistent + + --------------------------- + Condition Variables + --------------------------- + pthread_condattr_init + pthread_condattr_destroy + pthread_condattr_getpshared + pthread_condattr_setpshared + + pthread_cond_init + pthread_cond_destroy + pthread_cond_wait + pthread_cond_timedwait + pthread_cond_signal + pthread_cond_broadcast + + --------------------------- + Read/Write Locks + --------------------------- + pthread_rwlock_init + pthread_rwlock_destroy + pthread_rwlock_tryrdlock + pthread_rwlock_trywrlock + pthread_rwlock_rdlock + pthread_rwlock_timedrdlock + pthread_rwlock_rwlock + pthread_rwlock_timedwrlock + pthread_rwlock_unlock + pthread_rwlockattr_init + pthread_rwlockattr_destroy + pthread_rwlockattr_getpshared + pthread_rwlockattr_setpshared + + --------------------------- + Spin Locks + --------------------------- + pthread_spin_init + pthread_spin_destroy + pthread_spin_lock + pthread_spin_unlock + pthread_spin_trylock + + --------------------------- + Barriers + --------------------------- + pthread_barrier_init + pthread_barrier_destroy + pthread_barrier_wait + pthread_barrierattr_init + pthread_barrierattr_destroy + pthread_barrierattr_getpshared + pthread_barrierattr_setpshared + + --------------------------- + Semaphores + --------------------------- + sem_init + sem_destroy + sem_post + sem_wait + sem_trywait + sem_timedwait + sem_getvalue (# free if +ve, # of waiters if -ve) + sem_open (returns an error ENOSYS) + sem_close (returns an error ENOSYS) + sem_unlink (returns an error ENOSYS) + + --------------------------- + RealTime Scheduling + --------------------------- + pthread_attr_getschedparam + pthread_attr_setschedparam + pthread_attr_getinheritsched + pthread_attr_setinheritsched + pthread_attr_getschedpolicy (only supports SCHED_OTHER) + pthread_attr_setschedpolicy (only supports SCHED_OTHER) + pthread_getschedparam + pthread_setschedparam + pthread_getconcurrency + pthread_setconcurrency + pthread_attr_getscope + pthread_attr_setscope (only supports PTHREAD_SCOPE_SYSTEM) + sched_get_priority_max + sched_get_priority_min + sched_rr_get_interval (returns an error ENOTSUP) + sched_setscheduler (only supports SCHED_OTHER) + sched_getscheduler (only supports SCHED_OTHER) + sched_yield + + --------------------------- + Signals + --------------------------- + pthread_sigmask + pthread_kill (only supports zero sig value, + for thread validity checking) + + --------------------------- + Non-portable routines (see the README.NONPORTABLE file for usage) + --------------------------- + pthread_getw32threadhandle_np + pthread_timechange_handler_np + pthread_delay_np + pthread_getunique_np + pthread_mutexattr_getkind_np + pthread_mutexattr_setkind_np (types: PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ADAPTIVE_NP, + PTHREAD_MUTEX_TIMED_NP) + pthread_num_processors_np + (The following four routines may be required when linking statically. + The process_* routines should not be needed for MSVC or GCC.) + pthread_win32_process_attach_np + pthread_win32_process_detach_np + (The following routines should only be needed to manage implicit + POSIX handles i.e. when Win native threads call POSIX thread routines + (other than pthread_create)) + pthread_win32_thread_attach_np + pthread_win32_thread_detach_np + + --------------------------- + Static Initializers + --------------------------- + PTHREAD_ONCE_INIT + PTHREAD_MUTEX_INITIALIZER + PTHREAD_RECURSIVE_MUTEX_INITIALIZER + PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP + PTHREAD_COND_INITIALIZER + PTHREAD_RWLOCK_INITIALIZER + PTHREAD_SPINLOCK_INITIALIZER + + +The library includes two non-API functions for creating cancellation +points in applications and libraries: + + pthreadCancelableWait + pthreadCancelableTimedWait + + +The following functions are not implemented: + + --------------------------- + RealTime Scheduling + --------------------------- + pthread_mutex_getprioceiling + pthread_mutex_setprioceiling + pthread_mutex_attr_getprioceiling + pthread_mutex_attr_getprotocol + pthread_mutex_attr_setprioceiling + pthread_mutex_attr_setprotocol + + --------------------------- + Fork Handlers + --------------------------- + pthread_atfork + + --------------------------- + Stdio + --------------------------- + flockfile + ftrylockfile + funlockfile + getc_unlocked + getchar_unlocked + putc_unlocked + putchar_unlocked + + --------------------------- + Thread-Safe C Runtime Library + --------------------------- + readdir_r + getgrgid_r + getgrnam_r + getpwuid_r + getpwnam_r + + --------------------------- + Signals + --------------------------- + sigtimedwait + sigwait + sigwaitinfo + + --------------------------- + General + --------------------------- + sysconf + + --------------------------- + Thread-Safe C Runtime Library (macros) + --------------------------- + strtok_r + asctime_r + ctime_r + gmtime_r + localtime_r + rand_r + + +Availability +------------ + +The prebuilt DLL, export libs (for both MSVC and Mingw32), and the header +files (pthread.h, semaphore.h, sched.h) are available along with the +complete source code. + +The source code can be found at: + + ftp://sources.redhat.com/pub/pthreads-win32 + +and as individual source code files at + + ftp://sources.redhat.com/pub/pthreads-win32/source + +The pre-built DLL, export libraries and include files can be found at: + + ftp://sources.redhat.com/pub/pthreads-win32/dll-latest + + + +Mailing List +------------ + +There is a mailing list for discussing pthreads on Win32. To join, +send email to: + + pthreads-win32-subscribe@sourceware.cygnus.com + + +Application Development Environments +------------------------------------ + +See the README file for more information. + +MSVC: +MSVC using SEH works. Distribute pthreadVSE.dll with your application. +MSVC using C++ EH works. Distribute pthreadVCE.dll with your application. +MSVC using C setjmp/longjmp works. Distribute pthreadVC.dll with your application. + + +Mingw32: +See the FAQ, Questions 6 and 10. + +Mingw using C++ EH works. Distribute pthreadGCE.dll with your application. +Mingw using C setjmp/longjmp works. Distribute pthreadGC.dll with your application. + + +Cygwin: (http://sourceware.cygnus.com/cygwin/) +Developers using Cygwin do not need pthreads-win32 since it has POSIX threads +support. Refer to its documentation for details and extent. + + +UWIN: +UWIN is a complete Unix-like environment for Windows from AT&T. Pthreads-win32 +doesn't currently support UWIN (and vice versa), but that may change in the +future. + +Generally: +For convenience, the following pre-built files are available on the FTP site +(see Availability above): + + pthread.h - for POSIX threads + semaphore.h - for POSIX semaphores + sched.h - for POSIX scheduling + pthreadVCE.dll - built with MSVC++ compiler using C++ EH + pthreadVCE.lib + pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp + pthreadVC.lib + pthreadVSE.dll - built with MSVC compiler using SEH + pthreadVSE.lib + pthreadGCE.dll - built with Mingw32 G++ 2.95.2-1 + pthreadGC.dll - built with Mingw32 GCC 2.95.2-1 using setjmp/longjmp + libpthreadGCE.a - derived from pthreadGCE.dll + libpthreadGC.a - derived from pthreadGC.dll + gcc.dll - needed if distributing applications that use + pthreadGCE.dll (but see the FAQ Q 10 for the latest + related information) + +These are the only files you need in order to build POSIX threads +applications for Win32 using either MSVC or Mingw32. + +See the FAQ file in the source tree for additional information. + + +Documentation +------------- + +For the authoritative reference, see the online POSIX +standard reference at: + + http://www.OpenGroup.org + +For POSIX Thread API programming, several reference books are +available: + + Programming with POSIX Threads + David R. Butenhof + Addison-Wesley (pub) + + Pthreads Programming + By Bradford Nichols, Dick Buttlar & Jacqueline Proulx Farrell + O'Reilly (pub) + +On the web: see the links at the bottom of the pthreads-win32 site: + + http://sources.redhat.com/pthreads-win32/ + + Currently, there is no documentation included in the package apart + from the copious comments in the source code. + + + +Enjoy! + +Ross Johnson diff --git a/libs/pthreads/docs/BUGS b/libs/pthreads/docs/BUGS new file mode 100644 index 0000000000..285ba4eb98 --- /dev/null +++ b/libs/pthreads/docs/BUGS @@ -0,0 +1,141 @@ +---------- +Known bugs +---------- + +1. Not strictly a bug, more of a gotcha. + + Under MS VC++ (only tested with version 6.0), a term_func + set via the standard C++ set_terminate() function causes the + application to abort. + + Notes from the MSVC++ manual: + 1) A term_func() should call exit(), otherwise + abort() will be called on return to the caller. + A call to abort() raises SIGABRT and the default signal handler + for all signals terminates the calling program with + exit code 3. + 2) A term_func() must not throw an exception. Therefore + term_func() should not call pthread_exit(), which + works by throwing an exception (pthreadVCE or pthreadVSE) + or by calling longjmp (pthreadVC). + + Workaround: avoid using pthread_exit() in C++ applications. Exit + threads by dropping through the end of the thread routine. + +2. Cancellation problems in C++ builds + - Milan Gardian + + [Note: It's not clear if this problem isn't simply due to the context + switch in pthread_cancel() which occurs unless the QueueUserAPCEx + library and driver are installed and used. Just like setjmp/longjmp, + this is probably not going to work well in C++. In any case, unless for + some very unusual reason you really must use the C++ build then please + use the C build pthreadVC2.dll or pthreadGC2.dll, i.e. for C++ + applications.] + + This is suspected to be a compiler bug in VC6.0, and also seen in + VC7.0 and VS .NET 2003. The GNU C++ compiler does not have a problem + with this, and it has been reported that the Intel C++ 8.1 compiler + and Visual C++ 2005 Express Edition Beta2 pass tests\semaphore4.c + (which exposes the bug). + + Workaround [rpj - 2 Feb 2002] + ----------------------------- + [Please note: this workaround did not solve a similar problem in + snapshot-2004-11-03 or later, even though similar symptoms were seen. + tests\semaphore4.c fails in that snapshot for the VCE version of the + DLL.] + + The problem disappears when /Ob0 is used, i.e. /O2 /Ob0 works OK, + but if you want to use inlining optimisation you can be much more + specific about where it's switched off and on by using a pragma. + + So the inlining optimisation is interfering with the way that cleanup + handlers are run. It appears to relate to auto-inlining of class methods + since this is the only auto inlining that is performed at /O1 optimisation + (functions with the "inline" qualifier are also inlined, but the problem + doesn't appear to involve any such functions in the library or testsuite). + + In order to confirm the inlining culprit, the following use of pragmas + eliminate the problem but I don't know how to make it transparent, putting + it in, say, pthread.h where pthread_cleanup_push defined as a macro. + + #pragma inline_depth(0) + pthread_cleanup_push(handlerFunc, (void *) &arg); + + /* ... */ + + pthread_cleanup_pop(0); + #pragma inline_depth() + + Note the empty () pragma value after the pop macro. This resets depth to the + default. Or you can specify a non-zero depth here. + + The pragma is also needed (and now used) within the library itself wherever + cleanup handlers are used (condvar.c and rwlock.c). + + Use of these pragmas allows compiler optimisations /O1 and /O2 to be + used for either or both the library and applications. + + Experimenting further, I found that wrapping the actual cleanup handler + function with #pragma auto_inline(off|on) does NOT work. + + MSVC6.0 doesn't appear to support the C99 standard's _Pragma directive, + however, later versions may. This form is embeddable inside #define + macros, which would be ideal because it would mean that it could be added + to the push/pop macro definitions in pthread.h and hidden from the + application programmer. + + [/rpj] + + Original problem description + ---------------------------- + + The cancellation (actually, cleanup-after-cancel) tests fail when using VC + (professional) optimisation switches (/O1 or /O2) in pthreads library. I + have not investigated which concrete optimisation technique causes this + problem (/Og, /Oi, /Ot, /Oy, /Ob1, /Gs, /Gf, /Gy, etc.), but here is a + summary of builds and corresponding failures: + + * pthreads VSE (optimised tests): OK + * pthreads VCE (optimised tests): Failed "cleanup1" test (runtime) + + * pthreads VSE (DLL in CRT, optimised tests): OK + * pthreads VCE (DLL in CRT, optimised tests): Failed "cleanup1" test + (runtime) + + Please note that while in VSE version of the pthreads library the + optimisation does not really have any impact on the tests (they pass OK), in + VCE version addition of optimisation (/O2 in this case) causes the tests to + fail uniformly - either in "cleanup0" or "cleanup1" test cases. + + Please note that all the tests above use default pthreads DLL (no + optimisations, linked with either static or DLL CRT, based on test type). + Therefore the problem lies not within the pthreads DLL but within the + compiled client code (the application using pthreads -> involvement of + "pthread.h"). + + I think the message of this section is that usage of VCE version of pthreads + in applications relying on cancellation/cleanup AND using optimisations for + creation of production code is highly unreliable for the current version of + the pthreads library. + +3. The Borland Builder 5.5 version of the library produces memory read exceptions +in some tests. + +4. pthread_barrier_wait() can deadlock if the number of potential calling +threads for a particular barrier is greater than the barrier count parameter +given to pthread_barrier_init() for that barrier. + +This is due to the very lightweight implementation of pthread-win32 barriers. +To cope with more than "count" possible waiters, barriers must effectively +implement all the same safeguards as condition variables, making them much +"heavier" than at present. + +The workaround is to ensure that no more than "count" threads attempt to wait +at the barrier. + +5. Canceling a thread blocked on pthread_once appears not to work in the MSVC++ +version of the library "pthreadVCE.dll". The test case "once3.c" hangs. I have no +clues on this at present. All other versions pass this test ok - pthreadsVC.dll, +pthreadsVSE.dll, pthreadsGC.dll and pthreadsGCE.dll. diff --git a/libs/pthreads/docs/Bmakefile b/libs/pthreads/docs/Bmakefile new file mode 100644 index 0000000000..ea25dec4fd --- /dev/null +++ b/libs/pthreads/docs/Bmakefile @@ -0,0 +1,268 @@ +# This makefile is compatible with BCB make. Use "make -fBMakefile" to compile. +# +# The variables $DLLDEST and $LIBDEST hold the destination directories for the +# dll and the lib, respectively. Probably all that needs to change is $DEVROOT. +# +# Currently only the recommended pthreadBC.dll is built by this makefile. +# + + +DLL_VER = 2 + +DEVROOT = . + +DLLDEST = $(DEVROOT)\DLL +LIBDEST = $(DEVROOT)\DLL + +DLLS = pthreadBC$(DLL_VER).dll + +OPTIM = /O2 + +RC = brcc32 +RCFLAGS = -i. + +CFLAGS = /q /I. /D_WIN32_WINNT=0x400 /DHAVE_PTW32_CONFIG_H=1 /4 /tWD /tWM \ + /w-aus /w-asc /w-par + +#C cleanup code +BCFLAGS = $(PTW32_FLAGS) $(CFLAGS) + +# Agregate modules for inlinability +DLL_OBJS = \ + attr.obj \ + barrier.obj \ + cancel.obj \ + cleanup.obj \ + condvar.obj \ + create.obj \ + dll.obj \ + errno.obj \ + exit.obj \ + fork.obj \ + global.obj \ + misc.obj \ + mutex.obj \ + nonportable.obj \ + private.obj \ + rwlock.obj \ + sched.obj \ + semaphore.obj \ + signal.obj \ + spin.obj \ + sync.obj \ + tsd.obj + +INCL = config.h implement.h semaphore.h pthread.h need_errno.h + +ATTR_SRCS = \ + pthread_attr_init.c \ + pthread_attr_destroy.c \ + pthread_attr_getdetachstate.c \ + pthread_attr_setdetachstate.c \ + pthread_attr_getstackaddr.c \ + pthread_attr_setstackaddr.c \ + pthread_attr_getstacksize.c \ + pthread_attr_setstacksize.c \ + pthread_attr_getscope.c \ + pthread_attr_setscope.c + +BARRIER_SRCS = \ + pthread_barrier_init.c \ + pthread_barrier_destroy.c \ + pthread_barrier_wait.c \ + pthread_barrierattr_init.c \ + pthread_barrierattr_destroy.c \ + pthread_barrierattr_setpshared.c \ + pthread_barrierattr_getpshared.c + +CANCEL_SRCS = \ + pthread_setcancelstate.c \ + pthread_setcanceltype.c \ + pthread_testcancel.c \ + pthread_cancel.c + +CONDVAR_SRCS = \ + ptw32_cond_check_need_init.c \ + pthread_condattr_destroy.c \ + pthread_condattr_getpshared.c \ + pthread_condattr_init.c \ + pthread_condattr_setpshared.c \ + pthread_cond_destroy.c \ + pthread_cond_init.c \ + pthread_cond_signal.c \ + pthread_cond_wait.c + +EXIT_SRCS = \ + pthread_exit.c + +MISC_SRCS = \ + pthread_equal.c \ + pthread_getconcurrency.c \ + pthread_once.c \ + pthread_self.c \ + pthread_setconcurrency.c \ + ptw32_calloc.c \ + ptw32_MCS_lock.c \ + ptw32_new.c \ + w32_CancelableWait.c + +MUTEX_SRCS = \ + ptw32_mutex_check_need_init.c \ + pthread_mutex_init.c \ + pthread_mutex_destroy.c \ + pthread_mutexattr_init.c \ + pthread_mutexattr_destroy.c \ + pthread_mutexattr_getpshared.c \ + pthread_mutexattr_setpshared.c \ + pthread_mutexattr_settype.c \ + pthread_mutexattr_gettype.c \ + pthread_mutexattr_setrobust.c \ + pthread_mutexattr_getrobust.c \ + pthread_mutex_lock.c \ + pthread_mutex_timedlock.c \ + pthread_mutex_unlock.c \ + pthread_mutex_trylock.c \ + pthread_mutex_consistent.c + +NONPORTABLE_SRCS = \ + pthread_mutexattr_setkind_np.c \ + pthread_mutexattr_getkind_np.c \ + pthread_getw32threadhandle_np.c \ + pthread_delay_np.c \ + pthread_num_processors_np.c \ + pthread_win32_attach_detach_np.c \ + pthread_timechange_handler_np.c + +PRIVATE_SRCS = \ + ptw32_is_attr.c \ + ptw32_processInitialize.c \ + ptw32_processTerminate.c \ + ptw32_threadStart.c \ + ptw32_threadDestroy.c \ + ptw32_tkAssocCreate.c \ + ptw32_tkAssocDestroy.c \ + ptw32_callUserDestroyRoutines.c \ + ptw32_timespec.c \ + ptw32_relmillisecs.c \ + ptw32_throw.c \ + ptw32_getprocessors.c + +RWLOCK_SRCS = \ + ptw32_rwlock_check_need_init.c \ + ptw32_rwlock_cancelwrwait.c \ + pthread_rwlock_init.c \ + pthread_rwlock_destroy.c \ + pthread_rwlockattr_init.c \ + pthread_rwlockattr_destroy.c \ + pthread_rwlockattr_getpshared.c \ + pthread_rwlockattr_setpshared.c \ + pthread_rwlock_rdlock.c \ + pthread_rwlock_timedrdlock.c \ + pthread_rwlock_wrlock.c \ + pthread_rwlock_timedwrlock.c \ + pthread_rwlock_unlock.c \ + pthread_rwlock_tryrdlock.c \ + pthread_rwlock_trywrlock.c + +SCHED_SRCS = \ + pthread_attr_setschedpolicy.c \ + pthread_attr_getschedpolicy.c \ + pthread_attr_setschedparam.c \ + pthread_attr_getschedparam.c \ + pthread_attr_setinheritsched.c \ + pthread_attr_getinheritsched.c \ + pthread_setschedparam.c \ + pthread_getschedparam.c \ + sched_get_priority_max.c \ + sched_get_priority_min.c \ + sched_setscheduler.c \ + sched_getscheduler.c \ + sched_yield.c + +SEMAPHORE_SRCS = \ + sem_init.c \ + sem_destroy.c \ + sem_trywait.c \ + sem_timedwait.c \ + sem_wait.c \ + sem_post.c \ + sem_post_multiple.c \ + sem_getvalue.c \ + sem_open.c \ + sem_close.c \ + sem_unlink.c + +SPIN_SRCS = \ + ptw32_spinlock_check_need_init.c \ + pthread_spin_init.c \ + pthread_spin_destroy.c \ + pthread_spin_lock.c \ + pthread_spin_unlock.c \ + pthread_spin_trylock.c + +SYNC_SRCS = \ + pthread_detach.c \ + pthread_join.c + +TSD_SRCS = \ + pthread_key_create.c \ + pthread_key_delete.c \ + pthread_setspecific.c \ + pthread_getspecific.c + + +all: clean $(DLLS) + +realclean: clean + if exist pthread*.dll del pthread*.dll + if exist pthread*.lib del pthread*.lib + if exist *.stamp del *.stamp + +clean: + if exist *.obj del *.obj + if exist *.ilk del *.ilk + if exist *.ilc del *.ilc + if exist *.ild del *.ild + if exist *.ilf del *.ilf + if exist *.ils del *.ils + if exist *.tds del *.tds + if exist *.pdb del *.pdb + if exist *.exp del *.exp + if exist *.map del *.map + if exist *.o del *.o + if exist *.i del *.i + if exist *.res del *.res + + +install: $(DLLS) + copy pthread*.dll $(DLLDEST) + copy pthread*.lib $(LIBDEST) + +$(DLLS): $(DLL_OBJS) version.res + ilink32 /Tpd /Gi c0d32x.obj $(DLL_OBJS), \ + $@, ,\ + cw32mti.lib import32.lib, ,\ + version.res + +.c.obj: + $(CC) $(OPTIM) $(BCFLAGS) -c $< + +.rc.res: + $(RC) $(RCFLAGS) $< + +attr.obj: attr.c $(ATTR_SRCS) $(INCL) +barrier.obj: barrier.c $(BARRIER_SRCS) $(INCL) +cancel.obj: cancel.c $(CANCEL_SRCS) $(INCL) +condvar.obj: condvar.c $(CONDVAR_SRCS) $(INCL) +exit.obj: exit.c $(EXIT_SRCS) $(INCL) +misc.obj: misc.c $(MISC_SRCS) $(INCL) +mutex.obj: mutex.c $(MUTEX_SRCS) $(INCL) +nonportable.obj: nonportable.c $(NONPORTABLE_SRCS) $(INCL) +private.obj: private.c $(PRIVATE_SRCS) $(INCL) +rwlock.obj: rwlock.c $(RWLOCK_SRCS) $(INCL) +sched.obj: sched.c $(SCHED_SRCS) $(INCL) +semaphore.obj: semaphore.c $(SEMAPHORE_SRCS) $(INCL) +spin.obj: spin.c $(SPIN_SRCS) $(INCL) +sync.obj: sync.c $(SYNC_SRCS) $(INCL) +tsd.obj: tsd.c $(TSD_SRCS) $(INCL) +version.res: version.rc $(INCL) diff --git a/libs/pthreads/docs/CONTRIBUTORS b/libs/pthreads/docs/CONTRIBUTORS new file mode 100644 index 0000000000..da31ff266c --- /dev/null +++ b/libs/pthreads/docs/CONTRIBUTORS @@ -0,0 +1,140 @@ +Contributors (in approximate order of appearance) + +[See also the ChangeLog file where individuals are +attributed in log entries. Likewise in the FAQ file.] + +Ben Elliston bje at cygnus dot com + Initiated the project; + setup the project infrastructure (CVS, web page, etc.); + early prototype routines. +Ross Johnson Ross dot Johnson at dot homemail dot com dot au + early prototype routines; + ongoing project coordination/maintenance; + implementation of spin locks and barriers; + various enhancements; + bug fixes; + documentation; + testsuite. +Robert Colquhoun rjc at trump dot net dot au + Early bug fixes. +John E. Bossom John dot Bossom at cognos dot com + Contributed substantial original working implementation; + bug fixes; + ongoing guidance and standards interpretation. +Anders Norlander anorland at hem2 dot passagen dot se + Early enhancements and runtime checking for supported + Win32 routines. +Tor Lillqvist tml at iki dot fi + General enhancements; + early bug fixes to condition variables. +Scott Lightner scott at curriculum dot com + Bug fix. +Kevin Ruland Kevin dot Ruland at anheuser-busch dot com + Various bug fixes. +Mike Russo miker at eai dot com + Bug fix. +Mark E. Armstrong avail at pacbell dot net + Bug fixes. +Lorin Hochstein lmh at xiphos dot ca + general bug fixes; bug fixes to condition variables. +Peter Slacik Peter dot Slacik at tatramed dot sk + Bug fixes. +Mumit Khan khan at xraylith dot wisc dot edu + Fixes to work with Mingw32. +Milan Gardian mg at tatramed dot sk + Bug fixes and reports/analyses of obscure problems. +Aurelio Medina aureliom at crt dot com + First implementation of read-write locks. +Graham Dumpleton Graham dot Dumpleton at ra dot pad dot otc dot telstra dot com dot au + Bug fix in condition variables. +Tristan Savatier tristan at mpegtv dot com + WinCE port. +Erik Hensema erik at hensema dot xs4all dot nl + Bug fixes. +Rich Peters rpeters at micro-magic dot com +Todd Owen towen at lucidcalm dot dropbear dot id dot au + Bug fixes to dll loading. +Jason Nye jnye at nbnet dot nb dot ca + Implementation of async cancelation. +Fred Forester fforest at eticomm dot net +Kevin D. Clark kclark at cabletron dot com +David Baggett dmb at itasoftware dot com + Bug fixes. +Paul Redondo paul at matchvision dot com +Scott McCaskill scott at 3dfx dot com + Bug fixes. +Jef Gearhart jgearhart at tpssys dot com + Bug fix. +Arthur Kantor akantor at bexusa dot com + Mutex enhancements. +Steven Reddie smr at essemer dot com dot au + Bug fix. +Alexander Terekhov TEREKHOV at de dot ibm dot com + Re-implemented and improved read-write locks; + (with Louis Thomas) re-implemented and improved + condition variables; + enhancements to semaphores; + enhancements to mutexes; + new mutex implementation in 'futex' style; + suggested a robust implementation of pthread_once + similar to that implemented by V.Kliathcko; + system clock change handling re CV timeouts; + bug fixes. +Thomas Pfaff tpfaff at gmx dot net + Changes to make C version usable with C++ applications; + re-implemented mutex routines to avoid Win32 mutexes + and TryEnterCriticalSection; + procedure to fix Mingw32 thread-safety issues. +Franco Bez franco dot bez at gmx dot de + procedure to fix Mingw32 thread-safety issues. +Louis Thomas lthomas at arbitrade dot com + (with Alexander Terekhov) re-implemented and improved + condition variables. +David Korn dgk at research dot att dot com + Ported to UWIN. +Phil Frisbie, Jr. phil at hawksoft dot com + Bug fix. +Ralf Brese Ralf dot Brese at pdb4 dot siemens dot de + Bug fix. +prionx at juno dot com prionx at juno dot com + Bug fixes. +Max Woodbury mtew at cds dot duke dot edu + POSIX versioning conditionals; + reduced namespace pollution; + idea to separate routines to reduce statically + linked image sizes. +Rob Fanner rfanner at stonethree dot com + Bug fix. +Michael Johnson michaelj at maine dot rr dot com + Bug fix. +Nicolas Barry boozai at yahoo dot com + Bug fixes. +Piet van Bruggen pietvb at newbridges dot nl + Bug fix. +Makoto Kato raven at oldskool dot jp + AMD64 port. +Panagiotis E. Hadjidoukas peh at hpclab dot ceid dot upatras dot gr + phadjido at cs dot uoi dot gr + Contributed the QueueUserAPCEx package which + makes preemptive async cancelation possible. +Will Bryant will dot bryant at ecosm dot com + Borland compiler patch and makefile. +Anuj Goyal anuj dot goyal at gmail dot com + Port to Digital Mars compiler. +Gottlob Frege gottlobfrege at gmail dot com + re-implemented pthread_once (version 2) + (pthread_once cancellation added by rpj). +Vladimir Kliatchko vladimir at kliatchko dot com + reimplemented pthread_once with the same form + as described by A.Terekhov (later version 2); + implementation of MCS (Mellor-Crummey/Scott) locks. +Ramiro Polla ramiro.polla at gmail dot com + static library auto init/cleanup on application + start/exit via RT hooks (MSC and GCC compilers only). +Daniel Richard G. skunk at iSKUNK dot org + Patches and cleanups for x86 and x64, particularly + across a range of MS build environments. +John Kamp john dot kamp at globalgraphics dot com + Patches to fix various problems on x64; brutal testing + particularly using high memory run environments. + diff --git a/libs/pthreads/docs/COPYING b/libs/pthreads/docs/COPYING new file mode 100644 index 0000000000..5cfea0d0ed --- /dev/null +++ b/libs/pthreads/docs/COPYING @@ -0,0 +1,150 @@ + pthreads-win32 - a POSIX threads library for Microsoft Windows + + +This file is Copyrighted +------------------------ + + This file is covered under the following Copyright: + + Copyright (C) 2001,2006 Ross P. Johnson + All rights reserved. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Pthreads-win32 is covered by the GNU Lesser General Public License +------------------------------------------------------------------ + + Pthreads-win32 is open software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation version 2.1 of the + License. + + Pthreads-win32 is several binary link libraries, several modules, + associated interface definition files and scripts used to control + its compilation and installation. + + Pthreads-win32 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + A copy of the GNU Lesser General Public License is distributed with + pthreads-win32 under the filename: + + COPYING.LIB + + You should have received a copy of the version 2.1 GNU Lesser General + Public License with pthreads-win32; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place + Suite 330 + Boston, MA 02111-1307 + USA + + The contact addresses for pthreads-win32 is as follows: + + Web: http://sources.redhat.com/pthreads-win32 + Email: Ross Johnson + Please use: Firstname.Lastname@homemail.com.au + + + +Pthreads-win32 copyrights and exception files +--------------------------------------------- + + With the exception of the files listed below, Pthreads-win32 + is covered under the following GNU Lesser General Public License + Copyrights: + + Pthreads-win32 - POSIX Threads Library for Win32 + Copyright(C) 1998 John E. Bossom + Copyright(C) 1999,2006 Pthreads-win32 contributors + + The current list of contributors is contained + in the file CONTRIBUTORS included with the source + code distribution. The current list of CONTRIBUTORS + can also be seen at the following WWW location: + http://sources.redhat.com/pthreads-win32/contributors.html + + Contact Email: Ross Johnson + Please use: Firstname.Lastname@homemail.com.au + + These files are not covered under one of the Copyrights listed above: + + COPYING + COPYING.LIB + tests/rwlock7.c + + This file, COPYING, is distributed under the Copyright found at the + top of this file. It is important to note that you may distribute + verbatim copies of this file but you may not modify this file. + + The file COPYING.LIB, which contains a copy of the version 2.1 + GNU Lesser General Public License, is itself copyrighted by the + Free Software Foundation, Inc. Please note that the Free Software + Foundation, Inc. does NOT have a copyright over Pthreads-win32, + only the COPYING.LIB that is supplied with pthreads-win32. + + The file tests/rwlock7.c is derived from code written by + Dave Butenhof for his book 'Programming With POSIX(R) Threads'. + The original code was obtained by free download from his website + http://home.earthlink.net/~anneart/family/Threads/source.html + and did not contain a copyright or author notice. It is assumed to + be freely distributable. + + In all cases one may use and distribute these exception files freely. + And because one may freely distribute the LGPL covered files, the + entire pthreads-win32 source may be freely used and distributed. + + + +General Copyleft and License info +--------------------------------- + + For general information on Copylefts, see: + + http://www.gnu.org/copyleft/ + + For information on GNU Lesser General Public Licenses, see: + + http://www.gnu.org/copyleft/lesser.html + http://www.gnu.org/copyleft/lesser.txt + + +Why pthreads-win32 did not use the GNU General Public License +------------------------------------------------------------- + + The goal of the pthreads-win32 project has been to + provide a quality and complete implementation of the POSIX + threads API for Microsoft Windows within the limits imposed + by virtue of it being a stand-alone library and not + linked directly to other POSIX compliant libraries. For + example, some functions and features, such as those based + on POSIX signals, are missing. + + Pthreads-win32 is a library, available in several different + versions depending on supported compilers, and may be used + as a dynamically linked module or a statically linked set of + binary modules. It is not an application on it's own. + + It was fully intended that pthreads-win32 be usable with + commercial software not covered by either the GPL or the LGPL + licenses. Pthreads-win32 has many contributors to it's + code base, many of whom have done so because they have + used the library in commercial or proprietry software + projects. + + Releasing pthreads-win32 under the LGPL ensures that the + library can be used widely, while at the same time ensures + that bug fixes and improvements to the pthreads-win32 code + itself is returned to benefit all current and future users + of the library. + + Although pthreads-win32 makes it possible for applications + that use POSIX threads to be ported to Win32 platforms, the + broader goal of the project is to encourage the use of open + standards, and in particular, to make it just a little easier + for developers writing Win32 applications to consider + widening the potential market for their products. diff --git a/libs/pthreads/docs/ChangeLog b/libs/pthreads/docs/ChangeLog new file mode 100644 index 0000000000..42abcc457a --- /dev/null +++ b/libs/pthreads/docs/ChangeLog @@ -0,0 +1,5211 @@ +2012-03-18 Ross Johnson + + * create.c (pthread_create): add __cdecl attribute to thread routine + arg + * implement.h (pthread_key_t): add __cdecl attribute to destructor + element + (ThreadParms): likewise for start element + * pthread.h (pthread_create): add __cdecl to prototype start arg + (pthread_once): likewise for init_routine arg + (pthread_key_create): likewise for destructor arg + (ptw32_cleanup_push): replace type of routine arg with previously + defined ptw32_cleanup_callback_t + * pthread_key_create.c: add __cdecl attribute to destructor arg + * pthread_once.c: add __cdecl attribute to init_routine arg + * ptw32_threadStart.c (start): add __cdecl to start variable type + + +2011-07-06 Ross Johnson + + * pthread_cond_wait.c (pragma inline_depth): this is almost redundant + now nevertheless fixed thei controlling MSC_VER from "< 800" to + "< 1400" (i.e. any prior to VC++ 8.0). + * pthread_once.ci (pragma inline_depth): Likewise. + * pthread_rwlock_timedwrlock.ci (pragma inline_depth): Likewise. + * pthread_rwlock_wrlock.ci (pragma inline_depth): Likewise. + * sem_timedwait.ci (pragma inline_depth): Likewise. + * sem_wait.ci (pragma inline_depth): Likewise. + +2011-07-05 Ross Johnson + + * pthread_win32_attach_detach_np.c: Use strncat_s if available + to removei a compile warning; MingW supports this routine but we + continue to use strncat anyway there because it is secure if + given the correct parameters; fix strncat param 3 to avoid + buffer overrun exploitation potential. + +2011-07-03 Ross Johnson + + * pthread_spin_unlock.c (EPERM): Return success if unlocking a lock + that is not locked, because single CPU machines wrap a + PTHREAD_MUTEX_NORMAL mutex, which returns success in this case. + * pthread_win32_attach_detach_np.c (QUSEREX.DLL): Load from an + absolute path only which must be the Windows System folder. + +2011-07-03 Daniel Richard G. + + * Makefile (_WIN32_WINNT): Removed; duplicate definition in + implement.h; more cleanup and enhancements. + +2011-07-02 Daniel Richard G. + + * Makefile: Cleanups and implovements. + * ptw32_MCS_locks.c: Casting fixes. + * implement.h: Interlocked call and argument casting macro fixes + to support older and newer build environments. + +2011-07-01 Ross Johnson + + * *.[ch] (PTW32_INTERLOCKED_*): Redo 23 and 64 bit versions of these + macros and re-apply in code to undo the incorrect changes from + 2011-06-29; remove some size_t casts which should not be required + and may be problematic.a + There are now two sets of macros: + PTW32_INTERLOCKED_*_LONG which work only on 32 bit integer variables; + PTW32_INTERLOCKED_*_SIZE which work on size_t integer variables, i.e. + LONG for 32 bit systems and LONGLONG for 64 bit systems. + * implement.h (MCS locks): nextFlag and waitFlag are now HANDLE type. + * ptw32_MCS_locks.c: Likewise. + * pthread.h (#include ): Removed. + * ptw32_throw.c (#include ): Added. + * ptw32_threadStart.c (#include ): Added. + * implement.h (#include ): Added. + +2011-06-30 Ross Johnson + + * pthread_once.c: Tighten 'if' statement casting; fix interlocked + pointer cast for 64 bit compatibility (missed yesterday); remove + the superfluous static cleanup routine and call the release routine + directly if popped. + * create.c (stackSize): Now type size_t. + * pthread.h (struct ptw32_thread_t_): Rearrange to fix element alignments. + +2011-06-29 Daniel Richard G. + + * ptw32_relmillisecs.c (ftime): + _ftime64_s() is only available in MSVC 2005 or later; + _ftime64() is available in MinGW or MSVC 2002 or later; + _ftime() is always available. + * pthread.h (long long): Not defined in older MSVC 6. + * implement.h (long long): Likewise. + * pthread_getunique_np.c (long long): Likewise. + +2011-06-29 Ross Johnson + + * *.[ch] (PTW32_INTERLOCKED_*): These macros should now work for + both 32 and 64 bit builds. The MingW versions are all inlined asm + while the MSVC versions expand to their Interlocked* or Interlocked*64 + counterparts appropriately. The argument type have also been changed + to cast to the appropriate value or pointer size for the architecture. + +2011-05-29 Ross Johnson + + * *.[ch] (#ifdef): Extended cleanup to whole project. + +2011-05-29 Daniel Richard G. + + * Makefile (CC): Define CC to allow use of other compatible + compilers such as the Intel compilter icl. + * implement.h (#if): Fix forms like #if HAVE_SOMETHING. + * pthread.h: Likewise. + * sched.h: Likewise; PTW32_LEVEL_* becomes PTW32_SCHED_LEVEL_*. + * semaphore.h: Likewise. + +2011-05-11 Ross Johnson + + * ptw32_callUserDestroyRoutines.c (terminate): Altered includes + to match ptw32_threadStart.c. + * GNUmakefile (GCE-inlined-debug, DOPT): Fixed. + +2011-04-31 Ross Johnson + + * (robust mutexes): Added this API. The API is not + mandatory for implementations that don't support PROCESS_SHARED + mutexes, nevertheless it was considered useful both functionally + and for source-level compatibility. + +2011-03-26 Ross Johnson + + * pthread_getunique_np.c: New non-POSIX interface for compatibility + with some other implementations; returns a 64 bit sequence number + that is unique to each thread in the process. + * pthread.h (pthread_getunique_np): Added. + * global.c: Add global sequence counter for above. + * implement.h: Likewise. + +2011-03-25 Ross Johnson + + * (cancelLock): Convert to an MCS lock and rename to stateLock. + * (threadLock): Likewise. + * (keyLock): Likewise. + * pthread_mutex*.c: First working robust mutexes. + +2011-03-11 Ross Johnson + + * implement.h (PTW32_INTERLOCKED_*CREMENT macros): increment/decrement + using ++/-- instead of add/subtract 1. + * ptw32_MCS_lock.c: Make casts consistent. + +2011-03-09 Ross Johnson + + * implement.h (ptw32_thread_t_): Add process unique sequence number. + * global.c: Replace global Critical Section objects with MCS + queue locks. + * implement.h: Likewise. + * pthread_cond_destroy.c: Likewise. + * pthread_cond_init.c: Likewise. + * pthread_detach.c: Likewise. + * pthread_join.c: Likewise. + * pthread_kill.c: Likewise. + * pthread_mutex_destroy.c: Likewise. + * pthread_rwlock_destroy.c: Likewise. + * pthread_spin_destroy.c: Likewise. + * pthread_timechange_handler_np.c: Likewise. + * ptw32_cond_check_need_init.c: Likewise. + * ptw32_mutex_check_need_init.c: Likewise. + * ptw32_processInitialize.c: Likewise. + * ptw32_processTerminate.c: Likewise. + * ptw32_reuse.c: Likewise. + * ptw32_rwlock_check_need_init.c: Likewise. + * ptw32_spinlock_check_need_init.c: Likewise. + +2011-03-06 Ross Johnson + + * several (MINGW64): Cast and call fixups for 64 bit compatibility; + clean build via x86_64-w64-mingw32 cross toolchain on Linux i686 + targeting x86_64 win64. + * ptw32_threadStart.c (ptw32_threadStart): Routine no longer attempts + to pass [unexpected C++] exceptions out of scope but ends the thread + normally setting EINTR as the exit status. + * ptw32_throw.c: Fix C++ exception throwing warnings; ignore + informational warning. + * implement.h: Likewise with the corresponding header definition. + +2011-03-04 Ross Johnson + + * implement.h (PTW32_INTERLOCKED_*): Mingw32 does not provide + the __sync_* intrinsics so implemented them here as macro + assembler routines. MSVS Interlocked* are emmitted as intrinsics + wherever possible, so we want mingw to match it; Extended to + include all interlocked routines used by the library; implemented + x86_64 versions also. + * ptw32_InterlockedCompareExchange.c: No code remaining here. + * ptw32_MCS_lock.c: Converted interlocked calls to use new macros. + * pthread_barrier_wait.c: Likewise. + * pthread_once.c: Likewise. + * ptw32_MCS_lock.c (ptw32_mcs_node_substitute): Name changed to + ptw32_mcs_node_transfer. + +2011-02-28 Ross Johnson + + * ptw32_relmillisecs.c: If possible, use _ftime64_s or _ftime64 + before resorting to _ftime. + +2011-02-27 Ross Johnson + + * sched_setscheduler.c: Ensure the handle is closed after use. + * sched_getscheduler.c: Likewise. + * pthread.h: Remove POSIX compatibility macros; don't define + timespec if already defined. + * context.h: Changes for 64 bit. + * pthread_cancel.c: Likewise. + * pthread_exit.c: Likewise. + * pthread_spin_destroy.c: Likewise. + * pthread_timechange_handler_np.c: Likewise. + * ptw32_MCS_lock.c: Likewise; some of these changes may + not be compatible with pre Windows 2000 systems; reverse the order of + the includes. + * ptw32_threadStart.c: Likewise. + * ptw32_throw.c: Likewise. + +2011-02-13 Ross Johnson + + * pthread_self: Add comment re returning 'nil' value to + indicate failure only to win32 threads that call us. + * pthread_attr_setstackaddr: Fix comments; note this + function and it's compliment are now removed from SUSv4. + +2011-02-12 Ross Johnson + + README.NONPORTABLE: Record a description of an obvious + method for nulling/comparing/hashing pthread_t using a + union; plus and investigation of a change of type for + pthread_t (to a union) to neutralise any padding bits and + bytes if they occur in pthread_t (the current pthread_t struct + does not contain padding AFAIK, but porting the library to a + future architecture may introduce them). Padding affects + byte-by-byte copies and compare operations. + +2010-11-16 Ross Johnson + + * ChangeLog: Add this entry ;-) + Restore entries from 2007 through 2009 that went missing + at the last update. + +2010-06-19 Ross Johnson + + * ptw32_MCS_lock.c (ptw32_mcs_node_substitute): Fix variable + names to avoid using C++ keyword ("new"). + * implement.h (ptw32_mcs_node_substitute): Likewise. + * pthread_barrier_wait.c: Fix signed/unsigned comparison warning. + +2010-06-18 Ramiro Polla + + * autostatic.c: New file; call pthread_win32_process_*() + libary init/cleanup routines automatically on application start + when statically linked. + * pthread.c (autostatic.c): Included. + * pthread.h (declspec): Remove import/export defines if compiler + is MINGW. + * sched.h (declspec): Likewise. + * semaphore.h (declspec): Likewise. + * need_errno.h (declspec): Likewise. + * Makefile (autostatic.obj): Add for small static builds. + * GNUmakefile (autostatic.o): Likewise. + * NEWS (Version 2.9.0): Add changes. + * README.NONPORTABLE (pthread_win32_process_*): Update + description. + +2010-06-15 Ramiro Polla + + * Makefile: Remove linkage with the winsock library by default. + * GNUmakefile: Likewise. + * pthread_getspecific.c: Likewise by removing calls to WSA + functions. + * config.h (RETAIN_WSALASTERROR): Can be defined if necessary. + +2010-01-26 Ross Johnson + + * ptw32_MCS_lock.c (ptw32_mcs_node_substitute): New routine + to allow relocating the lock owners thread-local node to somewhere + else, e.g. to global space so that another thread can release the + lock. Used in pthread_barrier_wait. + (ptw32_mcs_lock_try_acquire): New routine. + * pthread_barrier_init: Only one semaphore is used now. + * pthread_barrier_wait: Added an MCS guard lock with the last thread + to leave the barrier releasing the lock. This removes a deadlock bug + observed when there are greater than barrier-count threads + attempting to cross. + * pthread_barrier_destroy: Added an MCS guard lock. + +2009-03-03 Stephan O'Farrill + + * pthread_attr_getschedpolicy.c: Add "const" to function parameter + in accordance with SUSv3 (POSIX). + * pthread_attr_getinheritsched.c: Likewise. + * pthread_mutexattr_gettype.c: Likewise. + +2008-06-06 Robert Kindred + + * ptw32_throw.c (ptw32_throw): Remove possible reference to NULL + pointer. (At the same time made the switch block conditionally + included only if exitCode is needed - RPJ.) + * pthread_testcancel.c (pthread_testcancel): Remove duplicate and + misplaced pthread_mutex_unlock(). + +2008-02-21 Sebastian Gottschalk + + * pthread_attr_getdetachstate.c (pthread_attr_getdetachstate): + Remove potential and superfluous null pointer assignment. + +2007-11-22 Ivan Pizhenko + + * pthread.h (gmtime_r): gmtime returns 0 if tm represents a time + prior to 1/1/1970. Notice this to prevent raising an exception. + * pthread.h (localtime_r): Likewise for localtime. + +2007-07-14 Marcel Ruff + + * errno.c (_errno): Fix test for pthread_self() success. + * need_errno.h: Remove unintentional line wrap from #if line. + +2007-07-14 Mike Romanchuk + + * pthread.h (timespec): Fix tv_sec type. + +2007-01-07 Sinan Kaya + + * need_errno.h: Fix declaration of _errno - the local version of + _errno() is used, e.g. by WinCE. + +2007-01-06 Ross Johnson + + * ptw32_semwait.c: Add check for invalid sem_t after acquiring the + sem_t state guard mutex and before affecting changes to sema state. + +2007-01-06 Marcel Ruff + + * error.c: Fix reference to pthread handle exitStatus member for + builds that use NEED_ERRNO (i.e. WINCE). + * context.h: Add support for ARM processor (WinCE). + * mutex.c (process.h): Exclude for WINCE. + * create.c: Likewise. + * exit.c: Likewise. + * implement.h: Likewise. + * pthread_detach.c (signal.h): Exclude for WINCE. + * pthread_join.c: Likewise. + * pthread_kill.c: Likewise. + * pthread_rwlock_init.c (errno.h): Remove - included by pthread.h. + * pthread_rwlock_destroy.c: Likewise. + * pthread_rwlock_rdlock.c: Likewise. + * pthread_rwlock_timedrdlock.c: Likewise. + * pthread_rwlock_timedwrlock.c: Likewise. + * pthread_rwlock_tryrdlock.c: Likewise. + * pthread_rwlock_trywrlock.c: likewise. + * pthread_rwlock_unlock.c: Likewise. + * pthread_rwlock_wrlock.c: Likewise. + * pthread_rwlockattr_destroy.c: Likewise. + * pthread_rwlockattr_getpshared.c: Likewise. + * pthread_rwlockattr_init.c: Likewise. + * pthread_rwlockattr_setpshared.c: Likewise. + +2007-01-06 Romano Paolo Tenca + + * pthread_cond_destroy.c: Replace sem_wait() with non-cancelable + ptw32_semwait() since pthread_cond_destroy() is not a cancelation + point. + * implement.h (ptw32_spinlock_check_need_init): Add prototype. + * ptw32_MCS_lock.c: Reverse order of includes. + +2007-01-06 Eric Berge + + * pthread_cond_destroy.c: Add LeaveCriticalSection before returning + after errors. + +2007-01-04 Ross Johnson + + * ptw32_InterlockedCompareExchange.c: Conditionally skip for + Win64 as not required. + * pthread_win32_attach_detach_np.c (pthread_win32_process_attach_np): + Test for InterlockedCompareExchange is not required for Win64. + * context.h: New file. Included by pthread_cancel.h and any tests + that need it (e.g. context1.c). + * pthread_cancel.c: Architecture-dependent context macros moved + to context.h. + +2007-01-04 Kip Streithorst + + * implement.h (PTW32_INTERLOCKED_COMPARE_EXCHANGE): Add Win64 + support. + +2006-12-20 Ross Johnson + + * sem_destroy.c: Fix the race involving invalidation of the sema; + fix incorrect return of EBUSY resulting from the mutex trylock + on the private mutex guard. + * sem_wait.c: Add check for invalid sem_t after acquiring the + sem_t state guard mutex and before affecting changes to sema state. + * sem_trywait.c: Likewise. + * sem_timedwait.c: Likewise. + * sem_getvalue.c: Likewise. + * sem_post.c: Similar. + * sem_post_multiple.c: Likewise. + * sem_init.c: Set max Win32 semaphore count to SEM_VALUE_MAX (was + _POSIX_SEM_VALUE_MAX, which is a lower value - the minimum). + + * pthread_win32_attach_detach_np.c (pthread_win32_process_attach_np): + Load COREDLL.DLL under WINCE to check existence of + InterlockedCompareExchange() routine. This used to be done to test + for TryEnterCriticalSection() but was removed when this was no + longer needed. + +2006-01-25 Prashant Thakre + + * pthread_cancel.c: Added _M_IA64 register context support. + +2005-05-13 Ross Johnson + + * pthread_kill.c (pthread_kill): Remove check for Win32 thread + priority (to confirm HANDLE validity). Useless since thread HANDLEs + a not recycle-unique. + +2005-05-30 Vladimir Kliatchko + + * pthread_once.c: Re-implement using an MCS queue-based lock. The form + of pthread_once is as proposed by Alexander Terekhov (see entry of + 2005-03-13). The MCS lock implementation does not require a unique + 'name' to identify the lock between threads. Attempts to get the Event + or Semaphore based versions of pthread_once to a satisfactory level + of robustness have thus far failed. The last problem (avoiding races + involving non recycle-unique Win32 HANDLEs) was giving everyone + grey hair trying to solve it. + + * ptw32_MCS_lock.c: New MCS queue-based lock implementation. These + locks are efficient: they have very low overhead in the uncontended case; + are efficient in contention and minimise cache-coherence updates in + managing the user level FIFO queue; do not require an ABI change in the + library. + +2005-05-27 Alexander Gottwald + + * pthread.h: Some things, like HANDLE, were only defined if + PTW32_LEVEL was >= 3. They should always be defined. + +2005-05-25 Vladimir Kliatchko + + * pthread_once.c: Eliminate all priority operations and other + complexity by replacing the event with a semaphore. The advantage + of the change is the ability to release just one waiter if the + init_routine thread is cancelled yet still release all waiters when + done. Simplify once_control state checks to improve efficiency + further. + +2005-05-24 Mikael Magnusson + + * GNUmakefile: Patched to allow cross-compile with mingw32 on Linux. + It uses macros instead of referencing dlltool, gcc and g++ directly; + added a call to ranlib. For example the GC static library can be + built with: + make CC=i586-mingw32msvc-gcc RC=i586-mingw32msvc-windres \ + RANLIB=i586-mingw32msvc-ranlib clean GC-static + +2005-05-13 Ross Johnson + + * pthread_win32_attach_detach_np.c (pthread_win32_thread_detach_np): + Move on-exit-only stuff from ptw32_threadDestroy() to here. + * ptw32_threadDestroy.c: It's purpose is now only to reclaim thread + resources for detached threads, or via pthread_join() or + pthread_detach() on joinable threads. + * ptw32_threadStart.c: Calling user destruct routines has moved to + pthread_win32_thread_detach_np(); call pthread_win32_thread_detach_np() + directly if statically linking, otherwise do so via dllMain; store + thread return value in thread struct for all cases, including + cancellation and exception exits; thread abnormal exits go via + pthread_win32_thread_detach_np. + * pthread_join.c (pthread_join): Don't try to get return code from + Win32 thread - always get it from he thread struct. + * pthread_detach.c (pthread_detach): reduce extent of the thread + existence check since we now don't care if the Win32 thread HANDLE has + been closed; reclaim thread resources if the thread has exited already. + * ptw32_throw.c (ptw32_throw): For Win32 threads that are not implicit, + only Call thread cleanup if statically linking, otherwise leave it to + dllMain. + * sem_post.c (_POSIX_SEM_VALUE_MAX): Change to SEM_VALUE_MAX. + * sem_post_multiple.c: Likewise. + * sem_init.c: Likewise. + +2005-05-10 Ross Johnson + + * pthread_join.c (pthread_join): Add missing check for thread ID + reference count in thread existence test; reduce extent of the + existence test since we don't care if the Win32 thread HANDLE has + been closed. + +2005-05-09 Ross Johnson + + * ptw32_callUserDestroyRoutines.c: Run destructor process (i.e. + loop over all keys calling destructors) up to + PTHREAD_DESTRUCTOR_ITERATIONS times if TSD value isn't NULL yet; + modify assoc management. + * pthread_key_delete.c: Modify assoc management. + * ptw32_tkAssocDestroy.c: Fix error in assoc removal from chains. + * pthread.h + (_POSIX_THREAD_DESTRUCTOR_ITERATIONS): Define to value specified by + POSIX. + (_POSIX_THREAD_KEYS_MAX): Define to value specified by POSIX. + (PTHREAD_KEYS_MAX): Redefine [upward] to minimum required by POSIX. + (SEM_NSEMS_MAX): Define to implementation value. + (SEM_VALUE_MAX): Define to implementation value. + (_POSIX_SEM_NSEMS_MAX): Redefine to value specified by POSIX. + (_POSIX_SEM_VALUE_MAX): Redefine to value specified by POSIX. + +2005-05-06 Ross Johnson + + * signal.c (sigwait): Add a cancellation point to this otherwise + no-op. + * sem_init.c (sem_init): Check for and return ERANGE error. + * sem_post.c (sem_post): Likewise. + * sem_post_multiple.c (sem_post_multiple): Likewise. + * manual (directory): Added; see ChangeLog inside. + +2005-05-02 Ross Johnson + + * implement.h (struct pthread_key_t_): Change threadsLock to keyLock + so as not to be confused with the per thread lock 'threadlock'; + change all references to it. + * implement.h (struct ThreadKeyAssoc): Remove lock; add prevKey + and prevThread pointers; re-implemented all routines that use this + struct. The effect of this is to save one handle per association, + which could potentially equal the number of keys multiplied by the + number of threads, accumulating over time - and to free the + association memory as soon as it is no longer referenced by either + the key or the thread. Previously, the handle and memory were + released only after BOTH key and thread no longer referenced the + association. That is, often no association resources were released + until the process itself exited. In addition, at least one race + condition has been removed - where two threads could attempt to + release the association resources simultaneously - one via + ptw32_callUserDestroyRoutines and the other via + pthread_key_delete. + - thanks to Richard Hughes at Aculab for discovering the problem. + * pthread_key_create.c: See above. + * pthread_key_delete.c: See above. + * pthread_setspecific.c: See above. + * ptw32_callUserDestroyRoutines.c: See above. + * ptw32_tkAssocCreate.c: See above. + * ptw32_tkAssocDestroy.c: See above. + +2005-04-27 Ross Johnson + + * sem_wait.c (ptw32_sem_wait_cleanup): after cancellation re-attempt + to acquire the semaphore to avoid a race with a late sem_post. + * sem_timedwait.c: Modify comments. + +2005-04-25 Ross Johnson + + * ptw32_relmillisecs.c: New module; converts future abstime to + milliseconds relative to 'now'. + * pthread_mutex_timedlock.c: Use new ptw32_relmillisecs routine in + place of internal code; remove the NEED_SEM code - this routine is now + implemented for builds that define NEED_SEM (WinCE etc) + * sem_timedwait.c: Likewise; after timeout or cancellation, + re-attempt to acquire the semaphore in case one has been posted since + the timeout/cancel occurred. Thanks to Stefan Mueller. + * Makefile: Add ptw32_relmillisecs.c module; remove + ptw32_{in,de}crease_semaphore.c modules. + * GNUmakefile: Likewise. + * Bmakefile: Likewise. + + * sem_init.c: Re-write the NEED_SEM code to be consistent with the + non-NEED_SEM code, but retaining use of an event in place of the w32 sema + for w32 systems that don't include semaphores (WinCE); + the NEED_SEM versions of semaphores has been broken for a long time but is + now fixed and supports all of the same routines as the non-NEED_SEM case. + * sem_destroy.c: Likewise. + * sem_wait.c: Likewise. + * sem_post.c: Likewise. + * sem_post_multple.c: Likewise. + * implement.h: Likewise. + * sem_timedwait.c: Likewise; this routine is now + implemented for builds that define NEED_SEM (WinCE etc). + * sem_trywait.c: Likewise. + * sem_getvalue.c: Likewise. + + * pthread_once.c: Yet more changes, reverting closer to Gottlob Frege's + first design, but retaining cancellation, priority boosting, and adding + preservation of W32 error codes to make pthread_once transparent to + GetLastError. + +2005-04-11 Ross Johnson + + * pthread_once.c (pthread_once): Added priority boosting to + solve starvation problem after once_routine cancellation. + See notes in file. + +2005-04-06 Kevin Lussier + + * Makefile: Added debug targets for all versions of the library. + +2005-04-01 Ross Johnson + + * GNUmakefile: Add target to build libpthreadGC1.a as a static link + library. + * Makefile: Likewise for pthreadGC1.lib. + +2005-04-01 Kevin Lussier + + * sem_timedwait.c (sem_timedwait): Increase size of temp variables to + avoid int overflows for large timeout values. + * implement.h (int64_t): Include or define. + +2005-03-31 Dimitar Panayotov ^M + + * pthread.h: Fix conditional defines for static linking. + * sched.h: Liekwise. + * semaphore.h: Likewise. + * dll.c (PTW32_STATIC_LIB): Module is conditionally included + in the build. + +2005-03-16 Ross Johnson ^M + + * pthread_setcancelstate.c: Undo the last change. + +2005-03-16 Ross Johnson ^M + + * pthread_setcancelstate.c: Don't check for an async cancel event + if the library is using alertable async cancel.. + +2005-03-14 Ross Johnson + + * pthread_once.c (pthread_once): Downgrade interlocked operations to simple + memory operations where these are protected by the critical section; edit + comments. + +2005-03-13 Ross Johnson + + * pthread_once.c (pthread_once): Completely redesigned; a change was + required to the ABI (pthread_once_t_), and resulting in a version + compatibility index increment. + + NOTES: + The design (based on pseudo code contributed by Gottlob Frege) avoids + creating a kernel object if there is no contention. See URL for details:- + http://sources.redhat.com/ml/pthreads-win32/2005/msg00029.html + This uses late initialisation similar to the technique already used for + pthreads-win32 mutexes and semaphores (from Alexander Terekhov). + + The subsequent cancelation cleanup additions (by rpj) could not be implemented + without sacrificing some of the efficiency in Gottlob's design. In particular, + although each once_control uses it's own event to block on, a global CS is + required to manage it - since the event must be either re-usable or + re-creatable under cancelation. This is not needed in the non-cancelable + design because it is able to mark the event as closed (forever). + + When uncontested, a CS operation is equivalent to an Interlocked operation + in speed. So, in the final design with cancelability, an uncontested + once_control operation involves a minimum of five interlocked operations + (including the LeaveCS operation). + + ALTERNATIVES: + An alternative design from Alexander Terekhov proposed using a named mutex, + as sketched below:- + + if (!once_control) { // May be in TLS + named_mutex::guard guard(&once_control2); + if (!once_control2) { + + once_control2 = true; + } + once_control = true; + } + + A more detailed description of this can be found here:- + http://groups.yahoo.com/group/boost/message/15442 + + [Although the definition of a suitable PTHREAD_ONCE_INIT precludes use of the + TLS located flag, this is not critical.] + + There are three primary concerns though:- + 1) The [named] mutex is 'created' even in the uncontended case. + 2) A system wide unique name must be generated. + 3) Win32 mutexes are VERY slow even in the uncontended case. An uncontested + Win32 mutex lock operation can be 50 (or more) times slower than an + uncontested EnterCS operation. + + Ultimately, the named mutex trick is making use of the global locks maintained + by the kernel. + + * pthread.h (pthread_once_t_): One flag and an event HANDLE added. + (PTHREAD_ONCE_INIT): Additional values included. + +2005-03-08 Ross Johnson + + * pthread_once.c (pthread_once): Redesigned to elliminate potential + starvation problem. + - reported by Gottlob Frege + + * ptw32_threadDestroy.c (ptw32_threadDestroy): Implicit threads were + not closing their Win32 thread duplicate handle. + - reported by Dmitrii Semii + +2005-01-25 Ralf Kubis + + * Attempted acquisition of recursive mutex was causing waiting + threads to not be woken when the mutex is released. + + * GNUmakefile (GCE): Generate correct version resource comments. + +2005-01-01 Konstantin Voronkov + + * pthread_mutex_lock.c (pthread_mutex_lock): The new atomic exchange + mutex algorithm is known to allow a thread to steal the lock off + FIFO waiting threads. The next waiting FIFO thread gets a spurious + wake-up and must attempt to re-acquire the lock. The woken thread + was setting itself as the mutex's owner before the re-acquisition. + +2004-11-22 Ross Johnson + + * pthread_cond_wait.c (ptw32_cond_wait_cleanup): Undo change + from 2004-11-02. + * Makefile (DLL_VER): Added for DLL naming suffix - see README. + * GNUmakefile (DLL_VER): Likewise. + * Wmakefile (DLL_VER): Likewise. + * Bmakefile (DLL_VER): Likewise. + * pthread.dsw (version.rc): Added to MSVS workspace. + +2004-11-20 Boudewijn Dekker + + * pthread_getspecific.c (pthread_getspecific): Check for + invalid (NULL) key argument. + +2004-11-19 Ross Johnson + + * config.h (PTW32_THREAD_ID_REUSE_INCREMENT): Added to allow + building the library for either unique thread IDs like Solaris + or non-unique thread IDs like Linux; allows application developers + to override the library's default insensitivity to some apps + that may not be strictly POSIX compliant. + * version.rc: New resource module to encode version information + within the DLL. + * pthread.h: Added PTW32_VERSION* defines and grouped sections + required by resource compiler together; bulk of file is skipped + if RC_INVOKED. Defined some error numbers and other names for + Borland compiler. + +2004-11-02 Ross Johnson + + * pthread_cond_wait.c (ptw32_cond_wait_cleanup): Lock CV mutex at + start of cleanup handler rather than at the end. + * implement.h (PTW32_THREAD_REUSE_EMPTY): Renamed from *_BOTTOM. + (ptw32_threadReuseBottom): New global variable. + * global.c (ptw32_threadReuseBottom): Declare new variable. + * ptw32_reuse.c (ptw32_reuse): Change reuse LIFO stack to LILO queue + to more evenly distribute use of reusable thread IDs; use renamed + PTW32_THREAD_REUSE_EMPTY. + * ptw32_processTerminate.c (ptw2_processTerminate): Use renamed + PTW32_THREAD_REUSE_EMPTY. + +2004-10-31 Ross Johnson + + * implement.h (PThreadState): Add new state value + 'PThreadStateCancelPending'. + * pthread_testcancel.c (pthread_testcancel): Use new thread + 'PThreadStateCancelPending' state as short cut to avoid entering + kernel space via WaitForSingleObject() call. This was obviated + by user space sema acquisition in sem_wait() and sem_timedwait(), + which are also cancelation points. A call to pthread_testcancel() + was required, which introduced a kernel call, effectively nullifying + any gains made by the user space sem acquisition checks. + * pthread_cancel.c (pthread_cancel): Set new thread + 'PThreadStateCancelPending' state. + +2004-10-29 Ross Johnson + + * implement.h (pthread_t): Renamed to ptw32_thread_t; struct contains + all thread state. + * pthread.h (ptw32_handle_t): New general purpose struct to serve + as a handle for various reusable object IDs - currently only used + by pthread_t; contains a pointer to ptw32_thread_t (thread state) + and a general purpose uint for use as a reuse counter or flags etc. + (pthread_t): typedef'ed to ptw32_handle_t; the uint is the reuse + counter that allows the library to maintain unique POSIX thread IDs. + When the pthread struct reuse stack was introduced, threads would + often acquire an identical ID to a previously destroyed thread. The + same was true for the pre-reuse stack library, by virtue of pthread_t + being the address of the thread struct. The new pthread_t retains + the reuse stack but provides virtually unique thread IDs. + * sem_wait.c (ptw32_sem_wait_cleanup): New routine used for + cancelation cleanup. + * sem_timedwait.c (ptw32_sem_timedwait_cleanup): Likewise. + +2004-10-22 Ross Johnson + + * sem_init.c (sem_init): Introduce a 'lock' element in order to + replace the interlocked operations with conventional serialisation. + This is needed in order to be able to atomically modify the sema + value and perform Win32 sema release operations. Win32 semaphores are + used instead of events in order to support efficient multiple posting. + If the whole modify/release isn't atomic, a race between + sem_timedwait() and sem_post() could result in a release when there is + no waiting semaphore, which would cause too many threads to proceed. + * sem_wait.c (sem_wait): Use new 'lock'element. + * sem_timedwait.c (sem_timedwait): Likewise. + * sem_trywait.c (sem_trywait): Likewise. + * sem_post.c (sem_post): Likewise. + * sem_post_multiple.c (sem_post_multiple): Likewise. + * sem_getvalue.c (sem_getvalue): Likewise. + * ptw32_semwait.c (ptw32_semwait): Likewise. + * sem_destroy.c (sem_destroy): Likewise; also tightened the conditions + for semaphore destruction; in particular, a semaphore will not be + destroyed if it has waiters. + * sem_timedwait.c (sem_timedwait): Added cancel cleanup handler to + restore sema value when cancelled. + * sem_wait.c (sem_wait): Likewise. + +2004-10-21 Ross Johnson + + * pthread_mutex_unlock.c (pthread_mutex_unlock): Must use PulseEvent() + rather than SetEvent() to reset the event if there are no waiters. + +2004-10-19 Ross Johnson + + * sem_init.c (sem_init): New semaphore model based on the same idea + as mutexes, i.e. user space interlocked check to avoid + unnecessarily entering kernel space. Wraps the Win32 semaphore and + keeps it's own counter. Although the motivation to do this has existed + for a long time, credit goes to Alexander Terekhov for providing + the logic. I have deviated slightly from AT's logic to add the waiters + count, which has made the code more complicated by adding cancelation + cleanup. This also appears to have broken the VCE (C++ EH) version of + the library (the same problem as previously reported - see BUGS #2), + only apparently not fixable using the usual workaround, nor by turning + all optimisation off. The GCE version works fine, so it is presumed to + be a bug in MSVC++ 6.0. The cancelation exception is thrown and caught + correctly, but the cleanup class destructor is never called. The failing + test is tests\semaphore4.c. + * sem_wait.c (sem_wait): Implemented user space check model. + * sem_post.c (sem_post): Likewise. + * sem_trywait.c (sem_trywait): Likewise. + * sem_timedwait.c (sem_timedwait): Likewise. + * sem_post_multiple.c (sem_post_multiple): Likewise. + * sem_getvalue.c (sem_getvalue): Likewise. + * ptw32_semwait.c (ptw32_semwait): Likewise. + * implement.h (sem_t_): Add counter element. + +2004-10-15 Ross Johnson + + * implement.h (pthread_mutex_t_): Use an event in place of + the POSIX semaphore. + * pthread_mutex_init.c: Create the event; remove semaphore init. + * pthread_mutex_destroy.c: Delete the event. + * pthread_mutex_lock.c: Replace the semaphore wait with the event wait. + * pthread_mutex_trylock.c: Likewise. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_unlock.c: Set the event. + +2004-10-14 Ross Johnson + + * pthread_mutex_lock.c (pthread_mutex_lock): New algorithm using + Terekhov's xchg based variation of Drepper's cmpxchg model. + Theoretically, xchg uses fewer clock cycles than cmpxchg (using IA-32 + as a reference), however, in my opinion bus locking dominates the + equation on smp systems, so the model with the least number of bus + lock operations in the execution path should win, which is Terekhov's + variant. On IA-32 uni-processor systems, it's faster to use the + CMPXCHG instruction without locking the bus than to use the XCHG + instruction, which always locks the bus. This makes the two variants + equal for the non-contended lock (fast lane) execution path on up + IA-32. Testing shows that the xchg variant is faster on up IA-32 as + well if the test forces higher lock contention frequency, even though + kernel calls should be dominating the times (on up IA-32, both + variants used CMPXCHG instructions and neither locked the bus). + * pthread_mutex_timedlock.c pthread_mutex_timedlock(): Similarly. + * pthread_mutex_trylock.c (pthread_mutex_trylock): Similarly. + * pthread_mutex_unlock.c (pthread_mutex_unlock): Similarly. + * ptw32_InterlockedCompareExchange.c (ptw32_InterlockExchange): New + function. + (PTW32_INTERLOCKED_EXCHANGE): Sets up macro to use inlined + ptw32_InterlockedExchange. + * implement.h (PTW32_INTERLOCKED_EXCHANGE): Set default to + InterlockedExchange(). + * Makefile: Building using /Ob2 so that asm sections within inline + functions are inlined. + +2004-10-08 Ross Johnson + + * pthread_mutex_destroy.c (pthread_mutex_destroy): Critical Section + element is no longer required. + * pthread_mutex_init.c (pthread_mutex_init): Likewise. + * pthread_mutex_lock.c (pthread_mutex_lock): New algorithm following + Drepper's paper at http://people.redhat.com/drepper/futex.pdf, but + using the existing semaphore in place of the futex described in the + paper. Idea suggested by Alexander Terekhov - see: + http://sources.redhat.com/ml/pthreads-win32/2003/msg00108.html + * pthread_mutex_timedlock.c pthread_mutex_timedlock(): Similarly. + * pthread_mutex_trylock.c (pthread_mutex_trylock): Similarly. + * pthread_mutex_unlock.c (pthread_mutex_unlock): Similarly. + * pthread_barrier_wait.c (pthread_barrier_wait): Use inlined version + of InterlockedCompareExchange() if possible - determined at + build-time. + * pthread_spin_destroy.c pthread_spin_destroy(): Likewise. + * pthread_spin_lock.c pthread_spin_lock():Likewise. + * pthread_spin_trylock.c (pthread_spin_trylock):Likewise. + * pthread_spin_unlock.c (pthread_spin_unlock):Likewise. + * ptw32_InterlockedCompareExchange.c: Sets up macro for inlined use. + * implement.h (pthread_mutex_t_): Remove Critical Section element. + (PTW32_INTERLOCKED_COMPARE_EXCHANGE): Set to default non-inlined + version of InterlockedCompareExchange(). + * private.c: Include ptw32_InterlockedCompareExchange.c first for + inlining. + * GNUmakefile: Add commandline option to use inlined + InterlockedCompareExchange(). + * Makefile: Likewise. + +2004-09-27 Ross Johnson + + * pthread_mutex_lock.c (pthread_mutex_lock): Separate + PTHREAD_MUTEX_NORMAL logic since we do not need to keep or check some + state required by other mutex types; do not check mutex pointer arg + for validity - leave this to the system since we are only checking + for NULL pointers. This should improve speed of NORMAL mutexes and + marginally improve speed of other type. + * pthread_mutex_trylock.c (pthread_mutex_trylock): Likewise. + * pthread_mutex_unlock.c (pthread_mutex_unlock): Likewise; also avoid + entering the critical section for the no-waiters case, with approx. + 30% reduction in lock/unlock overhead for this case. + * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise; also + no longer keeps mutex if post-timeout second attempt succeeds - this + will assist applications that wish to impose strict lock deadlines, + rather than simply to escape from frozen locks. + +2004-09-09 Tristan Savatier + * pthread.h (struct pthread_once_t_): Qualify the 'done' element + as 'volatile'. + * pthread_once.c: Concerned about possible race condition, + specifically on MPU systems re concurrent access to multibyte types. + [Maintainer's note: the race condition is harmless on SPU systems + and only a problem on MPU systems if concurrent access results in an + exception (presumably generated by a hardware interrupt). There are + other instances of similar harmless race conditions that have not + been identified as issues.] + +2004-09-09 Ross Johnson + + * pthread.h: Declare additional types as volatile. + +2004-08-27 Ross Johnson + + * pthread_barrier_wait.c (pthread_barrier_wait): Remove excessive code + by substituting the internal non-cancelable version of sem_wait + (ptw32_semwait). + +2004-08-25 Ross Johnson + + * pthread_join.c (pthread_join): Rewrite and re-order the conditional + tests in an attempt to improve efficiency and remove a race + condition. + +2004-08-23 Ross Johnson + + * create.c (pthread_create): Don't create a thread if the thread + id pointer location (first arg) is inaccessible. A memory + protection fault will result if the thread id arg isn't an accessible + location. This is consistent with GNU/Linux but different to + Solaris or MKS (and possibly others), which accept NULL as meaning + 'don't return the created thread's ID'. Applications that run + using pthreads-win32 will run on all other POSIX threads + implementations, at least w.r.t. this feature. + + It was decided not to copy the Solaris et al behaviour because, + although it would have simplified some application porting (but only + from Solaris to Windows), the feature is not technically necessary, + and the alternative segfault behaviour helps avoid buggy application + code. + +2004-07-01 Anuj Goyal + + * builddmc.bat: New; Windows bat file to build the library. + * config.h (__DMC__): Support for Digital Mars compiler. + * create.c (__DMC__): Likewise. + * pthread_exit.c (__DMC__): Likewise. + * pthread_join.c (__DMC__): Likewise. + * ptw32_threadDestroy.c (__DMC__): Likewise. + * ptw32_threadStart.c (__DMC__): Likewise. + * ptw32_throw.c (__DMC__): Likewise. + +2004-06-29 Anuj Goyal + + * pthread.h (__DMC__): Initial support for Digital Mars compiler. + +2004-06-29 Will Bryant + + * README.Borland: New; description of Borland changes. + * Bmakefile: New makefile for the Borland make utility. + * ptw32_InterlockedCompareExchange.c: + Add Borland compatible asm code. + +2004-06-26 Jason Bard + + * pthread.h (HAVE_STRUCT_TIMESPEC): If undefined, define it + to avoid timespec struct redefined errors elsewhere in an + application. + +2004-06-21 Ross Johnson + + * pthread.h (PTHREAD_RECURSIVE_MUTEX_INITIALIZER): Mutex + initialiser added for compatibility with Linux threads and + others; currently not included in SUSV3. + * pthread.h (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER): Likewise. + * pthread.h (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Likewise. + * pthread.h (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise. + + * ptw32_mutex_check_need_init.c (ptw32_mutex_check_need_init): + Add new initialisers. + + * pthread_mutex_lock.c (pthread_mutex_lock): Check for new + initialisers. + * pthread_mutex_trylock.c (pthread_mutex_trylock): Likewise. + * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Likewise. + * pthread_mutex_unlock.c (pthread_mutex_unlock): Likewise. + * pthread_mutex_destroy.c (pthread_mutex_destroy): Likewise. + +2004-05-20 Ross Johnson + + * README.NONPORTABLE: Document pthread_win32_test_features_np(). + * FAQ: Update various answers. + +2004-05-19 Ross Johnson + + * Makefile: Don't define _WIN32_WINNT on compiler command line. + * GNUmakefile: Likewise. + +2004-05-16 Ross Johnson + + * pthread_cancel.c (pthread_cancel): Adapted to use auto-detected + QueueUserAPCEx features at run-time. + (ptw32_RegisterCancelation): Drop in replacement for QueueUserAPCEx() + if it can't be used. Provides older style non-preemptive async + cancelation. + * pthread_win32_attach_detach_np.c (pthread_win32_attach_np): + Auto-detect quserex.dll and the availability of alertdrv.sys; + initialise and close on process attach/detach. + * global.c (ptw32_register_cancelation): Pointer to either + QueueUserAPCEx() or ptw32_RegisterCancelation() depending on + availability. QueueUserAPCEx makes pre-emptive async cancelation + possible. + * implement.h: Add definitions and prototypes related to QueueUserAPC. + +2004-05-16 Panagiotis E. Hadjidoukas + + * QueueUserAPCEx (separate contributed package): Provides preemptive + APC feature. + * pthread_cancel.c (pthread_cancel): Initial integration of + QueueUserAPCEx into pthreads-win32 to provide true pre-emptive + async cancelation of threads, including blocked threads. + +2004-05-06 Makoto Kato + + * pthread.h (DWORD_PTR): Define typedef for older MSVC. + * pthread_cancel.c (AMD64): Add architecture specific Context register. + * ptw32_getprocessors.c: Use correct types (DWORD_PTR) for mask + variables. + +2004-04-06 P. van Bruggen + + * ptw32_threadDestroy.c: Destroy threadLock mutex to + close a memory leak. + +2004-02-13 Gustav Hallberg + + * pthread_equal.c: Remove redundant equality logic. + +2003-12-10 Philippe Di Cristo + + * sem_timedwait.c (sem_timedwait): Fix timeout calculations. + +2003-10-20 Alexander Terekhov + + * pthread_mutex_timedlock.c (ptw32_semwait): Move to individual module. + * ptw32_semwait.c: New module. + * pthread_cond_wait.c (ptw32_cond_wait_cleanup): Replace cancelable + sem_wait() call with non-cancelable ptw32_semwait() call. + * pthread.c (private.c): Re-order for inlining. GNU C warned that + function ptw32_semwait() was defined 'inline' after it was called. + * pthread_cond_signal.c (ptw32_cond_unblock): Likewise. + * pthread_delay_np.c: Disable Watcom warning with comment. + * *.c (process.h): Remove include from .c files. This is conditionally + included by the common project include files. + +2003-10-20 James Ewing + + * ptw32_getprocessors.c: Some Win32 environments don't have + GetProcessAffinityMask(), so always return CPU count = 1 for them. + * config.h (NEED_PROCESSOR_AFFINITY_MASK): Define for WinCE. + +2003-10-15 Ross Johnson + + * Re-indented all .c files using default GNU style to remove assorted + editor ugliness (used GNU indent utility in default style). + +2003-10-15 Alex Blanco + + * sem_init.c (sem_init): Would call CreateSemaphore even if the sema + struct calloc failed; was not freeing calloced memory if either + CreateSemaphore or CreateEvent failed. + +2003-10-14 Ross Johnson + + * pthread.h: Add Watcom compiler compatibility. Esssentially just add + the cdecl attribute to all exposed function prototypes so that Watcom + generates function call code compatible with non-Watcom built libraries. + By default, Watcom uses registers to pass function args if possible rather + than pushing to stack. + * semaphore.h: Likewise. + * sched.h: Likewise. + * pthread_cond_wait.c (ptw32_cond_wait_cleanup): Define with cdecl attribute + for Watcom compatibility. This routine is called via pthread_cleanup_push so + it had to match function arg definition. + * Wmakefile: New makefile for Watcom builds. + +2003-09-14 Ross Johnson + + * pthread_setschedparam.c (pthread_setschedparam): Attempt to map + all priority levels between max and min (as returned by + sched_get_priority_min/max) to reasonable Win32 priority levels - i.e. + levels between THREAD_PRIORITY_LOWEST/IDLE to THREAD_PRIORITY_LOWEST and + between THREAD_PRIORITY_HIGHEST/TIME_CRITICAL to THREAD_PRIORITY_HIGHEST + while others remain unchanged; record specified thread priority level + for return by pthread_getschedparam. + + Note that, previously, specified levels not matching Win32 priority levels + would silently leave the current thread priority unaltered. + + * pthread_getschedparam.c (pthread_getschedparam): Return the priority + level specified by the latest pthread_setschedparam or pthread_create rather + than the actual running thread priority as returned by GetThreadPriority - as + required by POSIX. I.e. temporary or adjusted actual priority levels are not + returned by this routine. + + * pthread_create.c (pthread_create): For priority levels specified via + pthread attributes, attempt to map all priority levels between max and + min (as returned by sched_get_priority_min/max) to reasonable Win32 + priority levels; record priority level given via attributes, or + inherited from parent thread, for later return by pthread_getschedparam. + + * ptw32_new.c (ptw32_new): Initialise pthread_t_ sched_priority element. + + * pthread_self.c (pthread_self): Set newly created implicit POSIX thread + sched_priority to Win32 thread's current actual priority. Temporarily + altered priorities can't be avoided in this case. + + * implement.h (struct pthread_t_): Add new sched_priority element. + +2003-09-12 Ross Johnson + + * sched_get_priority_min.c (sched_get_priority_min): On error should return -1 + with errno set. + * sched_get_priority_max.c (sched_get_priority_max): Likewise. + +2003-09-03 Ross Johnson + + * w32_cancelableWait.c (ptw32_cancelable_wait): Allow cancelation + of implicit POSIX threads as well. + +2003-09-02 Ross Johnson + + * pthread_win32_attach_detach_np.c (pthread_win32_thread_detach_np): + Add comment. + + * pthread_exit.c (pthread_exit): Fix to recycle the POSIX thread handle in + addition to calling user TSD destructors. Move the implicit POSIX thread exit + handling to ptw32_throw to centralise the logic. + + * ptw32_throw.c (ptw32_throw): Implicit POSIX threads have no point + to jump or throw to, so cleanup and exit the thread here in this case. For + processes using the C runtime, the exit code will be set to the POSIX + reason for the throw (i.e. PTHREAD_CANCEL or the value given to pthread_exit). + Note that pthread_exit() already had similar logic, which has been moved to + here. + + * ptw32_threadDestroy.c (ptw32_threadDestroy): Don't close the Win32 handle + of implicit POSIX threads - expect this to be done by Win32? + +2003-09-01 Ross Johnson + + * pthread_self.c (pthread_self): The newly aquired pthread_t must be + assigned to the reuse stack, not freed, if the routine fails somehow. + +2003-08-13 Ross Johnson + + * pthread_getschedparam.c (pthread_getschedparam): An invalid thread ID + parameter was returning an incorrect error value; now uses a more exhaustive + check for validity. + + * pthread_setschedparam.c (pthread_setschedparam): Likewise. + + * pthread_join.c (pthread_join): Now uses a more exhaustive + check for validity. + + * pthread_detach.c (pthread_detach): Likewise. + + * pthread_cancel.c (pthread_cancel): Likewise. + + * ptw32_threadDestroy.c (ptw32_threadDestroy): pthread_t structs are + never freed - push them onto a stack for reuse. + + * ptw32_new.c (ptw32_new): Check for reusable pthread_t before dynamically + allocating new memory for the struct. + + * pthread_kill.c (pthread_kill): New file; new routine; takes only a zero + signal arg so that applications can check the thread arg for validity; checks + that the underlying Win32 thread HANDLE is valid. + + * pthread.h (pthread_kill): Add prototype. + + * ptw32_reuse.c (ptw32_threadReusePop): New file; new routine; pop a + pthread_t off the reuse stack. pthread_t_ structs that have been destroyed, i.e. + have exited detached or have been joined, are cleaned up and put onto a reuse + stack. Consequently, thread IDs are no longer freed once calloced. The library + will attempt to get a struct off this stack before asking the system to alloc + new memory when creating threads. The stack is guarded by a global mutex. + (ptw32_threadReusePush): New routine; push a pthread_t onto the reuse stack. + + * implement.h (ptw32_threadReusePush): Add new prototype. + (ptw32_threadReusePop): Likewise. + (pthread_t): Add new element. + + * ptw32_processTerminate.c (ptw32_processTerminate): Delete the thread + reuse lock; free all thread ID structs on the thread reuse stack. + + * ptw32_processInitialize.c (ptw32_processInitialize): Initialise the + thread reuse lock. + +2003-07-19 Ross Johnson + + * GNUmakefile: modified to work under MsysDTK environment. + * pthread_spin_lock.c (pthread_spin_lock): Check for NULL arg. + * pthread_spin_unlock.c (pthread_spin_unlock): Likewise. + * pthread_spin_trylock.c (pthread_spin_trylock): Likewise; + fix incorrect pointer value if lock is dynamically initialised by + this function. + * sem_init.c (sem_init): Initialise sem_t value to quell compiler warning. + * sem_destroy.c (sem_destroy): Likewise. + * ptw32_threadStart.c (non-MSVC code sections): Include rather + than old-style ; fix all std:: namespace entities such as + std::terminate_handler instances and associated methods. + * ptw32_callUserDestroyRoutines.c (non-MSVC code sections): Likewise. + +2003-06-24 Piet van Bruggen + + * pthread_spin_destroy.c (pthread_spin_destroy): Was not freeing the + spinlock struct. + +2003-06-22 Nicolas Barry + + * pthread_mutex_destroy.c (pthread_mutex_destroy): When called + with a recursive mutex that was locked by the current thread, the + function was failing with a success return code. + +2003-05-15 Steven Reddie + + * pthread_win32_attach_detach_np.c (pthread_win32_process_detach_np): + NULLify ptw32_selfThreadKey after the thread is destroyed, otherwise + destructors calling pthreads routines might resurrect it again, creating + memory leaks. Call the underlying Win32 Tls routine directly rather than + pthread_setspecific(). + (pthread_win32_thread_detach_np): Likewise. + +2003-05-14 Viv + + * pthread.dsp: Change /MT compile flag to /MD. + +2003-03-04 Alexander Terekhov + + * pthread_mutex_timedlock.c (pthread_mutex_timedlock): Fix failure to + set ownership of mutex on second grab after abstime timeout. + - bug reported by Robert Strycek + +2002-12-17 Thomas Pfaff + + * pthread_mutex_lock.c (ptw32_semwait): New static routine to provide + a non-cancelable sem_wait() function. This is consistent with the + way that pthread_mutex_timedlock.c does it. + (pthread_mutex_lock): Use ptw32_semwait() instead of sem_wait(). + +2002-12-11 Thomas Pfaff + + * pthread_mutex_trylock.c: Should return EBUSY rather than EDEADLK. + * pthread_mutex_destroy.c: Remove redundant ownership test (the + trylock call does this for us); do not destroy a recursively locked + mutex. + +2002-09-20 Michael Johnson + + * pthread_cond_destroy.c (pthread_cond_destroy): + When two different threads exist, and one is attempting to + destroy a condition variable while the other is attempting to + initialize a condition variable that was created with + PTHREAD_COND_INITIALIZER, a deadlock can occur. Shrink + the ptw32_cond_list_lock critical section to fix it. + +2002-07-31 Ross Johnson + + * ptw32_threadStart.c (ptw32_threadStart): Thread cancelLock + destruction moved to ptw32_threadDestroy(). + + * ptw32_threadDestroy.c (ptw32_threadDestroy): Destroy + the thread's cancelLock. Moved here from ptw32_threadStart.c + to cleanup implicit threads as well. + +2002-07-30 Alexander Terekhov + + * pthread_cond_wait.c (ptw32_cond_wait_cleanup): + Remove code designed to avoid/prevent spurious wakeup + problems. It is believed that the sem_timedwait() call + is consuming a CV signal that it shouldn't and this is + breaking the avoidance logic. + +2002-07-30 Ross Johnson + + * sem_timedwait.c (sem_timedwait): Tighten checks for + unreasonable abstime values - that would result in + unexpected timeout values. + + * w32_CancelableWait.c (ptw32_cancelable_wait): + Tighten up return value checking and add comments. + + +2002-06-08 Ross Johnson + + * sem_getvalue.c (sem_getvalue): Now returns a value for the + NEED_SEM version (i.e. earlier versions of WinCE). + + +2002-06-04 Rob Fanner + + * sem_getvalue.c (sem_getvalue): The Johnson M. Hart + approach didn't work - we are forced to take an + intrusive approach. We try to decrement the sema + and then immediately release it again to get the + value. There is a small probability that this may + block other threads, but only momentarily. + +2002-06-03 Ross Johnson + + * sem_init.c (sem_init): Initialise Win32 semaphores + to _POSIX_SEM_VALUE_MAX (which this implementation + defines in pthread.h) so that sem_getvalue() can use + the trick described in the comments in sem_getvalue(). + * pthread.h (_POSIX_SEM_VALUE_MAX): Defined. + (_POSIX_SEM_NSEMS_MAX): Defined - not used but may be + useful for source code portability. + +2002-06-03 Rob Fanner + + * sem_getvalue.c (sem_getvalue): Did not work on NT. + Use approach suggested by Johnson M. Hart in his book + "Win32 System Programming". + +2002-02-28 Ross Johnson + + * errno.c: Compiler directive was incorrectly including code. + * pthread.h: Conditionally added some #defines from config.h + needed when not building the library. e.g. NEED_ERRNO, NEED_SEM. + (PTW32_DLLPORT): Now only defined if _DLL defined. + (_errno): Compiler directive was incorrectly including prototype. + * sched.h: Conditionally added some #defines from config.h + needed when not building the library. + * semaphore.h: Replace an instance of NEED_SEM that should + have been NEED_ERRNO. This change currently has nil effect. + + * GNUmakefile: Correct some recent changes. + + * Makefile: Add rule to generate pre-processor output. + +2002-02-23 Ross Johnson + + * pthread_rwlock_timedrdlock.c: New - untested. + * pthread_rwlock_timedwrlock.c: New - untested. + + * Testsuite passed (except known MSVC++ problems) + + * pthread_cond_destroy.c: Expand the time change + critical section to solve deadlock problem. + + * pthread.c: Add all remaining C modules. + * pthread.h: Use dllexport/dllimport attributes on functions + to avoid using pthread.def. + * sched.h: Likewise. + * semaphore.h: Likewise. + * GNUmakefile: Add new targets for single translation + unit build to maximise inlining potential; generate + pthread.def automatically. + * Makefile: Likewise, but no longer uses pthread.def. + +2002-02-20 Ross Johnson + + * pthread_cond_destroy.c (pthread_cond_destroy): + Enter the time change critical section earlier. + +2002-02-17 Ross Johnson + + * nonportable.c (pthread_delay_np): Make a true + cancelation point. Deferred cancels will interrupt the + wait. + +2002-02-07 Ross Johnson + + Reduced name space pollution. + ----------------------------- + When the appropriate symbols are defined, the headers + will restrict the definitions of new names. In particular, + it must be possible to NOT include the + header and related definitions with some combination + of symbol definitions. Secondly, it should be possible + that additional definitions should be limited to POSIX + compliant symbols by the definition of appropriate symbols. + + * pthread.h: POSIX conditionals. + * sched.h: POSIX conditionals. + * semaphore.h: POSIX conditionals. + + * semaphore.c: Included . + (sem_init): Changed magic 0x7FFFFFFFL to INT_MAX. + (sem_getvalue): Trial version. + + Reduce executable size. + ----------------------- + When linking with the static library, only those + routines actually called, either directly or indirectly + should be included. + + [Gcc has the -ffunction-segments option to do this but MSVC + doesn't have this feature as far as I can determine. Other + compilers are undetermined as well. - rpj] + + * semaphore.c: All routines are now in separate compilation units; + This file is used to congregate the separate modules for + potential inline optimisation and backward build compatibility. + * sem_close.c: Separated routine from semaphore.c. + * ptw32_decrease_semaphore.c: Likewise. + * sem_destroy.c: Likewise. + * sem_getvalue.c: Likewise. + * ptw32_increase_semaphore.c: Likewise. + * sem_init.c: Likewise. + * sem_open.c: Likewise. + * sem_post.c: Likewise. + * sem_post_multiple.c: Likewise. + * sem_timedwait.c: Likewise. + * sem_trywait.c: Likewise. + * sem_unlink.c: Likewise. + * sem_wait.c: Likewise. + +2002-02-04 Ross Johnson + + The following extends the idea above to the rest of pthreads-win32 - rpj + + * attr.c: All routines are now in separate compilation units; + This file is used to congregate the separate modules for + potential inline optimisation and backward build compatibility. + * pthread_attr_destroy.c: Separated routine from attr.c. + * pthread_attr_getdetachstate.c: Likewise. + * pthread_attr_getscope.c: Likewise. + * pthread_attr_getstackaddr.c: Likewise. + * pthread_attr_getstacksize.c: Likewise. + * pthread_attr_init.c: Likewise. + * pthread_attr_is_attr.c: Likewise. + * pthread_attr_setdetachstate.c: Likewise. + * pthread_attr_setscope.c: Likewise. + * pthread_attr_setstackaddr.c: Likewise. + * pthread_attr_setstacksize.c: Likewise. + + * pthread.c: Agregation of agregate modules for super-inlineability. + +2002-02-02 Ross Johnson + + * cancel.c: Rearranged some code and introduced checks + to disable cancelation at the start of a thread's cancelation + run to prevent double cancelation. The main problem + arises if a thread is canceling and then receives a subsequent + async cancel request. + * private.c: Likewise. + * condvar.c: Place pragmas around cleanup_push/pop to turn + off inline optimisation (/Obn where n>0 - MSVC only). Various + optimisation switches in MSVC turn this on, which interferes with + the way that cleanup handlers are run in C++ EH and SEH + code. Application code compiled with inline optimisation must + also wrap cleanup_push/pop blocks with the pragmas, e.g. + #pragma inline_depth(0) + pthread_cleanup_push(...) + ... + pthread_cleanup_pop(...) + #pragma inline_depth(8) + * rwlock.c: Likewise. + * mutex.c: Remove attempts to inline some functions. + * signal.c: Modify misleading comment. + +2002-02-01 Ross Johnson + + * semaphore.c (sem_trywait): Fix missing errno return + for systems that define NEED_SEM (e.g. early WinCE). + * mutex.c (pthread_mutex_timedlock): Return ENOTSUP + for systems that define NEED_SEM since they don't + have sem_trywait(). + +2002-01-27 Ross Johnson + + * mutex.c (pthread_mutex_timedlock): New function suggested by + Alexander Terekhov. The logic required to implement this + properly came from Alexander, with some collaboration + with Thomas Pfaff. + (pthread_mutex_unlock): Wrap the waiters check and sema + post in a critical section to prevent a race with + pthread_mutex_timedlock. + (ptw32_timed_semwait): New function; + returns a special result if the absolute timeout parameter + represents a time already passed when called; used by + pthread_mutex_timedwait(). Have deliberately not reused + the name "ptw32_sem_timedwait" because they are not the same + routine. + * condvar.c (ptw32_cond_timedwait): Use the new sem_timedwait() + instead of ptw32_sem_timedwait(), which now has a different + function. See previous. + * implement.h: Remove prototype for ptw32_sem_timedwait. + See next. + (pthread_mutex_t_): Add critical section element for access + to lock_idx during mutex post-timeout processing. + * semaphore.h (sem_timedwait): See next. + * semaphore.c (sem_timedwait): See next. + * private.c (ptw32_sem_timedwait): Move to semaphore.c + and rename as sem_timedwait(). + +2002-01-18 Ross Johnson + + * sync.c (pthread_join): Was getting the exit code from the + calling thread rather than the joined thread if + defined(__MINGW32__) && !defined(__MSVCRT__). + +2002-01-15 Ross Johnson + + * pthread.h: Unless the build explicitly defines __CLEANUP_SEH, + __CLEANUP_CXX, or __CLEANUP_C, then the build defaults to + __CLEANUP_C style cleanup. This style uses setjmp/longjmp + in the cancelation and thread exit implementations and therefore + won't do stack unwinding if linked to applications that have it + (e.g. C++ apps). This is currently consistent with most/all + commercial Unix POSIX threads implementations. + + * spin.c (pthread_spin_init): Edit renamed function call. + * nonportable.c (pthread_num_processors_np): New. + (pthread_getprocessors_np): Renamed to ptw32_getprocessors + and moved to private.c. + * private.c (pthread_getprocessors): Moved here from + nonportable.c. + * pthread.def (pthread_getprocessors_np): Removed + from export list. + + * rwlock.c (pthread_rwlockattr_init): New. + (pthread_rwlockattr_destroy): New. + (pthread_rwlockattr_getpshared): New. + (pthread_rwlockattr_setpshared): New. + +2002-01-14 Ross Johnson + + * attr.c (pthread_attr_setscope): Fix struct pointer + indirection error introduced 2002-01-04. + (pthread_attr_getscope): Likewise. + +2002-01-12 Ross Johnson + + * pthread.dsp (SOURCE): Add missing source files. + +2002-01-08 Ross Johnson + + * mutex.c (pthread_mutex_trylock): use + ptw32_interlocked_compare_exchange function pointer + rather than ptw32_InterlockedCompareExchange() directly + to retain portability to non-iX86 processors, + e.g. WinCE etc. The pointer will point to the native + OS version of InterlockedCompareExchange() if the + OS supports it (see ChangeLog entry of 2001-10-17). + +2002-01-07 Thomas Pfaff , Alexander Terekhov + + * mutex.c (pthread_mutex_init): Remove critical + section calls. + (pthread_mutex_destroy): Likewise. + (pthread_mutex_unlock): Likewise. + (pthread_mutex_trylock): Likewise; uses + ptw32_InterlockedCompareExchange() to avoid need for + critical section; library is no longer i386 compatible; + recursive mutexes now increment the lock count rather + than return EBUSY; errorcheck mutexes return EDEADLCK + rather than EBUSY. This behaviour is consistent with the + Solaris pthreads implementation. + * implement.h (pthread_mutex_t_): Remove critical + section element - no longer needed. + + +2002-01-04 Ross Johnson + + * attr.c (pthread_attr_setscope): Add more error + checking and actually store the scope value even + though it's not really necessary. + (pthread_attr_getscope): Return stored value. + * implement.h (pthread_attr_t_): Add new scope element. + * ANNOUNCE: Fix out of date comment next to + pthread_attr_setscope in conformance section. + +2001-12-21 Alexander Terekhov + + * mutex.c (pthread_mutex_lock): Decrementing lock_idx was + not thread-safe. + (pthread_mutex_trylock): Likewise. + +2001-10-26 prionx@juno.com + + * semaphore.c (sem_init): Fix typo and missing bracket + in conditionally compiled code. Only older versions of + WinCE require this code, hence it doesn't normally get + tested; somehow when sem_t reverted to an opaque struct + the calloc NULL check was left in the conditionally included + section. + (sem_destroy): Likewise, the calloced sem_t wasn't being freed. + +2001-10-25 Ross Johnson + + * GNUmakefile (libwsock32): Add to linker flags for + WSAGetLastError() and WSASetLastError(). + * Makefile (wsock32.lib): Likewise. + * create.c: Minor mostly inert changes. + * implement.h (PTW32_MAX): Move into here and renamed + from sched.h. + (PTW32_MIN): Likewise. + * GNUmakefile (TEST_ICE): Define if testing internal + implementation of InterlockedCompareExchange. + * Makefile (TEST_ICE): Likewise. + * private.c (TEST_ICE): Likewise. + +2001-10-24 Ross Johnson + + * attr.c (pthread_attr_setstacksize): Quell warning + from LCC by conditionally compiling the stacksize + validity check. LCC correctly warns that the condition + (stacksize < PTHREAD_STACK_MIN) is suspicious + because STACK_MIN is 0 and stacksize is of type + size_t (or unsigned int). + +2001-10-17 Ross Johnson + + * barrier.c: Move _LONG and _LPLONG defines into + implement.h; rename to PTW32_INTERLOCKED_LONG and + PTW32_INTERLOCKED_LPLONG respectively. + * spin.c: Likewise; ptw32_interlocked_compare_exchange used + in place of InterlockedCompareExchange directly. + * global.c (ptw32_interlocked_compare_exchange): Add + prototype for this new routine pointer to be used when + InterlockedCompareExchange isn't supported by Windows. + * nonportable.c (pthread_win32_process_attach_np): Check for + support of InterlockedCompareExchange in kernel32 and assign its + address to ptw32_interlocked_compare_exchange if it exists, or + our own ix86 specific implementation ptw32_InterlockedCompareExchange. + *private.c (ptw32_InterlockedCompareExchange): An + implementation of InterlockedCompareExchange() which is + specific to ix86; written directly in assembler for either + MSVC or GNU C; needed because Windows 95 doesn't support + InterlockedCompareExchange(). + + * sched.c (sched_get_priority_min): Extend to return + THREAD_PRIORITY_IDLE. + (sched_get_priority_max): Extend to return + THREAD_PRIORITY_CRITICAL. + +2001-10-15 Ross Johnson + + * spin.c (pthread_spin_lock): PTHREAD_SPINLOCK_INITIALIZER + was causing a program fault. + (pthread_spin_init): Could have alloced memory + without freeing under some error conditions. + + * mutex.c (pthread_mutex_init): Move memory + allocation of mutex struct after checking for + PROCESS_SHARED. + +2001-10-12 Ross Johnson + + * spin.c (pthread_spin_unlock): Was not returning + EPERM if the spinlock was not locked, for multi CPU + machines. + +2001-10-08 Ross Johnson + + * spin.c (pthread_spin_trylock): Was not returning + EBUSY for multi CPU machines. + +2001-08-24 Ross Johnson + + * condvar.c (pthread_cond_destroy): Remove cv element + that is no longer used. + * implement.h: Likewise. + +2001-08-23 Alexander Terekhov + + * condvar.c (pthread_cond_destroy): fix bug with + respect to deadlock in the case of concurrent + _destroy/_unblock; a condition variable can be destroyed + immediately after all the threads that are blocked on + it are awakened. + +2001-08-23 Phil Frisbie, Jr. + + * tsd.c (pthread_getspecific): Preserve the last + winsock error [from WSAGetLastError()]. + +2001-07-18 Scott McCaskill + + * mutex.c (pthread_mutexattr_init): Return ENOMEM + immediately and don't dereference the NULL pointer + if calloc fails. + (pthread_mutexattr_getpshared): Don't dereference + a pointer that is possibly NULL. + * barrier.c (pthread_barrierattr_init): Likewise + (pthread_barrierattr_getpshared): Don't dereference + a pointer that is possibly NULL. + * condvar.c (pthread_condattr_getpshared): Don't dereference + a pointer that is possibly NULL. + +2001-07-15 Ross Johnson + + * rwlock.c (pthread_rwlock_wrlock): Is allowed to be + a cancelation point; re-enable deferred cancelability + around the CV call. + +2001-07-10 Ross Johnson + + * barrier.c: Still more revamping. The exclusive access + mutex isn't really needed so it has been removed and replaced + by an InterlockedDecrement(). nSerial has been removed. + iStep is now dual-purpose. The process shared attribute + is now stored in the barrier struct. + * implement.h (pthread_barrier_t_): Lost some/gained one + elements. + * private.c (ptw32_threadStart): Removed some comments. + +2001-07-10 Ross Johnson + + * barrier.c: Revamped to fix the race condition. Two alternating + semaphores are used instead of the PulseEvent. Also improved + overall throughput by returning PTHREAD_BARRIER_SERIAL_THREAD + to the first waking thread. + * implement.h (pthread_barrier_t_): Revamped. + +2001-07-09 Ross Johnson + + * barrier.c: Fix several bugs in all routines. Now passes + tests/barrier5.c which is fairly rigorous. There is still + a non-optimal work-around for a race condition between + the barrier breeched event signal and event wait. Basically + the last (signalling) thread to hit the barrier yields + to allow any other threads, which may have lost the race, + to complete. + +2001-07-07 Ross Johnson + + * barrier.c: Changed synchronisation mechanism to a + Win32 manual reset Event and use PulseEvent to signal + waiting threads. If the implementation continued to use + a semaphore it would require a second semaphore and + some management to use them alternately as barriers. A + single semaphore allows threads to cascade from one barrier + through the next, leaving some threads blocked at the first. + * implement.h (pthread_barrier_t_): As per above. + * general: Made a number of other routines inlinable. + +2001-07-07 Ross Johnson + + * spin.c: Revamped and working; included static initialiser. + Now beta level. + * barrier.c: Likewise. + * condvar.c: Macro constant change; inline auto init routine. + * mutex.c: Likewise. + * rwlock.c: Likewise. + * private.c: Add support for spinlock initialiser. + * global.c: Likewise. + * implement.h: Likewise. + * pthread.h (PTHREAD_SPINLOCK_INITIALIZER): Fix typo. + +2001-07-05 Ross Johnson + + * barrier.c: Remove static initialisation - irrelevent + for this object. + * pthread.h (PTHREAD_BARRIER_INITIALIZER): Removed. + * rwlock.c (pthread_rwlock_wrlock): This routine is + not a cancelation point - disable deferred + cancelation around call to pthread_cond_wait(). + +2001-07-05 Ross Johnson + + * spin.c: New module implementing spin locks. + * barrier.c: New module implementing barriers. + * pthread.h (_POSIX_SPIN_LOCKS): defined. + (_POSIX_BARRIERS): Defined. + (pthread_spin_*): Defined. + (pthread_barrier*): Defined. + (PTHREAD_BARRIER_SERIAL_THREAD): Defined. + * implement.h (pthread_spinlock_t_): Defined. + (pthread_barrier_t_): Defined. + (pthread_barrierattr_t_): Defined. + + * mutex.c (pthread_mutex_lock): Return with the error + if an auto-initialiser initialisation fails. + + * nonportable.c (pthread_getprocessors_np): New; gets the + number of available processors for the current process. + +2001-07-03 Ross Johnson + + * pthread.h (_POSIX_READER_WRITER_LOCKS): Define it + if not already defined. + +2001-07-01 Alexander Terekhov + + * condvar.c: Fixed lost signal bug reported by Timur Aydin + (taydin@snet.net). + [RPJ (me) didn't translate the original algorithm + correctly.] + * semaphore.c: Added sem_post_multiple; this is a useful + routine, but it doesn't appear to be standard. For now it's + not an exported function. + +2001-06-25 Ross Johnson + + * create.c (pthread_create): Add priority inheritance + attributes. + * mutex.c (pthread_mutex_lock): Remove some overhead for + PTHREAD_MUTEX_NORMAL mutex types. Specifically, avoid + calling pthread_self() and pthread_equal() to check/set + the mutex owner. Introduce a new pseudo owner for this + type. Test results suggest increases in speed of up to + 90% for non-blocking locks. + This is the default type of mutex used internally by other + synchronising objects, ie. condition variables and + read-write locks. The test rwlock7.c shows about a + 30-35% speed increase over snapshot 2001-06-06. The + price of this is that the application developer + must ensure correct behaviour, or explicitly set the + mutex to a safer type such as PTHREAD_MUTEX_ERRORCHECK. + For example, PTHREAD_MUTEX_NORMAL (or PTHREAD_MUTEX_DEFAULT) + type mutexes will not return an error if a thread which is not + the owner calls pthread_mutex_unlock. The call will succeed + in unlocking the mutex if it is currently locked, but a + subsequent unlock by the true owner will then fail with EPERM. + This is however consistent with some other implementations. + (pthread_mutex_unlock): Likewise. + (pthread_mutex_trylock): Likewise. + (pthread_mutex_destroy): Likewise. + * attr.c (pthread_attr_init): PTHREAD_EXPLICIT_SCHED is the + default inheritance attribute; THREAD_PRIORITY_NORMAL is + the default priority for new threads. + * sched.c (pthread_attr_setschedpolicy): Added routine. + (pthread_attr_getschedpolicy): Added routine. + (pthread_attr_setinheritsched): Added routine. + (pthread_attr_getinheritsched): Added routine. + * pthread.h (sched_rr_set_interval): Added as a macro; + returns -1 with errno set to ENOSYS. + +2001-06-23 Ross Johnson + + *sched.c (pthread_attr_setschedparam): Add priority range + check. + (sched_setscheduler): New function; checks for a valid + pid and policy; checks for permission to set information + in the target process; expects pid to be a Win32 process ID, + not a process handle; the only scheduler policy allowed is + SCHED_OTHER. + (sched_getscheduler): Likewise, but checks for permission + to query. + * pthread.h (SCHED_*): Moved to sched.h as defined in the + POSIX standard. + * sched.h (SCHED_*): Moved from pthread.h. + (pid_t): Defined if necessary. + (sched_setscheduler): Defined. + (sched_getscheduler): Defined. + * pthread.def (sched_setscheduler): Exported. + (sched_getscheduler): Likewise. + +2001-06-23 Ralf Brese + + * create.c (pthread_create): Set thread priority from + thread attributes. + +2001-06-18 Ross Johnson + + * Made organisational-only changes to UWIN additions. + * dll.c (dllMain): Moved UWIN process attach code + to pthread_win32_process_attach_np(); moved + instance of pthread_count to global.c. + * global.c (pthread_count): Moved from dll.c. + * nonportable.c (pthread_win32_process_attach_np): + Moved _UWIN code to here from dll.c. + * implement.h (pthread_count): Define extern int. + * create.c (pthread_count): Remove extern int. + * private.c (pthread_count): Likewise. + * exit.c (pthread_count): Likewise. + +2001-06-18 David Korn + + * dll.c: Added changes necessary to work with UWIN. + * create.c: Likewise. + * pthread.h: Likewise. + * misc.c: Likewise. + * exit.c: Likewise. + * private.c: Likewise. + * implement.h: Likewise. + There is some room at the start of struct pthread_t_ + to implement the signal semantics in UWIN's posix.dll + although this is not yet complete. + * Nmakefile: Compatible with UWIN's Nmake utility. + * Nmakefile.tests: Likewise - for running the tests. + +2001-06-08 Ross Johnson + + * semaphore.h (sem_t): Fixed for compile and test. + * implement.h (sem_t_): Likewise. + * semaphore.c: Likewise. + * private.c (ptw32_sem_timedwait): Updated to use new + opaque sem_t. + +2001-06-06 Ross Johnson + + * semaphore.h (sem_t): Is now an opaque pointer; + moved actual definition to implement.h. + * implement.h (sem_t_): Move here from semaphore.h; + was the definition of sem_t. + * semaphore.c: Wherever necessary, changed use of sem + from that of a pointer to a pointer-pointer; added + extra checks for a valid sem_t; NULL sem_t when + it is destroyed; added extra checks when creating + and destroying sem_t elements in the NEED_SEM + code branches; changed from using a pthread_mutex_t + ((*sem)->mutex) to CRITICAL_SECTION ((*sem)->sem_lock_cs) + in NEED_SEM branches for access serialisation. + +2001-06-06 Ross Johnson + + * mutex.c (pthread_mutexattr_init): Remove + ptw32_mutex_default_kind. + +2001-06-05 Ross Johnson + + * nonportable.c (pthread_mutex_setdefaultkind_np): + Remove - should not have been included in the first place. + (pthread_mutex_getdefaultkind_np): Likewise. + * global.c (ptw32_mutex_default_kind): Likewise. + * mutex.c (pthread_mutex_init): Remove use of + ptw32_mutex_default_kind. + * pthread.h (pthread_mutex_setdefaultkind_np): Likewise. + (pthread_mutex_getdefaultkind_np): Likewise. + * pthread.def (pthread_mutexattr_setkind_np): Added. + (pthread_mutexattr_getkind_np): Likewise. + + * README: Many changes that should have gone in before + the last snapshot. + * README.NONPORTABLE: New - referred to by ANNOUNCE + but never created; documents the non-portable routines + included in the library - moved from README with new + routines added. + * ANNOUNCE (pthread_mutexattr_setkind_np): Added to + compliance list. + (pthread_mutexattr_getkind_np): Likewise. + +2001-06-04 Ross Johnson + + * condvar.c: Add original description of the algorithm as + developed by Terekhov and Thomas, plus reference to + README.CV. + +2001-06-03 Alexander Terekhov , Louis Thomas + + * condvar.c (pthread_cond_init): Completely revamped. + (pthread_cond_destroy): Likewise. + (ptw32_cond_wait_cleanup): Likewise. + (ptw32_cond_timedwait): Likewise. + (ptw32_cond_unblock): New general signaling routine. + (pthread_cond_signal): Now calls ptw32_cond_unblock. + (pthread_cond_broadcast): Likewise. + * implement.h (pthread_cond_t_): Revamped. + * README.CV: New; explanation of the above changes. + +2001-05-30 Ross Johnson + + * pthread.h (rand_r): Fake using _seed argument to quell + compiler warning (compiler should optimise this away later). + + * GNUmakefile (OPT): Leave symbolic information out of the library + and increase optimisation level - for smaller faster prebuilt + dlls. + +2001-05-29 Milan Gardian + + * Makefile: fix typo. + * pthreads.h: Fix problems with stdcall/cdecl conventions, in particular + remove the need for PT_STDCALL everywhere; remove warning supression. + * (errno): Fix the longstanding "inconsistent dll linkage" problem + with errno; now also works with /MD debugging libs - + warnings emerged when compiling pthreads library with /MD (or /MDd) + compiler switch, instead of /MT (or /MTd) (i.e. when compiling pthreads + using Multithreaded DLL CRT instead of Multithreaded statically linked + CRT). + * create.c (pthread_create): Likewise; fix typo. + * private.c (ptw32_threadStart): Eliminate use of terminate() which doesn't + throw exceptions. + * Remove unnecessary #includes from a number of modules - + [I had to #include malloc.h in implement.h for gcc - rpj]. + +2001-05-29 Thomas Pfaff + + * pthread.h (PTHREAD_MUTEX_DEFAULT): New; equivalent to + PTHREAD_MUTEX_DEFAULT_NP. + * (PTHREAD_MUTEX_NORMAL): Similarly. + * (PTHREAD_MUTEX_ERRORCHECK): Similarly. + * (PTHREAD_MUTEX_RECURSIVE): Similarly. + * (pthread_mutex_setdefaultkind_np): New; Linux compatibility stub + for pthread_mutexattr_settype. + * (pthread_mutexattr_getkind_np): New; Linux compatibility stub + for pthread_mutexattr_gettype. + * mutex.c (pthread_mutexattr_settype): New; allow + the following types of mutex: + PTHREAD_MUTEX_DEFAULT_NP + PTHREAD_MUTEX_NORMAL_NP + PTHREAD_MUTEX_ERRORCHECK_NP + PTHREAD_MUTEX_RECURSIVE_NP + * Note that PTHREAD_MUTEX_DEFAULT is equivalent to + PTHREAD_MUTEX_NORMAL - ie. mutexes should no longer + be recursive by default, and a thread will deadlock if it + tries to relock a mutex it already owns. This is inline with + other pthreads implementations. + * (pthread_mutex_lock): Process the lock request + according to the mutex type. + * (pthread_mutex_init): Eliminate use of Win32 mutexes as the + basis of POSIX mutexes - instead, a combination of one critical section + and one semaphore are used in conjunction with Win32 Interlocked* routines. + * (pthread_mutex_destroy): Likewise. + * (pthread_mutex_lock): Likewise. + * (pthread_mutex_trylock): Likewise. + * (pthread_mutex_unlock): Likewise. + * Use longjmp/setjmp to implement cancelation when building the library + using a C compiler which doesn't support exceptions, e.g. gcc -x c (note + that gcc -x c++ uses exceptions). + * Also fixed some of the same typos and eliminated PT_STDCALL as + Milan Gardian's patches above. + +2001-02-07 Alexander Terekhov + + * rwlock.c: Revamped. + * implement.h (pthread_rwlock_t_): Redefined. + This implementation does not have reader/writer starvation problem. + Rwlock attempts to behave more like a normal mutex with + races and scheduling policy determining who is more important; + It also supports recursive locking, + has less synchronization overhead (no broadcasts at all, + readers are not blocked on any condition variable) and seem to + be faster than the current implementation [W98 appears to be + approximately 15 percent faster at least - on top of speed increase + from Thomas Pfaff's changes to mutex.c - rpj]. + +2000-12-29 Ross Johnson + + * Makefile: Back-out "for" loops which don't work. + + * GNUmakefile: Remove the fake.a target; add the "realclean" + target; don't remove built libs under the "clean" target. + + * config.h: Add a guard against multiple inclusion. + + * semaphore.h: Add some defines from config.h to make + semaphore.h independent of config.h when building apps. + + * pthread.h (_errno): Back-out previous fix until we know how to + fix it properly. + + * implement.h (lockCount): Add missing element to pthread_mutex_t_. + + * sync.c (pthread_join): Spelling fix in comment. + + * private.c (ptw32_threadStart): Reset original termination + function (C++). + (ptw32_threadStart): Cleanup detached threads early in case + the library is statically linked. + (ptw32_callUserDestroyRoutines): Remove [SEH] __try block from + destructor call so that unhandled exceptions will be passed through + to the system; call terminate() from [C++] try block for the same + reason. + + * tsd.c (pthread_getspecific): Add comment. + + * mutex.c (pthread_mutex_init): Initialise new elements in + pthread_mutex_t. + (pthread_mutex_unlock): Invert "pthread_equal()" test. + +2000-12-28 Ross Johnson + + * semaphore.c (mode_t): Use ifndef HAVE_MODE_T to include definition. + + * config.h.in (HAVE_MODE_T): Added. + (_UWIN): Start adding defines for the UWIN package. + + * private.c (ptw32_threadStart): Unhandled exceptions are + now passed through to the system to deal with. This is consistent + with normal Windows behaviour. C++ applications may use + set_terminate() to override the default behaviour which is + to call ptw32_terminate(). Ptw32_terminate() cleans up some + POSIX thread stuff before calling the system default function + which calls abort(). The users termination function should conform + to standard C++ semantics which is to not return. It should + exit the thread (call pthread_exit()) or exit the application. + * private.c (ptw32_terminate): Added as the default set_terminate() + function. It calls the system default function after cleaning up + some POSIX thread stuff. + + * implement.h (ptw32_try_enter_critical_section): Move + declaration. + * global.c (ptw32_try_enter_critical_section): Moved + from dll.c. + * dll.c: Move process and thread attach/detach code into + functions in nonportable.c. + * nonportable.c (pthread_win32_process_attach_np): Process + attach code from dll.c is now available to static linked + applications. + * nonportable.c (pthread_win32_process_detach_np): Likewise. + * nonportable.c (pthread_win32_thread_attach_np): Likewise. + * nonportable.c (pthread_win32_thread_detach_np): Likewise. + + * pthread.h: Add new non-portable prototypes for static + linked applications. + + * GNUmakefile (OPT): Increase optimisation flag and remove + debug info flag. + + * pthread.def: Add new non-portable exports for static + linked applications. + +2000-12-11 Ross Johnson + + * FAQ: Update Answer 6 re getting a fully working + Mingw32 built library. + +2000-10-10 Steven Reddie + + * misc.c (pthread_self): Restore Win32 "last error" + cleared by TlsGetValue() call in + pthread_getspecific() + +2000-09-20 Arthur Kantor + + * mutex.c (pthread_mutex_lock): Record the owner + of the mutex. This requires also keeping count of + recursive locks ourselves rather than leaving it + to Win32 since we need to know when to NULL the + thread owner when the mutex is unlocked. + (pthread_mutex_trylock): Likewise. + (pthread_mutex_unlock): Check that the calling + thread owns the mutex, decrement the recursive + lock count, and NULL the owner if zero. Return + EPERM if the mutex is owned by another thread. + * implement.h (pthread_mutex_t_): Add ownerThread + and lockCount members. + +2000-09-13 Jef Gearhart + + * mutex.c (pthread_mutex_init): Call + TryEnterCriticalSection through the pointer + rather than directly so that the dll can load + on Windows versions that can't resolve the + function, eg. Windows 95 + +2000-09-09 Ross Johnson + + * pthread.h (ctime_r): Fix arg. + +2000-09-08 Ross Johnson + + * GNUmakefile(_WIN32_WINNT=0x400): Define in CFLAGS; + doesn't seem to be needed though. + + * cancel.c (pthread_cancel): Must get "self" through + calling pthread_self() which will ensure a POSIX thread + struct is built for non-POSIX threads; return an error + if this fails + - Ollie Leahy + (pthread_setcancelstate): Likewise. + (pthread_setcanceltype): Likewise. + * misc.c (ptw32_cancelable_wait): Likewise. + + * private.c (ptw32_tkAssocCreate): Remove unused #if 0 + wrapped code. + + * pthread.h (ptw32_get_exception_services_code): + Needed to be forward declared unconditionally. + +2000-09-06 Ross Johnson + + * cancel.c (pthread_cancel): If called from the main + thread "self" would be NULL; get "self" via pthread_self() + instead of directly from TLS so that an implicit + pthread object is created. + + * misc.c (pthread_equal): Strengthen test for NULLs. + +2000-09-02 Ross Johnson + + * condvar.c (ptw32_cond_wait_cleanup): Ensure that all + waking threads check if they are the last, and notify + the broadcaster if so - even if an error occurs in the + waiter. + + * semaphore.c (_decrease_semaphore): Should be + a call to ptw32_decrease_semaphore. + (_increase_semaphore): Should be a call to + ptw32_increase_semaphore. + + * misc.c (ptw32_cancelable_wait): Renamed from + CancelableWait. + * rwlock.c (_rwlock_check*): Renamed to + ptw32_rwlock_check*. + * mutex.c (_mutex_check*): Renamed to ptw32_mutex_check*. + * condvar.c (cond_timed*): Renamed to ptw32_cond_timed*. + (_cond_check*): Renamed to ptw32_cond_check*. + (cond_wait_cleanup*): Rename to ptw32_cond_wait_cleanup*. + (ptw32_cond_timedwait): Add comments. + +2000-08-22 Ross Johnson + + * private.c (ptw32_throw): Fix exception test; + move exceptionInformation declaration. + + * tsd.c (pthread_key_create): newkey wrongly declared. + + * pthread.h: Fix comment block. + +2000-08-18 Ross Johnson + + * mutex.c (pthread_mutex_destroy): Check that the mutex isn't + held; invalidate the mutex as early as possible to avoid + contention; not perfect - FIXME! + + * rwlock.c (pthread_rwlock_init): Remove redundant assignment + to "rw". + (pthread_rwlock_destroy): Invalidate the rwlock before + freeing up any of it's resources - to avoid contention. + + * private.c (ptw32_tkAssocCreate): Change assoc->lock + to use a dynamically initialised mutex - only consumes + a W32 mutex or critical section when first used, + not before. + + * mutex.c (pthread_mutex_init): Remove redundant assignment + to "mx". + (pthread_mutexattr_destroy): Set attribute to NULL + before freeing it's memory - to avoid contention. + + * implement.h (PTW32_EPS_CANCEL/PTW32_EPS_EXIT): + Must be defined for all compilers - used as generic + exception selectors by ptw32_throw(). + + * Several: Fix typos from scripted edit session + yesterday. + + * nonportable.c (pthread_mutexattr_setforcecs_np): + Moved this function from mutex.c. + (pthread_getw32threadhandle_np): New function to + return the win32 thread handle that the POSIX + thread is using. + * mutex.c (pthread_mutexattr_setforcecs_np): + Moved to new file "nonportable.c". + + * pthread.h (PTW32_BUILD): Only redefine __except + and catch compiler keywords if we aren't building + the library (ie. PTW32_BUILD is not defined) - + this is safer than defining and then undefining + if not building the library. + * implement.h: Remove __except and catch undefines. + * Makefile (CFLAGS): Define PTW32_BUILD. + * GNUmakefile (CFLAGS): Define PTW32_BUILD. + + * All appropriate: Change Pthread_exception* to + ptw32_exception* to be consistent with internal + identifier naming. + + * private.c (ptw32_throw): New function to provide + a generic exception throw for all internal + exceptions and EH schemes. + (ptw32_threadStart): pthread_exit() value is now + returned via the thread structure exitStatus + element. + * exit.c (pthread_exit): pthread_exit() value is now + returned via the thread structure exitStatus + element. + * cancel.c (ptw32_cancel_self): Now uses ptw32_throw. + (pthread_setcancelstate): Ditto. + (pthread_setcanceltype): Ditto. + (pthread_testcancel): Ditto. + (pthread_cancel): Ditto. + * misc.c (CancelableWait): Ditto. + * exit.c (pthread_exit): Ditto. + * All applicable: Change PTW32_ prefix to + PTW32_ prefix to remove leading underscores + from private library identifiers. + +2000-08-17 Ross Johnson + + * All applicable: Change _pthread_ prefix to + ptw32_ prefix to remove leading underscores + from private library identifiers (single + and double leading underscores are reserved in the + ANSI C standard for compiler implementations). + + * tsd.c (pthread_create_key): Initialise temporary + key before returning it's address to avoid race + conditions. + +2000-08-13 Ross Johnson + + * errno.c: Add _MD precompile condition; thus far + had no effect when using /MD compile option but I + thnk it should be there. + + * exit.c: Add __cplusplus to various #if lines; + was compiling SEH code even when VC++ had + C++ compile options. + + * private.c: ditto. + + * create.c (pthread_create): Add PT_STDCALL macro to + function pointer arg in _beginthread(). + + * pthread.h: PT_STDCALL really does need to be defined + in both this and impliment.h; don't set it to __cdecl + - this macro is only used to extend function pointer + casting for functions that will be passed as parameters. + (~PThreadCleanup): add cast and group expression. + (_errno): Add _MD compile conditional. + (PtW32NoCatchWarn): Change pragma message. + + * implement.h: Move and change PT_STDCALL define. + + * need_errno.h: Add _MD to compilation conditional. + + * GNUmakefile: Substantial rewrite for new naming + convention; set for nil optimisation (turn it up + when we have a working library build; add target + "fake.a" to build a libpthreadw32.a from the VC++ + built DLL pthreadVCE.dll. + + * pthread.def (LIBRARY): Don't specify in the .def + file - it is specified on the linker command line + since we now use the same .def file for variously + named .dlls. + + * Makefile: Substantial rewrite for new naming + convention; default nmake target only issues a + help message; run nmake with specific target + corresponding to the EH scheme being used. + + * README: Update information; add naming convention + explanation. + + * ANNOUNCE: Update information. + +2000-08-12 Ross Johnson + + * pthread.h: Add compile-time message when using + MSC_VER compiler and C++ EH to warn application + programmers to use PtW32Catch instead of catch(...) + if they want cancelation and pthread_exit to work. + + * implement.h: Remove #include ; we + use our own local semaphore.h. + +2000-08-10 Ross Johnson + + * cleanup.c (pthread_pop_cleanup): Remove _pthread + prefix from __except and catch keywords; implement.h + now simply undefines ptw32__except and + ptw32_catch if defined; VC++ was not textually + substituting ptw32_catch etc back to catch as + it was redefined; the reason for using the prefixed + version was to make it clear that it was not using + the pthread.h redefined catch keyword. + + * private.c (ptw32_threadStart): Ditto. + (ptw32_callUserDestroyRoutines): Ditto. + + * implement.h (ptw32__except): Remove #define. + (ptw32_catch): Remove #define. + + * GNUmakefile (pthread.a): New target to build + libpthread32.a from pthread.dll using dlltool. + + * buildlib.bat: Duplicate cl commands with args to + build C++ EH version of pthread.dll; use of .bat + files is redundant now that nmake compatible + Makefile is included; used as a kludge only now. + + * Makefile: Localise some macros and fix up the clean: + target to extend it and work properly. + + * CONTRIBUTORS: Add contributors. + + * ANNOUNCE: Updated. + + * README: Updated. + +2000-08-06 Ross Johnson + + * pthread.h: Remove #warning - VC++ doesn't accept it. + +2000-08-05 Ross Johnson + + * pthread.h (PtW32CatchAll): Add macro. When compiling + applications using VC++ with C++ EH rather than SEH + 'PtW32CatchAll' must be used in place of any 'catch( ... )' + if the application wants pthread cancelation or + pthread_exit() to work. + +2000-08-03 Ross Johnson + + * pthread.h: Add a base class ptw32_exception for + library internal exceptions and change the "catch" + re-define macro to use it. + +2000-08-02 Ross Johnson + + * GNUmakefile (CFLAGS): Add -mthreads. + Add new targets to generate cpp and asm output. + + * sync.c (pthread_join): Remove dead code. + +2000-07-25 Tristan Savatier + + * sched.c (sched_get_priority_max): Handle different WinCE and + Win32 priority values together. + (sched_get_priority_min): Ditto. + +2000-07-25 Ross Johnson + + * create.c (pthread_create): Force new threads to wait until + pthread_create has the new thread's handle; we also retain + a local copy of the handle for internal use until + pthread_create returns. + + * private.c (ptw32_threadStart): Initialise ei[]. + (ptw32_threadStart): When beginthread is used to start the + thread, force waiting until the creator thread had the + thread handle. + + * cancel.c (ptw32_cancel_thread): Include context switch + code for defined(_X86_) environments in addition to _M_IX86. + + * rwlock.c (pthread_rwlock_destroy): Assignment changed + to avoid compiler warning. + + * private.c (ptw32_get_exception_services_code): Cast + NULL return value to avoid compiler warning. + + * cleanup.c (pthread_pop_cleanup): Initialise "cleanup" variable + to avoid compiler warnings. + + * misc.c (ptw32_new): Change "new" variable to "t" to avoid + confusion with the C++ keyword of the same name. + + * condvar.c (cond_wait_cleanup): Initialise lastWaiter variable. + (cond_timedwait): Remove unused local variables. to avoid + compiler warnings. + + * dll.c (dllMain): Remove 2000-07-21 change - problem + appears to be in pthread_create(). + +2000-07-22 Ross Johnson + + * tsd.c (pthread_key_create): If a destructor was given + and the pthread_mutex_init failed, then would try to + reference a NULL pointer (*key); eliminate this section of + code by using a dynamically initialised mutex + (PTHREAD_MUTEX_INITIALIZER). + + * tsd.c (pthread_setspecific): Return an error if + unable to set the value; simplify cryptic conditional. + + * tsd.c (pthread_key_delete): Locking threadsLock relied + on mutex_lock returning an error if the key has no destructor. + ThreadsLock is only initialised if the key has a destructor. + Making this mutex a static could reduce the number of mutexes + used by an application since it is actually created only at + first use and it's often destroyed soon after. + +2000-07-22 Ross Johnson + + * FAQ: Added Q5 and Q6. + +2000-07-21 David Baggett + + * dll.c: Include resource leakage work-around. This is a + partial FIXME which doesn't stop all leakage. The real + problem needs to be found and fixed. + +2000-07-21 Ross Johnson + + * create.c (pthread_create): Set threadH to 0 (zero) + everywhere. Some assignments were using NULL. Maybe + it should be NULL everywhere - need to check. (I know + they are nearly always the same thing - but not by + definition.) + + * misc.c (pthread_self): Try to catch NULL thread handles + at the point where they might be generated, even though + they should always be valid at this point. + + * tsd.c (pthread_setspecific): return an error value if + pthread_self() returns NULL. + + * sync.c (pthread_join): return an error value if + pthread_self() returns NULL. + + * signal.c (pthread_sigmask): return an error value if + pthread_self() returns NULL. + +2000-03-02 Ross Johnson + + * attr.c (pthread_attr_init): Set default stacksize to zero (0) + rather than PTHREAD_STACK_MIN even though these are now the same. + + * pthread.h (PTHREAD_STACK_MIN): Lowered to 0. + +2000-01-28 Ross Johnson + + * mutex.c (pthread_mutex_init): Free mutex if it has been alloced; + if critical sections can be used instead of Win32 mutexes, test + that the critical section works and return an error if not. + +2000-01-07 Ross Johnson + + * cleanup.c (pthread_pop_cleanup): Include SEH code only if MSC is not + compiling as C++. + (pthread_push_cleanup): Include SEH code only if MSC is not + compiling as C++. + + * pthread.h: Include SEH code only if MSC is not + compiling as C++. + + * implement.h: Include SEH code only if MSC is not + compiling as C++. + + * cancel.c (ptw32_cancel_thread): Add _M_IX86 check. + (pthread_testcancel): Include SEH code only if MSC is not + compiling as C++. + (ptw32_cancel_self): Include SEH code only if MSC is not + compiling as C++. + +2000-01-06 Erik Hensema + + * Makefile: Remove inconsistencies in 'cl' args + +2000-01-04 Ross Johnson + + * private.c (ptw32_get_exception_services_code): New; returns + value of EXCEPTION_PTW32_SERVICES. + (ptw32_processInitialize): Remove initialisation of + ptw32_exception_services which is no longer needed. + + * pthread.h (ptw32_exception_services): Remove extern. + (ptw32_get_exception_services_code): Add function prototype; + use this to return EXCEPTION_PTW32_SERVICES value instead of + using the ptw32_exception_services variable which I had + trouble exporting through pthread.def. + + * global.c (ptw32_exception_services): Remove declaration. + +1999-11-22 Ross Johnson + + * implement.h: Forward declare ptw32_new(); + + * misc.c (ptw32_new): New; alloc and initialise a new pthread_t. + (pthread_self): New thread struct is generated by new routine + ptw32_new(). + + * create.c (pthread_create): New thread struct is generated + by new routine ptw32_new(). + +1999-11-21 Ross Johnson + + * global.c (ptw32_exception_services): Declare new variable. + + * private.c (ptw32_threadStart): Destroy thread's + cancelLock mutex; make 'catch' and '__except' usageimmune to + redfinitions in pthread.h. + (ptw32_processInitialize): Init new constant ptw32_exception_services. + + * create.c (pthread_create): Initialise thread's cancelLock + mutex. + + * cleanup.c (pthread_pop_cleanup): Make 'catch' and '__except' + usage immune to redfinition s in pthread.h. + + * private.c: Ditto. + + * pthread.h (catch): Redefine 'catch' so that C++ applications + won't catch our internal exceptions. + (__except): ditto for __except. + + * implement.h (ptw32_catch): Define internal version + of 'catch' because 'catch' is redefined by pthread.h. + (__except): ditto for __except. + (struct pthread_t_): Add cancelLock mutex for async cancel + safety. + +1999-11-21 Jason Nye , Erik Hensema + + * cancel.c (ptw32_cancel_self): New; part of the async + cancellation implementation. + (ptw32_cancel_thread): Ditto; this function is X86 + processor specific. + (pthread_setcancelstate): Add check for pending async + cancel request and cancel the calling thread if + required; add async-cancel safety lock. + (pthread_setcanceltype): Ditto. + +1999-11-13 Erik Hensema + + * configure.in (AC_OUTPUT): Put generated output into GNUmakefile + rather than Makefile. Makefile will become the MSC nmake compatible + version + +1999-11-13 John Bossom (John.Bossom@cognos.com> + + * misc.c (pthread_self): Add a note about GetCurrentThread + returning a pseudo-handle + +1999-11-10 Todd Owen + + * dll.c (dllMain): Free kernel32 ASAP. + If TryEnterCriticalSection is not being used, then free + the kernel32.dll handle now, rather than leaving it until + DLL_PROCESS_DETACH. + + Note: this is not a pedantic exercise in freeing unused + resources! It is a work-around for a bug in Windows 95 + (see microsoft knowledge base article, Q187684) which + does Bad Things when FreeLibrary is called within + the DLL_PROCESS_DETACH code, in certain situations. + Since w95 just happens to be a platform which does not + provide TryEnterCriticalSection, the bug will be + effortlessly avoided. + +1999-11-10 Ross Johnson + + * sync.c (pthread_join): Make it a deferred cancelation point. + + * misc.c (pthread_self): Explicitly initialise implicitly + created thread state to default values. + +1999-11-05 Tristan Savatier + + * pthread.h (winsock.h): Include unconditionally. + (ETIMEDOUT): Change fallback value to that defined by winsock.h. + + * general: Patched for portability to WinCE. The details are + described in the file WinCE-PORT. Follow the instructions + in README.WinCE to make the appropriate changes in config.h. + +1999-10-30 Erik Hensema + + * create.c (pthread_create): Explicitly initialise thread state to + default values. + + * cancel.c (pthread_setcancelstate): Check for NULL 'oldstate' + for compatibility with Solaris pthreads; + (pthread_setcanceltype): ditto: + +1999-10-23 Erik Hensema + + * pthread.h (ctime_r): Fix incorrect argument "_tm" + +1999-10-21 Aurelio Medina + + * pthread.h (_POSIX_THREADS): Only define it if it isn't + already defined. Projects may need to define this on + the CC command line under Win32 as it doesn't have unistd.h + +1999-10-17 Ross Johnson + + * rwlock.c (pthread_rwlock_destroy): Add cast to remove compile + warning. + + * condvar.c (pthread_cond_broadcast): Only release semaphores + if there are waiting threads. + +1999-10-15 Lorin Hochstein , Peter Slacik + + * condvar.c (cond_wait_cleanup): New static cleanup handler for + cond_timedwait; + (cond_timedwait): pthread_cleanup_push args changed; + canceling a thread while it's in pthread_cond_wait + will now decrement the waiters count and cleanup if it's the + last waiter. + +1999-10-15 Graham Dumpleton + + * condvar.c (cond_wait_cleanup): the last waiter will now reset the CV's + wasBroadcast flag + +Thu Sep 16 1999 Ross Johnson + + * rwlock.c (pthread_rwlock_destroy): Add serialisation. + (_rwlock_check_need_init): Check for detroyed rwlock. + * rwlock.c: Check return codes from _rwlock_check_need_init(); + modify comments; serialise access to rwlock objects during + operations; rename rw_mutex to rw_lock. + * implement.h: Rename rw_mutex to rw_lock. + * mutex.c (pthread_mutex_destroy): Add serialisation. + (_mutex_check_need_init): Check for detroyed mutex. + * condvar.c (pthread_cond_destroy): Add serialisation. + (_cond_check_need_init): Check for detroyed condvar. + * mutex.c: Modify comments. + * condvar.c: Modify comments. + +1999-08-10 Aurelio Medina + + * implement.h (pthread_rwlock_t_): Add. + * pthread.h (pthread_rwlock_t): Add. + (PTHREAD_RWLOCK_INITIALIZER): Add. + Add rwlock function prototypes. + * rwlock.c: New module. + * pthread.def: Add new rwlock functions. + * private.c (ptw32_processInitialize): initialise + ptw32_rwlock_test_init_lock critical section. + * global.c (ptw32_rwlock_test_init_lock): Add. + + * mutex.c (pthread_mutex_destroy): Don't free mutex memory + if mutex is PTHREAD_MUTEX_INITIALIZER and has not been + initialised yet. + +1999-08-08 Milan Gardian + + * mutex.c (pthread_mutex_destroy): Free mutex memory. + +1999-08-22 Ross Johnson + + * exit.c (pthread_exit): Fix reference to potentially + uninitialised pointer. + +1999-08-21 Ross Johnson + + * private.c (ptw32_threadStart): Apply fix of 1999-08-19 + this time to C++ and non-trapped C versions. Ommitted to + do this the first time through. + +1999-08-19 Ross Johnson + + * private.c (ptw32_threadStart): Return exit status from + the application thread startup routine. + - Milan Gardian + +1999-08-18 John Bossom + + * exit.c (pthread_exit): Put status into pthread_t->exitStatus + * private.c (ptw32_threadStart): Set pthread->exitStatus + on exit of try{} block. + * sync.c (pthread_join): use pthread_exitStatus value if the + thread exit doesn't return a value (for Mingw32 CRTDLL + which uses endthread instead of _endthreadex). + +Tue Aug 17 20:17:58 CDT 1999 Mumit Khan + + * create.c (pthread_create): Add CRTDLL suppport. + * exit.c (pthread_exit): Likewise. + * private.c (ptw32_threadStart): Likewise. + (ptw32_threadDestroy): Likewise. + * sync.c (pthread_join): Likewise. + * tests/join1.c (main): Warn about partial support for CRTDLL. + +Tue Aug 17 20:00:08 1999 Mumit Khan + + * Makefile.in (LD): Delete entry point. + * acconfig.h (STDCALL): Delete unused macro. + * configure.in: Remove test for STDCALL. + * config.h.in: Regenerate. + * errno.c (_errno): Fix self type. + * pthread.h (PT_STDCALL): Move from here to + * implement.h (PT_STDCALL): here. + (ptw32_threadStart): Fix prototype. + * private.c (ptw32_threadStart): Likewise. + +1999-08-14 Ross Johnson + + * exit.c (pthread_exit): Don't call pthread_self() but + get thread handle directly from TSD for efficiency. + +1999-08-12 Ross Johnson + + * private.c (ptw32_threadStart): ei[] only declared if _MSC_VER. + + * exit.c (pthread_exit): Check for implicitly created threads + to avoid raising an unhandled exception. + +1999-07-12 Peter Slacik + + * condvar.c (pthread_cond_destroy): Add critical section. + (cond_timedwait): Add critical section; check for timeout + waiting on semaphore. + (pthread_cond_broadcast): Add critical section. + +1999-07-09 Lorin Hochstein , John Bossom + + The problem was that cleanup handlers were not executed when + pthread_exit() was called. + + * implement.h (pthread_t_): Add exceptionInformation element for + C++ per-thread exception information. + (general): Define and rename exceptions. + +1999-07-09 Ross Johnson + + * misc.c (CancelableWait): PTW32_EPS_CANCEL (SEH) and + ptw32_exception_cancel (C++) used to identify the exception. + + * cancel.c (pthread_testcancel): PTW32_EPS_CANCEL (SEH) and + ptw32_exception_cancel (C++) used to identify the exception. + + * exit.c (pthread_exit): throw/raise an exception to return to + ptw32_threadStart() to exit the thread. PTW32_EPS_EXIT (SEH) + and ptw32_exception_exit (C++) used to identify the exception. + + * private.c (ptw32_threadStart): Add pthread_exit exception trap; + clean up and exit the thread directly rather than via pthread_exit(). + +Sun May 30 00:25:02 1999 Ross Johnson + + * semaphore.h (mode_t): Conditionally typedef it. + +Fri May 28 13:33:05 1999 Mark E. Armstrong + + * condvar.c (pthread_cond_broadcast): Fix possible memory fault + +Thu May 27 13:08:46 1999 Peter Slacik + + * condvar.c (pthread_cond_broadcast): Fix logic bug + +Thu May 27 13:08:46 1999 Bossom, John + + * condvar.c (pthread_cond_broadcast): optimise sem_post loop + +Fri May 14 12:13:18 1999 Mike Russo + + * attr.c (pthread_attr_setdetachstate): Fix logic bug + +Sat May 8 09:42:30 1999 Ross Johnson + + * pthread.def (sem_open): Add. + (sem_close): Add. + (sem_unlink): Add. + (sem_getvalue): Add. + + * FAQ (Question 3): Add. + +Thu Apr 8 01:16:23 1999 Ross Johnson + + * semaphore.c (sem_open): New function; returns an error (ENOSYS). + (sem_close): ditto. + (sem_unlink): ditto. + (sem_getvalue): ditto. + + * semaphore.h (_POSIX_SEMAPHORES): define. + +Wed Apr 7 14:09:52 1999 Ross Johnson + + * errno.c (_REENTRANT || _MT): Invert condition. + + * pthread.h (_errno): Conditionally include prototype. + +Wed Apr 7 09:37:00 1999 Ross Johnson + + * *.c (comments): Remove individual attributions - these are + documented sufficiently elsewhere. + + * implement.h (pthread.h): Remove extraneous include. + +Sun Apr 4 11:05:57 1999 Ross Johnson + + * sched.c (sched.h): Include. + + * sched.h: New file for POSIX 1b scheduling. + + * pthread.h: Move opaque structures to implement.h; move sched_* + prototypes out and into sched.h. + + * implement.h: Add opaque structures from pthread.h. + + * sched.c (sched_yield): New function. + + * condvar.c (ptw32_sem_*): Rename to sem_*; except for + ptw32_sem_timedwait which is an private function. + +Sat Apr 3 23:28:00 1999 Ross Johnson + + * Makefile.in (OBJS): Add errno.o. + +Fri Apr 2 11:08:50 1999 Ross Johnson + + * implement.h (ptw32_sem_*): Remove prototypes now defined in + semaphore.h. + + * pthread.h (sempahore.h): Include. + + * semaphore.h: New file for POSIX 1b semaphores. + + * semaphore.c (ptw32_sem_timedwait): Moved to private.c. + + * pthread.h (ptw32_sem_t): Change to sem_t. + + * private.c (ptw32_sem_timedwait): Moved from semaphore.c; + set errno on error. + + * pthread.h (pthread_t_): Add per-thread errno element. + +Fri Apr 2 11:08:50 1999 John Bossom + + * semaphore.c (ptw32_sem_*): Change to sem_*; these functions + will be exported from the library; set errno on error. + + * errno.c (_errno): New file. New function. + +Fri Mar 26 14:11:45 1999 Tor Lillqvist + + * semaphore.c (ptw32_sem_timedwait): Check for negative + milliseconds. + +Wed Mar 24 11:32:07 1999 John Bossom + + * misc.c (CancelableWait): Initialise exceptionInformation[2]. + (pthread_self): Get a real Win32 thread handle for implicit threads. + + * cancel.c (pthread_testcancel): Initialise exceptionInformation[2]. + + * implement.h (SE_INFORMATION): Fix values. + + * private.c (ptw32_threadDestroy): Close the thread handle. + +Fri Mar 19 12:57:27 1999 Ross Johnson + + * cancel.c (comments): Update and cleanup. + +Fri Mar 19 09:12:59 1999 Ross Johnson + + * private.c (ptw32_threadStart): status returns PTHREAD_CANCELED. + + * pthread.h (PTHREAD_CANCELED): defined. + +Tue Mar 16 1999 Ross Johnson + + * all: Add GNU LGPL and Copyright and Warranty. + +Mon Mar 15 00:20:13 1999 Ross Johnson + + * condvar.c (pthread_cond_init): fix possible uninitialised use + of cv. + +Sun Mar 14 21:01:59 1999 Ross Johnson + + * condvar.c (pthread_cond_destroy): don't do full cleanup if + static initialised cv has never been used. + (cond_timedwait): check result of auto-initialisation. + +Thu Mar 11 09:01:48 1999 Ross Johnson + + * pthread.h (pthread_mutex_t): revert to (pthread_mutex_t *); + define a value to serve as PTHREAD_MUTEX_INITIALIZER. + (pthread_mutex_t_): remove staticinit and valid elements. + (pthread_cond_t): revert to (pthread_cond_t_ *); + define a value to serve as PTHREAD_COND_INITIALIZER. + (pthread_cond_t_): remove staticinit and valid elements. + + * mutex.c (pthread_mutex_t args): adjust indirection of references. + (all functions): check for PTHREAD_MUTEX_INITIALIZER value; + check for NULL (invalid). + + * condvar.c (pthread_cond_t args): adjust indirection of references. + (all functions): check for PTHREAD_COND_INITIALIZER value; + check for NULL (invalid). + +Wed Mar 10 17:18:12 1999 Ross Johnson + + * misc.c (CancelableWait): Undo changes from Mar 8 and 7. + +Mon Mar 8 11:18:59 1999 Ross Johnson + + * misc.c (CancelableWait): Ensure cancelEvent handle is the lowest + indexed element in the handles array. Enhance test for abandoned + objects. + + * pthread.h (PTHREAD_MUTEX_INITIALIZER): Trailing elements not + initialised are set to zero by the compiler. This avoids the + problem of initialising the opaque critical section element in it. + (PTHREAD_COND_INITIALIZER): Ditto. + + * semaphore.c (ptw32_sem_timedwait): Check sem == NULL earlier. + +Sun Mar 7 12:31:14 1999 Ross Johnson + + * condvar.c (pthread_cond_init): set semaphore initial value + to 0, not 1. cond_timedwait was returning signaled immediately. + + * misc.c (CancelableWait): Place the cancel event handle first + in the handle table for WaitForMultipleObjects. This ensures that + the cancel event is recognised and acted apon if both objects + happen to be signaled together. + + * private.c (ptw32_cond_test_init_lock): Initialise and destroy. + + * implement.h (ptw32_cond_test_init_lock): Add extern. + + * global.c (ptw32_cond_test_init_lock): Add declaration. + + * condvar.c (pthread_cond_destroy): check for valid initialised CV; + flag destroyed CVs as invalid. + (pthread_cond_init): pthread_cond_t is no longer just a pointer. + This is because PTHREAD_COND_INITIALIZER needs state info to reside + in pthread_cond_t so that it can initialise on first use. Will work on + making pthread_cond_t (and other objects like it) opaque again, if + possible, later. + (cond_timedwait): add check for statically initialisation of + CV; initialise on first use. + (pthread_cond_signal): check for valid CV. + (pthread_cond_broadcast): check for valid CV. + (_cond_check_need_init): Add. + + * pthread.h (PTHREAD_COND_INITIALIZER): Fix. + (pthread_cond_t): no longer a pointer to pthread_cond_t_. + (pthread_cond_t_): add 'staticinit' and 'valid' elements. + +Sat Mar 6 1999 Ross Johnson + + * implement.h: Undate comments. + +Sun Feb 21 1999 Ross Johnson + + * pthread.h (PTHREAD_MUTEX_INITIALIZER): missing braces around + cs element initialiser. + +1999-02-21 Ben Elliston + + * pthread.h (pthread_exit): The return type of this function is + void, not int. + + * exit.c (pthread_exit): Do not return 0. + +Sat Feb 20 16:03:30 1999 Ross Johnson + + * dll.c (DLLMain): Expand TryEnterCriticalSection support test. + + * mutex.c (pthread_mutex_trylock): The check for + ptw32_try_enter_critical_section == NULL should have been + removed long ago. + +Fri Feb 19 16:03:30 1999 Ross Johnson + + * sync.c (pthread_join): Fix pthread_equal() test. + + * mutex.c (pthread_mutex_trylock): Check mutex != NULL before + using it. + +Thu Feb 18 16:17:30 1999 Ross Johnson + + * misc.c (pthread_equal): Fix inverted result. + + * Makefile.in: Use libpthread32.a as the name of the DLL export + library instead of pthread.lib. + + * condvar.c (pthread_cond_init): cv could have been used unitialised; + initialise. + + * create.c (pthread_create): parms could have been used unitialised; + initialise. + + * pthread.h (struct pthread_once_t_): Remove redefinition. + +Sat Feb 13 03:03:30 1999 Ross Johnson + + * pthread.h (struct pthread_once_t_): Replaced. + + * misc.c (pthread_once): Replace with John Bossom's version; + has lighter weight serialisation; fixes problem of not holding + competing threads until after the init_routine completes. + +Thu Feb 11 13:34:14 1999 Ross Johnson + + * misc.c (CancelableWait): Change C++ exception throw. + + * sync.c (pthread_join): Change FIXME comment - issue resolved. + +Wed Feb 10 12:49:11 1999 Ross Johnson + + * configure: Various temporary changes. + - Kevin Ruland + + * README: Update. + + * pthread.def (pthread_attr_getstackaddr): uncomment + (pthread_attr_setstackaddr): uncomment + +Fri Feb 5 13:42:30 1999 Ross Johnson + + * semaphore.c: Comment format changes. + +Thu Feb 4 10:07:28 1999 Ross Johnson + + * global.c: Remove ptw32_exception instantiation. + + * cancel.c (pthread_testcancel): Change C++ exception throw. + + * implement.h: Remove extern declaration. + +Wed Feb 3 13:04:44 1999 Ross Johnson + + * cleanup.c: Rename ptw32_*_cleanup() to pthread_*_cleanup(). + + * pthread.def: Ditto. + + * pthread.h: Ditto. + + * pthread.def (pthread_cleanup_push): Remove from export list; + the function is defined as a macro under all compilers. + (pthread_cleanup_pop): Ditto. + + * pthread.h: Remove #if defined(). + +Wed Feb 3 10:13:48 1999 Ross Johnson + + * sync.c (pthread_join): Check for NULL value_ptr arg; + check for detached threads. + +Tue Feb 2 18:07:43 1999 Ross Johnson + + * implement.h: Add #include . + Change sem_t to ptw32_sem_t. + +Tue Feb 2 18:07:43 1999 Kevin Ruland + + * signal.c (pthread_sigmask): Add and modify casts. + Reverse LHS/RHS bitwise assignments. + + * pthread.h: Remove #include . + (PTW32_ATTR_VALID): Add cast. + (struct pthread_t_): Add sigmask element. + + * dll.c: Add "extern C" for DLLMain. + (DllMain): Add cast. + + * create.c (pthread_create): Set sigmask in thread. + + * condvar.c: Remove #include. Change sem_* to ptw32_sem_*. + + * attr.c: Changed #include. + + * Makefile.in: Additional targets and changes to build the library + as a DLL. + +Fri Jan 29 11:56:28 1999 Ross Johnson + + * Makefile.in (OBJS): Add semaphore.o to list. + + * semaphore.c (ptw32_sem_timedwait): Move from private.c. + Rename sem_* to ptw32_sem_*. + + * pthread.h (pthread_cond_t): Change type of sem_t. + _POSIX_SEMAPHORES no longer defined. + + * semaphore.h: Contents moved to implement.h. + Removed from source tree. + + * implement.h: Add semaphore function prototypes and rename all + functions to prepend 'ptw32_'. They are + now private to the pthreads-win32 implementation. + + * private.c: Change #warning. + Move ptw32_sem_timedwait() to semaphore.c. + + * cleanup.c: Change #warning. + + * misc.c: Remove #include + + * pthread.def: Cleanup CVS merge conflicts. + + * global.c: Ditto. + + * ChangeLog: Ditto. + + * cleanup.c: Ditto. + +Sun Jan 24 01:34:52 1999 Ross Johnson + + * semaphore.c (sem_wait): Remove second arg to + pthreadCancelableWait() call. + +Sat Jan 23 17:36:40 1999 Ross Johnson + + * pthread.def: Add new functions to export list. + + * pthread.h (PTHREAD_MUTEX_AUTO_CS_NP): New. + (PTHREAD_MUTEX_FORCE_CS_NP): New. + + * README: Updated. + +Fri Jan 22 14:31:59 1999 Ross Johnson + + * Makefile.in (CFLAGS): Remove -fhandle-exceptions. Not needed + with egcs. Add -g for debugging. + + * create.c (pthread_create): Replace __stdcall with PT_STDCALL + macro. This is a hack and must be fixed. + + * misc.c (CancelableWait): Remove redundant statement. + + * mutex.c (pthread_mutexattr_init): Cast calloc return value. + + * misc.c (CancelableWait): Add cast. + (pthread_self): Add cast. + + * exit.c (pthread_exit): Add cast. + + * condvar.c (pthread_condattr_init): Cast calloc return value. + + * cleanup.c: Reorganise conditional compilation. + + * attr.c (pthread_attr_init): Remove unused 'result'. + Cast malloc return value. + + * private.c (ptw32_callUserDestroyRoutines): Redo conditional + compilation. + + * misc.c (CancelableWait): C++ version uses 'throw'. + + * cancel.c (pthread_testcancel): Ditto. + + * implement.h (class ptw32_exception): Define for C++. + + * pthread.h: Fix C, C++, and Win32 SEH condition compilation + mayhem around pthread_cleanup_* defines. C++ version now uses John + Bossom's cleanup handlers. + (pthread_attr_t): Make 'valid' unsigned. + Define '_timeb' as 'timeb' for Ming32. + Define PT_STDCALL as nothing for Mingw32. May be temporary. + + * cancel.c (pthread_testcancel): Cast return value. + +Wed Jan 20 09:31:28 1999 Ross Johnson + + * pthread.h (pthread_mutexattr_t): Changed to a pointer. + + * mutex.c (pthread_mutex_init): Conditionally create Win32 mutex + - from John Bossom's implementation. + (pthread_mutex_destroy): Conditionally close Win32 mutex + - from John Bossom's implementation. + (pthread_mutexattr_init): Replaced by John Bossom's version. + (pthread_mutexattr_destroy): Ditto. + (pthread_mutexattr_getpshared): New function from John Bossom's + implementation. + (pthread_mutexattr_setpshared): New function from John Bossom's + implementation. + +Tue Jan 19 18:27:42 1999 Ross Johnson + + * pthread.h (pthreadCancelableTimedWait): New prototype. + (pthreadCancelableWait): Remove second argument. + + * misc.c (CancelableWait): New static function is + pthreadCancelableWait() renamed. + (pthreadCancelableWait): Now just calls CancelableWait() with + INFINITE timeout. + (pthreadCancelableTimedWait): Just calls CancelableWait() + with passed in timeout. + +Tue Jan 19 18:27:42 1999 Scott Lightner + + * private.c (ptw32_sem_timedwait): 'abstime' arg really is + absolute time. Calculate relative time to wait from current + time before passing timeout to new routine + pthreadCancelableTimedWait(). + +Tue Jan 19 10:27:39 1999 Ross Johnson + + * pthread.h (pthread_mutexattr_setforcecs_np): New prototype. + + * mutex.c (pthread_mutexattr_init): Init 'pshared' and 'forcecs' + attributes to 0. + (pthread_mutexattr_setforcecs_np): New function (not portable). + + * pthread.h (pthread_mutex_t): + Add 'mutex' element. Set to NULL in PTHREAD_MUTEX_INITIALIZER. + The pthread_mutex_*() routines will try to optimise performance + by choosing either mutexes or critical sections as the basis + for pthread mutexes for each indevidual mutex. + (pthread_mutexattr_t_): Add 'forcecs' element. + Some applications may choose to force use of critical sections + if they know that:- + the mutex is PROCESS_PRIVATE and, + either the OS supports TryEnterCriticalSection() or + pthread_mutex_trylock() will never be called on the mutex. + This attribute will be setable via a non-portable routine. + + Note: We don't yet support PROCESS_SHARED mutexes, so the + implementation as it stands will default to Win32 mutexes only if + the OS doesn't support TryEnterCriticalSection. On Win9x, and early + versions of NT 'forcecs' will need to be set in order to get + critical section based mutexes. + +Sun Jan 17 12:01:26 1999 Ross Johnson + + * pthread.h (PTHREAD_MUTEX_INITIALIZER): Init new 'staticinit' + value to '1' and existing 'valid' value to '1'. + + * global.c (ptw32_mutex_test_init_lock): Add. + + * implement.h (ptw32_mutex_test_init_lock.): Add extern. + + * private.c (ptw32_processInitialize): Init critical section for + global lock used by _mutex_check_need_init(). + (ptw32_processTerminate): Ditto (:s/Init/Destroy/). + + * dll.c (dllMain): Move call to FreeLibrary() so that it is only + called once when the process detaches. + + * mutex.c (_mutex_check_need_init): New static function to test + and init PTHREAD_MUTEX_INITIALIZER mutexes. Provides serialised + access to the internal state of the uninitialised static mutex. + Called from pthread_mutex_trylock() and pthread_mutex_lock() which + do a quick unguarded test to check if _mutex_check_need_init() + needs to be called. This is safe as the test is conservative + and is repeated inside the guarded section of + _mutex_check_need_init(). Thus in all calls except the first + calls to lock static mutexes, the additional overhead to lock any + mutex is a single memory fetch and test for zero. + + * pthread.h (pthread_mutex_t_): Add 'staticinit' member. Mutexes + initialised by PTHREAD_MUTEX_INITIALIZER aren't really initialised + until the first attempt to lock it. Using the 'valid' + flag (which flags the mutex as destroyed or not) to record this + information would be messy. It is possible for a statically + initialised mutex such as this to be destroyed before ever being + used. + + * mutex.c (pthread_mutex_trylock): Call _mutex_check_need_init() + to test/init PTHREAD_MUTEX_INITIALIZER mutexes. + (pthread_mutex_lock): Ditto. + (pthread_mutex_unlock): Add check to ensure we don't try to unlock + an unitialised static mutex. + (pthread_mutex_destroy): Add check to ensure we don't try to delete + a critical section that we never created. Allows us to destroy + a static mutex that has never been locked (and hence initialised). + (pthread_mutex_init): Set 'staticinit' flag to 0 for the new mutex. + +Sun Jan 17 12:01:26 1999 Ross Johnson + + * private.c (ptw32_sem_timedwait): Move from semaphore.c. + + * semaphore.c : Remove redundant #includes. + (ptw32_sem_timedwait): Move to private.c. + (sem_wait): Add missing abstime arg to pthreadCancelableWait() call. + +Fri Jan 15 23:38:05 1999 Ross Johnson + + * condvar.c (cond_timedwait): Remove comment. + +Fri Jan 15 15:41:28 1999 Ross Johnson + + * pthread.h: Add new 'abstime' arg to pthreadCancelableWait() + prototype. + + * condvar.c (cond_timedwait): New generalised function called by + both pthread_cond_wait() and pthread_cond_timedwait(). This is + essentially pthread_cond_wait() renamed and modified to add the + 'abstime' arg and call the new ptw32_sem_timedwait() instead of + sem_wait(). + (pthread_cond_wait): Now just calls the internal static + function cond_timedwait() with an INFINITE wait. + (pthread_cond_timedwait): Now implemented. Calls the internal + static function cond_timedwait(). + + * implement.h (ptw32_sem_timedwait): New internal function + prototype. + + * misc.c (pthreadCancelableWait): Added new 'abstime' argument + to allow shorter than INFINITE wait. + + * semaphore.c (ptw32_sem_timedwait): New function for internal + use. This is essentially sem_wait() modified to add the + 'abstime' arg and call the modified (see above) + pthreadCancelableWait(). + +Thu Jan 14 14:27:13 1999 Ross Johnson + + * cleanup.c: Correct _cplusplus to __cplusplus wherever used. + + * Makefile.in: Add CC=g++ and add -fhandle-exceptions to CFLAGS. + The derived Makefile will compile all units of the package as C++ + so that those which include try/catch exception handling should work + properly. The package should compile ok if CC=gcc, however, exception + handling will not be included and thus thread cancellation, for + example, will not work. + + * cleanup.c (ptw32_pop_cleanup): Add #warning to compile this + file as C++ if using a cygwin32 environment. Perhaps the whole package + should be compiled using g++ under cygwin. + + * private.c (ptw32_threadStart): Change #error directive + into #warning and bracket for __CYGWIN__ and derivative compilers. + +Wed Jan 13 09:34:52 1999 Ross Johnson + + * build.bat: Delete old binaries before compiling/linking. + +Tue Jan 12 09:58:38 1999 Tor Lillqvist + + * dll.c: The Microsoft compiler pragmas probably are more + appropriately protected by _MSC_VER than by _WIN32. + + * pthread.h: Define ETIMEDOUT. This should be returned by + pthread_cond_timedwait which is not implemented yet as of + snapshot-1999-01-04-1305. It was implemented in the older version. + The Microsoft compiler pragmas probably are more appropriately + protected by _MSC_VER than by _WIN32. + + * pthread.def: pthread_mutex_destroy was missing from the def file + + * condvar.c (pthread_cond_broadcast): Ensure we only wait on threads + if there were any waiting on the condition. + I think pthread_cond_broadcast should do the WaitForSingleObject + only if cv->waiters > 0? Otherwise it seems to hang, at least in the + testg thread program from glib. + +Tue Jan 12 09:58:38 1999 Ross Johnson + + * condvar.c (pthread_cond_timedwait): Fix function description + comments. + + * semaphore.c (sem_post): Correct typo in comment. + +Mon Jan 11 20:33:19 1999 Ross Johnson + + * pthread.h: Re-arrange conditional compile of pthread_cleanup-* + macros. + + * cleanup.c (ptw32_push_cleanup): Provide conditional + compile of cleanup->prev. + +1999-01-11 Tor Lillqvist + + * condvar.c (pthread_cond_init): Invert logic when testing the + return value from calloc(). + +Sat Jan 9 14:32:08 1999 Ross Johnson + + * implement.h: Compile-time switch for CYGWIN derived environments + to use CreateThread instead of _beginthreadex. Ditto for ExitThread. + Patch provided by Anders Norlander . + +Tue Jan 5 16:33:04 1999 Ross Johnson + + * cleanup.c (ptw32_pop_cleanup): Add C++ version of __try/__except + block. Move trailing "}" out of #ifdef _WIN32 block left there by + (rpj's) mistake. + + * private.c: Remove #include which is included by pthread.h. + +1998-12-11 Ben Elliston + + * README: Update info about subscribing to the mailing list. + +Mon Jan 4 11:23:40 1999 Ross Johnson + + * all: No code changes, just cleanup. + - remove #if 0 /* Pre Bossom */ enclosed code. + - Remove some redundant #includes. + * pthread.h: Update implemented/unimplemented routines list. + * Tag the bossom merge branch getting ready to merge back to main + trunk. + +Tue Dec 29 13:11:16 1998 Ross Johnson + + * implement.h: Move the following struct definitions to pthread.h: + pthread_t_, pthread_attr_t_, pthread_mutex_t_, pthread_mutex_t_, + pthread_mutexattr_t_, pthread_key_t_, pthread_cond_t_, + pthread_condattr_t_, pthread_once_t_. + + * pthread.h: Add "_" prefix to pthread_push_cleanup and + pthread_pop_cleanup internal routines, and associated struct and + typedefs. + + * buildlib.bat: Add compile command for semaphore.c + + * pthread.def: Comment out pthread_atfork routine name. + Now unimplemented. + + * tsd.c (pthread_setspecific): Rename tkAssocCreate to + ptw32_tkAssocCreate. + (pthread_key_delete): Rename tkAssocDestroy to + ptw32_tkAssocDestroy. + + * sync.c (pthread_join): Rename threadDestroy to ptw32_threadDestroy + + * sched.c (is_attr): attr is now **attr (was *attr), so add extra + NULL pointer test. + (pthread_attr_setschedparam): Increase redirection for attr which is + now a **. + (pthread_attr_getschedparam): Ditto. + (pthread_setschedparam): Change thread validation and rename "thread" + Win32 thread Handle element name to match John Bossom's version. + (pthread_getschedparam): Ditto. + + * private.c (ptw32_threadDestroy): Rename call to + callUserDestroyRoutines() as ptw32_callUserDestroyRoutines() + + * misc.c: Add #include "implement.h". + + * dll.c: Remove defined(KLUDGE) wrapped code. + + * fork.c: Remove redefinition of ENOMEM. + Remove pthread_atfork() and fork() with #if 0/#endif. + + * create.c (pthread_create): Rename threadStart and threadDestroy calls + to ptw32_threadStart and ptw32_threadDestroy. + + * implement.h: Rename "detachedstate" to "detachstate". + + * attr.c: Rename "detachedstate" to "detachstate". + +Mon Dec 28 09:54:39 1998 John Bossom + + * semaphore.c: Initial version. + * semaphore.h: Initial version. + +Mon Dec 28 09:54:39 1998 Ross Johnson + + * pthread.h (pthread_attr_t_): Change to *pthread_attr_t. + +Mon Dec 28 09:54:39 1998 John Bossom, Ben Elliston + + * attr.c (pthread_attr_setstacksize): Merge with John's version. + (pthread_attr_getstacksize): Merge with John's version. + (pthread_attr_setstackaddr): Merge with John's version. + (pthread_attr_getstackaddr): Merge with John's version. + (pthread_attr_init): Merge with John's version. + (pthread_attr_destroy): Merge with John's version. + (pthread_attr_getdetachstate): Merge with John's version. + (pthread_attr_setdetachstate): Merge with John's version. + (is_attr): attr is now **attr (was *attr), so add extra NULL pointer + test. + +Mon Dec 28 09:54:39 1998 Ross Johnson + + * implement.h (pthread_attr_t_): Add and rename elements in JEB's + version to correspond to original, so that it can be used with + original attr routines. + + * pthread.h: Add #endif at end which was truncated in merging. + +Sun Dec 20 14:51:58 1998 Ross Johnson + + * misc.c (pthreadCancelableWait): New function by John Bossom. Non-standard + but provides a hook that can be used to implement cancellation points in + applications that use this library. + + * pthread.h (pthread_cleanup_pop): C++ (non-WIN32) version uses + try/catch to emulate John Bossom's WIN32 __try/__finally behaviour. + In the WIN32 version __finally block, add a test for AbnormalTermination otherwise + cleanup is only run if the cleanup_pop execute arg is non-zero. Cancellation + should cause the cleanup to run irrespective of the execute arg. + + * condvar.c (pthread_condattr_init): Replaced by John Bossom's version. + (pthread_condattr_destroy): Replaced by John Bossom's version. + (pthread_condattr_getpshared): Replaced by John Bossom's version. + (pthread_condattr_setpshared): Replaced by John Bossom's version. + (pthread_cond_init): Replaced by John Bossom's version. + Fix comment (refered to mutex rather than condition variable). + (pthread_cond_destroy): Replaced by John Bossom's version. + (pthread_cond_wait): Replaced by John Bossom's version. + (pthread_cond_timedwait): Replaced by John Bossom's version. + (pthread_cond_signal): Replaced by John Bossom's version. + (pthread_cond_broadcast): Replaced by John Bossom's version. + +Thu Dec 17 19:10:46 1998 Ross Johnson + + * tsd.c (pthread_key_create): Replaced by John Bossom's version. + (pthread_key_delete): Replaced by John Bossom's version. + (pthread_setspecific): Replaced by John Bossom's version. + (pthread_getspecific): Replaced by John Bossom's version. + +Mon Dec 7 09:44:40 1998 John Bossom + + * cancel.c (pthread_setcancelstate): Replaced. + (pthread_setcanceltype): Replaced. + (pthread_testcancel): Replaced. + (pthread_cancel): Replaced. + + * exit.c (pthread_exit): Replaced. + + * misc.c (pthread_self): Replaced. + (pthread_equal): Replaced. + + * sync.c (pthread_detach): Replaced. + (pthread_join): Replaced. + + * create.c (pthread_create): Replaced. + + * private.c (ptw32_processInitialize): New. + (ptw32_processTerminate): New. + (ptw32_threadStart): New. + (ptw32_threadDestroy): New. + (ptw32_cleanupStack): New. + (ptw32_tkAssocCreate): New. + (ptw32_tkAssocDestroy): New. + (ptw32_callUserDestroyRoutines): New. + + * implement.h: Added non-API structures and declarations. + + * dll.c (PthreadsEntryPoint): Cast return value of GetProcAddress + to resolve compile warning from MSVC. + + * dll.c (DLLmain): Replaced. + * dll.c (PthreadsEntryPoint): + Re-applied Anders Norlander's patch:- + Initialize ptw32_try_enter_critical_section at startup + and release kernel32 handle when DLL is being unloaded. + +Sun Dec 6 21:54:35 1998 Ross Johnson + + * buildlib.bat: Fix args to CL when building the .DLL + + * cleanup.c (ptw32_destructor_run_all): Fix TSD key management. + This is a tidy-up before TSD and Thread management is completely + replaced by John Bossom's code. + + * tsd.c (pthread_key_create): Fix TSD key management. + + * global.c (ptw32_key_virgin_next): Initialise. + + * build.bat: New DOS script to compile and link a pthreads app + using Microsoft's CL compiler linker. + * buildlib.bat: New DOS script to compile all the object files + and create pthread.lib and pthread.dll using Microsoft's CL + compiler linker. + +1998-12-05 Anders Norlander + + * implement.h (ptw32_try_enter_critical_section): New extern + * dll.c (ptw32_try_enter_critical_section): New pointer to + TryEnterCriticalSection if it exists; otherwise NULL. + * dll.c (PthreadsEntryPoint): + Initialize ptw32_try_enter_critical_section at startup + and release kernel32 handle when DLL is being unloaded. + * mutex.c (pthread_mutex_trylock): Replaced check for NT with + a check if ptw32_try_enter_critical_section is valid + pointer to a function. Call ptw32_try_enter_critical_section + instead of TryEnterCriticalSection to avoid errors on Win95. + +Thu Dec 3 13:32:00 1998 Ross Johnson + + * README: Correct cygwin32 compatibility statement. + +Sun Nov 15 21:24:06 1998 Ross Johnson + + * cleanup.c (ptw32_destructor_run_all): Declare missing void * arg. + Fixup CVS merge conflicts. + +1998-10-30 Ben Elliston + + * condvar.c (cond_wait): Fix semantic error. Test for equality + instead of making an assignment. + +Fri Oct 30 15:15:50 1998 Ross Johnson + + * cleanup.c (ptw32_handler_push): Fixed bug appending new + handler to list reported by Peter Slacik + . + (new_thread): Rename poorly named local variable to + "new_handler". + +Sat Oct 24 18:34:59 1998 Ross Johnson + + * global.c: Add TSD key management array and index declarations. + + * implement.h: Ditto for externs. + +Fri Oct 23 00:08:09 1998 Ross Johnson + + * implement.h (PTW32_TSD_KEY_REUSE): Add enum. + + * private.c (ptw32_delete_thread): Add call to + ptw32_destructor_run_all() to clean up the threads keys. + + * cleanup.c (ptw32_destructor_run_all): Check for no more dirty + keys to run destructors on. Assume that the destructor call always + succeeds and set the key value to NULL. + +Thu Oct 22 21:44:44 1998 Ross Johnson + + * tsd.c (pthread_setspecific): Add key management code. + (pthread_key_create): Ditto. + (pthread_key_delete): Ditto. + + * implement.h (struct ptw32_tsd_key): Add status member. + + * tsd.c: Add description of pthread_key_delete() from the + standard as a comment. + +Fri Oct 16 17:38:47 1998 Ross Johnson + + * cleanup.c (ptw32_destructor_run_all): Fix and improve + stepping through the key table. + +Thu Oct 15 14:05:01 1998 Ross Johnson + + * private.c (ptw32_new_thread): Remove init of destructorstack. + No longer an element of pthread_t. + + * tsd.c (pthread_setspecific): Fix type declaration and cast. + (pthread_getspecific): Ditto. + (pthread_getspecific): Change error return value to NULL if key + is not in use. + +Thu Oct 15 11:53:21 1998 Ross Johnson + + * global.c (ptw32_tsd_key_table): Fix declaration. + + * implement.h(ptw32_TSD_keys_TlsIndex): Add missing extern. + (ptw32_tsd_mutex): Ditto. + + * create.c (ptw32_start_call): Fix "keys" array declaration. + Add comment. + + * tsd.c (pthread_setspecific): Fix type declaration and cast. + (pthread_getspecific): Ditto. + + * cleanup.c (ptw32_destructor_run_all): Declare missing loop + counter. + +Wed Oct 14 21:09:24 1998 Ross Johnson + + * private.c (ptw32_new_thread): Increment ptw32_threads_count. + (ptw32_delete_thread): Decrement ptw32_threads_count. + Remove some comments. + + * exit.c (ptw32_exit): : Fix two pthread_mutex_lock() calls that + should have been pthread_mutex_unlock() calls. + (ptw32_vacuum): Remove call to ptw32_destructor_pop_all(). + + * create.c (pthread_create): Fix two pthread_mutex_lock() calls that + should have been pthread_mutex_unlock() calls. + + * global.c (ptw32_tsd_mutex): Add mutex for TSD operations. + + * tsd.c (pthread_key_create): Add critical section. + (pthread_setspecific): Ditto. + (pthread_getspecific): Ditto. + (pthread_key_delete): Ditto. + + * sync.c (pthread_join): Fix two pthread_mutex_lock() calls that + should have been pthread_mutex_unlock() calls. + +Mon Oct 12 00:00:44 1998 Ross Johnson + + * implement.h (ptw32_tsd_key_table): New. + + * create.c (ptw32_start_call): Initialise per-thread TSD keys + to NULL. + + * misc.c (pthread_once): Correct typo in comment. + + * implement.h (ptw32_destructor_push): Remove. + (ptw32_destructor_pop): Remove. + (ptw32_destructor_run_all): Rename from ptw32_destructor_pop_all. + (PTW32_TSD_KEY_DELETED): Add enum. + (PTW32_TSD_KEY_INUSE): Add enum. + + * cleanup.c (ptw32_destructor_push): Remove. + (ptw32_destructor_pop): Remove. + (ptw32_destructor_run_all): Totally revamped TSD. + + * dll.c (ptw32_TSD_keys_TlsIndex): Initialise. + + * tsd.c (pthread_setspecific): Totally revamped TSD. + (pthread_getspecific): Ditto. + (pthread_create): Ditto. + (pthread_delete): Ditto. + +Sun Oct 11 22:44:55 1998 Ross Johnson + + * global.c (ptw32_tsd_key_table): Add new global. + + * implement.h (ptw32_tsd_key_t and struct ptw32_tsd_key): + Add. + (struct _pthread): Remove destructorstack. + + * cleanup.c (ptw32_destructor_run_all): Rename from + ptw32_destructor_pop_all. The key destructor stack was made + global rather than per-thread. No longer removes destructor nodes + from the stack. Comments updated. + +1998-10-06 Ben Elliston + + * condvar.c (cond_wait): Use POSIX, not Win32 mutex calls. + (pthread_cond_broadcast): Likewise. + (pthread_cond_signal): Likewise. + +1998-10-05 Ben Elliston + + * pthread.def: Update. Some functions aren't available yet, others + are macros in . + + * tests/join.c: Remove; useless. + +Mon Oct 5 14:25:08 1998 Ross Johnson + + * pthread.def: New file for building the DLL. + +1998-10-05 Ben Elliston + + * misc.c (pthread_equal): Correct inverted logic bug. + (pthread_once): Use the POSIX mutex primitives, not Win32. Remove + irrelevant FIXME comment. + + * global.c (PTHREAD_MUTEX_INITIALIZER): Move to pthread.h. + + * pthread.h (PTHREAD_MUTEX_INITIALIZER): Define. + (pthread_mutex_t): Reimplement as a struct containing a valid + flag. If the flag is ever down upon entry to a mutex operation, + we call pthread_mutex_create() to initialise the object. This + fixes the problem of how to handle statically initialised objects + that can't call InitializeCriticalSection() due to their context. + (PTHREAD_ONCE_INIT): Define. + + * mutex.c (pthread_mutex_init): Set valid flag. + (pthread_mutex_destroy): Clear valid flag. + (pthread_mutex_lock): Check and handle the valid flag. + (pthread_mutex_unlock): Likewise. + (pthread_mutex_trylock): Likewise. + + * tests/mutex3.c: New file; test for the static initialisation + macro. Passes. + + * tests/create1.c: New file; test pthread_create(). Passes. + + * tests/equal.c: Poor test; remove. + + * tests/equal1.c New file; test pthread_equal(). Passes. + + * tests/once1.c: New file; test for pthread_once(). Passes. + + * tests/self.c: Remove; rename to self1.c. + + * tests/self1.c: This is the old self.c. + + * tests/self2.c: New file. Test pthread_self() with a single + thread. Passes. + + * tests/self3.c: New file. Test pthread_self() with a couple of + threads to ensure their thread IDs differ. Passes. + +1998-10-04 Ben Elliston + + * tests/mutex2.c: Test pthread_mutex_trylock(). Passes. + + * tests/mutex1.c: New basic test for mutex functions (it passes). + (main): Eliminate warning. + + * configure.in: Test for __stdcall, not _stdcall. Typo. + + * configure: Regenerate. + + * attr.c (pthread_attr_setstackaddr): Remove FIXME comment. Win32 + does know about ENOSYS after all. + (pthread_attr_setstackaddr): Likewise. + +1998-10-03 Ben Elliston + + * configure.in: Test for the `_stdcall' keyword. Define `STDCALL' + to `_stdcall' if we have it, null otherwise. + + * configure: Regenerate. + + * acconfig.h (STDCALL): New define. + + * config.h.in: Regenerate. + + * create.c (ptw32_start_call): Add STDCALL prefix. + + * mutex.c (pthread_mutex_init): Correct function signature. + + * attr.c (pthread_attr_init): Only zero out the `sigmask' member + if we have the sigset_t type. + + * pthread.h: No need to include . It doesn't even exist + on Win32! Again, an artifact of cross-compilation. + (pthread_sigmask): Only provide if we have the sigset_t type. + + * process.h: Remove. This was a stand-in before we started doing + native compilation under Win32. + + * pthread.h (pthread_mutex_init): Make `attr' argument const. + +1998-10-02 Ben Elliston + + * COPYING: Remove. + + * COPYING.LIB: Add. This library is under the LGPL. + +1998-09-13 Ben Elliston + + * configure.in: Test for required system features. + + * configure: Generate. + + * acconfig.h: New file. + + * config.h.in: Generate. + + * Makefile.in: Renamed from Makefile. + + * COPYING: Import from a recent GNU package. + + * config.guess: Likewise. + + * config.sub: Likewise. + + * install-sh: Likewise. + + * config.h: Remove. + + * Makefile: Likewise. + +1998-09-12 Ben Elliston + + * windows.h: No longer needed; remove. + + * windows.c: Likewise. + +Sat Sep 12 20:09:24 1998 Ross Johnson + + * windows.h: Remove error number definitions. These are in + + * tsd.c: Add comment explaining rationale for not building + POSIX TSD on top of Win32 TLS. + +1998-09-12 Ben Elliston + + * {most}.c: Include to get POSIX error values. + + * signal.c (pthread_sigmask): Only provide if HAVE_SIGSET_T is + defined. + + * config.h: #undef features, don't #define them. This will be + generated by autoconf very soon. + +1998-08-11 Ben Elliston + + * Makefile (LIB): Define. + (clean): Define target. + (all): Build a library not just the object files. + + * pthread.h: Provide a definition for struct timespec if we don't + already have one. + + * windows.c (TlsGetValue): Bug fix. + +Thu Aug 6 15:19:22 1998 Ross Johnson + + * misc.c (pthread_once): Fix arg 1 of EnterCriticalSection() + and LeaveCriticalSection() calls to pass address-of lock. + + * fork.c (pthread_atfork): Typecast (void (*)(void *)) funcptr + in each ptw32_handler_push() call. + + * exit.c (ptw32_exit): Fix attr arg in + pthread_attr_getdetachstate() call. + + * private.c (ptw32_new_thread): Typecast (HANDLE) NULL. + (ptw32_delete_thread): Ditto. + + * implement.h: (PTW32_MAX_THREADS): Add define. This keeps + changing in an attempt to make thread administration data types + opaque and cleanup DLL startup. + + * dll.c (PthreadsEntryPoint): + (ptw32_virgins): Remove malloc() and free() calls. + (ptw32_reuse): Ditto. + (ptw32_win32handle_map): Ditto. + (ptw32_threads_mutex_table): Ditto. + + * global.c (_POSIX_THREAD_THREADS_MAX): Initialise with + PTW32_MAX_THREADS. + (ptw32_virgins): Ditto. + (ptw32_reuse): Ditto. + (ptw32_win32handle_map): Ditto. + (ptw32_threads_mutex_table): Ditto. + + * create.c (pthread_create): Typecast (HANDLE) NULL. + Typecast (unsigned (*)(void *)) start_routine. + + * condvar.c (pthread_cond_init): Add address-of operator & to + arg 1 of pthread_mutex_init() call. + (pthread_cond_destroy): Add address-of operator & to + arg 1 of pthread_mutex_destroy() call. + + * cleanup.c (ptw32_destructor_pop_all): Add (int) cast to + pthread_getspecific() arg. + (ptw32_destructor_pop): Add (void *) cast to "if" conditional. + (ptw32_destructor_push): Add (void *) cast to + ptw32_handler_push() "key" arg. + (malloc.h): Add include. + + * implement.h (ptw32_destructor_pop): Add prototype. + + * tsd.c (implement.h): Add include. + + * sync.c (pthread_join): Remove target_thread_mutex and it's + initialisation. Rename getdetachedstate to getdetachstate. + Remove unused variable "exitcode". + (pthread_detach): Remove target_thread_mutex and it's + initialisation. Rename getdetachedstate to getdetachstate. + Rename setdetachedstate to setdetachstate. + + * signal.c (pthread_sigmask): Rename SIG_SET to SIG_SETMASK. + Cast "set" to (long *) in assignment to passify compiler warning. + Add address-of operator & to thread->attr.sigmask in memcpy() call + and assignment. + (pthread_sigmask): Add address-of operator & to thread->attr.sigmask + in memcpy() call and assignment. + + * windows.h (THREAD_PRIORITY_ERROR_RETURN): Add. + (THREAD_PRIORITY_LOWEST): Add. + (THREAD_PRIORITY_HIGHEST): Add. + + * sched.c (is_attr): Add function. + (implement.h): Add include. + (pthread_setschedparam): Rename all instances of "sched_policy" + to "sched_priority". + (pthread_getschedparam): Ditto. + +Tue Aug 4 16:57:58 1998 Ross Johnson + + * private.c (ptw32_delete_thread): Fix typo. Add missing ';'. + + * global.c (ptw32_virgins): Change types from pointer to + array pointer. + (ptw32_reuse): Ditto. + (ptw32_win32handle_map): Ditto. + (ptw32_threads_mutex_table): Ditto. + + * implement.h(ptw32_virgins): Change types from pointer to + array pointer. + (ptw32_reuse): Ditto. + (ptw32_win32handle_map): Ditto. + (ptw32_threads_mutex_table): Ditto. + + * private.c (ptw32_delete_thread): Fix "entry" should be "thread". + + * misc.c (pthread_self): Add extern for ptw32_threadID_TlsIndex. + + * global.c: Add comment. + + * misc.c (pthread_once): Fix member -> dereferences. + Change ptw32_once_flag to once_control->flag in "if" test. + +Tue Aug 4 00:09:30 1998 Ross Johnson + + * implement.h(ptw32_virgins): Add extern. + (ptw32_virgin_next): Ditto. + (ptw32_reuse): Ditto. + (ptw32_reuse_top): Ditto. + (ptw32_win32handle_map): Ditto. + (ptw32_threads_mutex_table): Ditto. + + * global.c (ptw32_virgins): Changed from array to pointer. + Storage allocation for the array moved into dll.c. + (ptw32_reuse): Ditto. + (ptw32_win32handle_map): Ditto. + (ptw32_threads_mutex_table): Ditto. + + * dll.c (PthreadsEntryPoint): Set up thread admin storage when + DLL is loaded. + + * fork.c (pthread_atfork): Fix function pointer arg to all + ptw32_handler_push() calls. Change "arg" arg to NULL in child push. + + * exit.c: Add windows.h and process.h includes. + (ptw32_exit): Add local detachstate declaration. + (ptw32_exit): Fix incorrect name for pthread_attr_getdetachstate(). + + * pthread.h (_POSIX_THREAD_ATTR_STACKSIZE): Move from global.c + (_POSIX_THREAD_ATTR_STACKADDR): Ditto. + + * create.c (pthread_create): Fix #if should be #ifdef. + (ptw32_start_call): Remove usused variables. + + * process.h: Create. + + * windows.h: Move _beginthreadex and _endthreadex into + process.h + +Mon Aug 3 21:19:57 1998 Ross Johnson + + * condvar.c (pthread_cond_init): Add NULL attr to + pthread_mutex_init() call - default attributes will be used. + (cond_wait): Fix typo. + (cond_wait): Fix typo - cv was ev. + (pthread_cond_broadcast): Fix two identical typos. + + * cleanup.c (ptw32_destructor_pop_all): Remove _ prefix from + PTHREAD_DESTRUCTOR_ITERATIONS. + + * pthread.h: Move _POSIX_* values into posix.h + + * pthread.h: Fix typo in pthread_mutex_init() prototype. + + * attr.c (pthread_attr_init): Fix error in priority member init. + + * windows.h (THREAD_PRIORITY_NORMAL): Add. + + * pthread.h (sched_param): Add missing ';' to struct definition. + + * attr.c (pthread_attr_init): Remove obsolete pthread_attr_t + member initialisation - cancelstate, canceltype, cancel_pending. + (is_attr): Make arg "attr" a const. + + * implement.h (PTW32_HANDLER_POP_LIFO): Remove definition. + (PTW32_HANDLER_POP_FIFO): Ditto. + (PTW32_VALID): Add missing newline escape (\). + (ptw32_handler_node): Make element "next" a pointer. + +1998-08-02 Ben Elliston + + * windows.h: Remove duplicate TlsSetValue() prototype. Add + TlsGetValue() prototype. + (FALSE): Define. + (TRUE): Likewise. + Add forgotten errno values. Guard against multiple #includes. + + * windows.c: New file. Implement stubs for Win32 functions. + + * Makefile (SRCS): Remove. Not explicitly needed. + (CFLAGS): Add -Wall for all warnings with GCC. + +Sun Aug 2 19:03:42 1998 Ross Johnson + + * config.h: Create. This is a temporary stand-in for autoconf yet + to be done. + (HAVE_SIGNAL_H): Add. + + * pthread.h: Minor rearrangement for temporary config.h. + +Fri Jul 31 14:00:29 1998 Ross Johnson + + * cleanup.c (ptw32_destructor_pop): Implement. Removes + destructors associated with a key without executing them. + (ptw32_destructor_pop_all): Add FIXME comment. + + * tsd.c (pthread_key_delete): Add call to ptw32_destructor_pop(). + +Fri Jul 31 00:05:45 1998 Ross Johnson + + * tsd.c (pthread_key_create): Update to properly associate + the destructor routine with the key. + (pthread_key_delete): Add FIXME comment. + + * exit.c (ptw32_vacuum): Add call to + ptw32_destructor_pop_all(). + + * implement.h (ptw32_handler_pop_all): Add prototype. + (ptw32_destructor_pop_all): Ditto. + + * cleanup.c (ptw32_destructor_push): Implement. This is just a + call to ptw32_handler_push(). + (ptw32_destructor_pop_all): Implement. This is significantly + different to ptw32_handler_pop_all(). + + * Makefile (SRCS): Create. Preliminary. + + * windows.h: Create. Contains Win32 definitions for compile + testing. This is just a standin for the real one. + + * pthread.h (SIG_UNBLOCK): Fix typo. Was SIG_BLOCK. + (windows.h): Add include. Required for CRITICAL_SECTION. + (pthread_cond_t): Move enum declaration outside of struct + definition. + (unistd.h): Add include - may be temporary. + + * condvar.c (windows.h): Add include. + + * implement.h (PTW32_THIS): Remove - no longer required. + (PTW32_STACK): Use pthread_self() instead of PTW32_THIS. + +Thu Jul 30 23:12:45 1998 Ross Johnson + + * implement.h: Remove ptw32_find_entry() prototype. + + * private.c: Extend comments. + Remove ptw32_find_entry() - no longer needed. + + * create.c (ptw32_start_call): Add call to TlsSetValue() to + store the thread ID. + + * dll.c (PthreadsEntryPoint): Implement. This is called + whenever a process loads the DLL. Used to initialise thread + local storage. + + * implement.h: Add ptw32_threadID_TlsIndex. + Add ()s around PTW32_VALID expression. + + * misc.c (pthread_self): Re-implement using Win32 TLS to store + the threads own ID. + +Wed Jul 29 11:39:03 1998 Ross Johnson + + * private.c: Corrections in comments. + (ptw32_new_thread): Alter "if" flow to be more natural. + + * cleanup.c (ptw32_handler_push): Same as below. + + * create.c (pthread_create): Same as below. + + * private.c (ptw32_new_thread): Rename "new" to "new_thread". + Since when has a C programmer been required to know C++? + +Tue Jul 28 14:04:29 1998 Ross Johnson + + * implement.h: Add PTW32_VALID macro. + + * sync.c (pthread_join): Modify to use the new thread + type and ptw32_delete_thread(). Rename "target" to "thread". + Remove extra local variable "target". + (pthread_detach): Ditto. + + * signal.c (pthread_sigmask): Move init of "us" out of inner block. + Fix instance of "this" should have been "us". Rename "us" to "thread". + + * sched.c (pthread_setschedparam): Modify to use the new thread + type. + (pthread_getschedparam): Ditto. + + * private.c (ptw32_find_thread): Fix return type and arg. + + * implement.h: Remove PTW32_YES and PTW32_NO. + (ptw32_new_thread): Add prototype. + (ptw32_find_thread): Ditto. + (ptw32_delete_thread): Ditto. + (ptw32_new_thread_entry): Remove prototype. + (ptw32_find_thread_entry): Ditto. + (ptw32_delete_thread_entry): Ditto. + ( PTW32_NEW, PTW32_INUSE, PTW32_EXITED, PTW32_REUSE): + Add. + + + * create.c (pthread_create): Minor rename "us" to "new" (I need + these cues but it doesn't stop me coming out with some major bugs + at times). + Load start_routine and arg into the thread so the wrapper can + call it. + + * exit.c (pthread_exit): Fix pthread_this should be pthread_self. + + * cancel.c (pthread_setcancelstate): Change + ptw32_threads_thread_t * to pthread_t and init with + pthread_this(). + (pthread_setcanceltype): Ditto. + + * exit.c (ptw32_exit): Add new pthread_t arg. + Rename ptw32_delete_thread_entry to ptw32_delete_thread. + Rename "us" to "thread". + (pthread_exit): Call ptw32_exit with added thread arg. + + * create.c (ptw32_start_call): Insert missing ")". + Add "us" arg to ptw32_exit() call. + (pthread_create): Modify to use new thread allocation scheme. + + * private.c: Added detailed explanation of the new thread + allocation scheme. + (ptw32_new_thread): Totally rewritten to use + new thread allocation scheme. + (ptw32_delete_thread): Ditto. + (ptw32_find_thread): Obsolete. + +Mon Jul 27 17:46:37 1998 Ross Johnson + + * create.c (pthread_create): Start of rewrite. Not completed yet. + + * private.c (ptw32_new_thread_entry): Start of rewrite. Not + complete. + + * implement.h (ptw32_threads_thread): Rename, remove thread + member, add win32handle and ptstatus members. + (ptw32_t): Add. + + * pthread.h: pthread_t is no longer mapped directly to a Win32 + HANDLE type. This is so we can let the Win32 thread terminate and + reuse the HANDLE while pthreads holds it's own thread ID until + the last waiting join exits. + +Mon Jul 27 00:20:37 1998 Ross Johnson + + * private.c (ptw32_delete_thread_entry): Destroy the thread + entry attribute object before deleting the thread entry itself. + + * attr.c (pthread_attr_init): Initialise cancel_pending = FALSE. + (pthread_attr_setdetachstate): Rename "detached" to "detachedstate". + (pthread_attr_getdetachstate): Ditto. + + * exit.c (ptw32_exit): Fix incorrect check for detachedstate. + + * implement.h (ptw32_call_t): Remove env member. + +Sun Jul 26 13:06:12 1998 Ross Johnson + + * implement.h (ptw32_new_thread_entry): Fix prototype. + (ptw32_find_thread_entry): Ditto. + (ptw32_delete_thread_entry): Ditto. + (ptw32_exit): Add prototype. + + * exit.c (ptw32_exit): New function. Called from pthread_exit() + and ptw32_start_call() to exit the thread. It allows an extra + argument which is the return code passed to _endthreadex(). + (ptw32_exit): Move thread entry delete call from ptw32_vacuum() + into here. Add more explanation of thread entry deletion. + (ptw32_exit): Clarify comment. + + * create.c (ptw32_start_call): Change pthread_exit() call to + ptw32_exit() call. + + * exit.c (ptw32_vacuum): Add thread entry deletion code + moved from ptw32_start_call(). See next item. + (pthread_exit): Remove longjmp(). Add mutex lock around thread table + manipulation code. This routine now calls _enthreadex(). + + * create.c (ptw32_start_call): Remove setjmp() call and move + cleanup code out. Call pthread_exit(NULL) to terminate the thread. + +1998-07-26 Ben Elliston + + * tsd.c (pthread_getspecific): Update comments. + + * mutex.c (pthread_mutexattr_setpshared): Not supported; remove. + (pthread_mutexattr_getpshared): Likewise. + + * pthread.h (pthread_mutexattr_setpshared): Remove prototype. + (pthread_mutexattr_getpshared): Likewise. + +Sun Jul 26 00:09:59 1998 Ross Johnson + + * sync.c: Rename all instances of ptw32_count_mutex to + ptw32_table_mutex. + + * implement.h: Rename ptw32_count_mutex to + ptw32_table_mutex. + + * global.c: Rename ptw32_count_mutex to + ptw32_table_mutex. + + * create.c (pthread_create): Add critical sections. + (ptw32_start_call): Rename ptw32_count_mutex to + ptw32_table_mutex. + + * cancel.c (pthread_setcancelstate): Fix indirection bug and rename + "this" to "us". + + * signal.c (pthread_sigmask): Rename "this" to "us" and fix some + minor syntax errors. Declare "us" and initialise it. + + * sync.c (pthread_detach): Rename "this" to "target". + + * pthread.h: Converting PTHREAD_* defines to alias the (const int) + values in global.c. + + * global.c: Started converting PTHREAD_* defines to (const int) as + a part of making the eventual pthreads DLL binary compatible + through version changes. + + * condvar.c (cond_wait): Add cancelation point. This applies the + point to both pthread_cond_wait() and pthread_cond_timedwait(). + + * exit.c (pthread_exit): Rename "this" to "us". + + * implement.h: Add comment. + + * sync.c (pthread_join): I've satisfied myself that pthread_detach() + does set the detached attribute in the thread entry attributes + to PTHREAD_CREATE_DETACHED. "if" conditions were changed to test + that attribute instead of a separate flag. + + * create.c (pthread_create): Rename "this" to "us". + (pthread_create): cancelstate and canceltype are not attributes + so the copy to thread entry attribute storage was removed. + Only the thread itself can change it's cancelstate or canceltype, + ie. the thread must exist already. + + * private.c (ptw32_delete_thread_entry): Mutex locks removed. + Mutexes must be applied at the caller level. + (ptw32_new_thread_entry): Ditto. + (ptw32_new_thread_entry): Init cancelstate, canceltype, and + cancel_pending to default values. + (ptw32_new_thread_entry): Rename "this" to "new". + (ptw32_find_thread_entry): Rename "this" to "entry". + (ptw32_delete_thread_entry): Rename "thread_entry" to "entry". + + * create.c (ptw32_start_call): Mutexes changed to + ptw32_count_mutex. All access to the threads table entries is + under the one mutex. Otherwise chaos reigns. + +Sat Jul 25 23:16:51 1998 Ross Johnson + + * implement.h (ptw32_threads_thread): Move cancelstate and + canceltype members out of pthread_attr_t into here. + + * fork.c (fork): Add comment. + +1998-07-25 Ben Elliston + + * fork.c (fork): Autoconfiscate. + +Sat Jul 25 00:00:13 1998 Ross Johnson + + * create.c (ptw32_start_call): Set thread priority. Ensure our + thread entry is removed from the thread table but only if + pthread_detach() was called and there are no waiting joins. + (pthread_create): Set detach flag in thread entry if the + thread is created PTHREAD_CREATE_DETACHED. + + * pthread.h (pthread_attr_t): Rename member "detachedstate". + + * attr.c (pthread_attr_init): Rename attr members. + + * exit.c (pthread_exit): Fix indirection mistake. + + * implement.h (PTW32_THREADS_TABLE_INDEX): Add. + + * exit.c (ptw32_vacuum): Fix incorrect args to + ptw32_handler_pop_all() calls. + Make thread entry removal conditional. + + * sync.c (pthread_join): Add multiple join and async detach handling. + + * implement.h (PTW32_THREADS_TABLE_INDEX): Add. + + * global.c (ptw32_threads_mutex_table): Add. + + * implement.h (ptw32_once_flag): Remove. + (ptw32_once_lock): Ditto. + (ptw32_threads_mutex_table): Add. + + * global.c (ptw32_once_flag): Remove. + (ptw32_once_lock): Ditto. + + * sync.c (pthread_join): Fix tests involving new return value + from ptw32_find_thread_entry(). + (pthread_detach): Ditto. + + * private.c (ptw32_find_thread_entry): Failure return code + changed from -1 to NULL. + +Fri Jul 24 23:09:33 1998 Ross Johnson + + * create.c (pthread_create): Change . to -> in sigmask memcpy() args. + + * pthread.h: (pthread_cancel): Add function prototype. + (pthread_testcancel): Ditto. + +1998-07-24 Ben Elliston + + * pthread.h (pthread_condattr_t): Rename dummy structure member. + (pthread_mutexattr_t): Likewise. + +Fri Jul 24 21:13:55 1998 Ross Johnson + + * cancel.c (pthread_cancel): Implement. + (pthread_testcancel): Implement. + + * exit.c (pthread_exit): Add comment explaining the longjmp(). + + * implement.h (ptw32_threads_thread_t): New member cancelthread. + (PTW32_YES): Define. + (PTW32_NO): Define. + (RND_SIZEOF): Remove. + + * create.c (pthread_create): Rename cancelability to cancelstate. + + * pthread.h (pthread_attr_t): Rename cancelability to cancelstate. + (PTHREAD_CANCELED): Define. + +1998-07-24 Ben Elliston + + * pthread.h (SIG_BLOCK): Define if not already defined. + (SIG_UNBLOCK): Likewise. + (SIG_SETMASK): Likewise. + (pthread_attr_t): Add signal mask member. + (pthread_sigmask): Add function prototype. + + * signal.c (pthread_sigmask): Implement. + + * create.c: #include to get a prototype for memcpy(). + (pthread_create): New threads inherit their creator's signal + mask. Copy the signal mask to the new thread structure if we know + about signals. + +Fri Jul 24 16:33:17 1998 Ross Johnson + + * fork.c (pthread_atfork): Add all the necessary push calls. + Local implementation semantics: + If we get an ENOMEM at any time then ALL handlers + (including those from previous pthread_atfork() calls) will be + popped off each of the three atfork stacks before we return. + (fork): Add all the necessary pop calls. Add the thread cancellation + and join calls to the child fork. + Add #includes. + + * implement.h: (ptw32_handler_push): Fix return type and stack arg + type in prototype. + (ptw32_handler_pop): Fix stack arg type in prototype. + (ptw32_handler_pop_all): Fix stack arg type in prototype. + + * cleanup.c (ptw32_handler_push): Change return type to int and + return ENOMEM if malloc() fails. + + * sync.c (pthread_detach): Use equality test, not assignment. + + * create.c (ptw32_start_call): Add call to Win32 CloseHandle() + if thread is detached. + +1998-07-24 Ben Elliston + + * sync.c (pthread_detach): Close the Win32 thread handle to + emulate detached (or daemon) threads. + +Fri Jul 24 03:00:25 1998 Ross Johnson + + * sync.c (pthread_join): Save valueptr arg in joinvalueptr for + pthread_exit() to use. + + * private.c (ptw32_new_thread_entry): Initialise joinvalueptr to + NULL. + + * create.c (ptw32_start_call): Rewrite to facilitate joins. + pthread_exit() will do a longjmp() back to here. Does appropriate + cleanup and exit/return from the thread. + (pthread_create): _beginthreadex() now passes a pointer to our + thread table entry instead of just the call member of that entry. + + * implement.h (ptw32_threads_thread): New member + void ** joinvalueptr. + (ptw32_call_t): New member jmpbuf env. + + * exit.c (pthread_exit): Major rewrite to handle joins and handing + value pointer to joining thread. Uses longjmp() back to + ptw32_start_call(). + + * create.c (pthread_create): Ensure values of new attribute members + are copied to the thread attribute object. + + * attr.c (pthread_attr_destroy): Fix merge conflicts. + (pthread_attr_getdetachstate): Fix merge conflicts. + (pthread_attr_setdetachstate): Fix merge conflicts. + + * pthread.h: Fix merge conflicts. + + * sync.c (pthread_join): Fix merge conflicts. + +Fri Jul 24 00:21:21 1998 Ross Johnson + + * sync.c (pthread_join): Add check for valid and joinable + thread. + (pthread_detach): Implement. After checking for a valid and joinable + thread, it's still a no-op. + + * private.c (ptw32_find_thread_entry): Bug prevented returning + an error value in some cases. + + * attr.c (pthread_attr_setdetachedstate): Implement. + (pthread_attr_getdetachedstate): Implement. + + * implement.h: Move more hidden definitions into here from + pthread.h. + +1998-07-24 Ben Elliston + + * pthread.h (PTHREAD_CREATE_JOINABLE): Define. + (PTHREAD_CREATE_DETACHED): Likewise. + (pthread_attr_t): Add new structure member `detached'. + (pthread_attr_getdetachstate): Add function prototype. + (pthread_attr_setdetachstate): Likewise. + + * sync.c (pthread_join): Return if the target thread is detached. + + * attr.c (pthread_attr_init): Initialise cancelability and + canceltype structure members. + (pthread_attr_getdetachstate): Implement. + (pthread_attr_setdetachstate): Likewise. + + * implement.h (PTW32_CANCEL_DEFAULTS): Remove. Bit fields + proved to be too cumbersome. Set the defaults in attr.c using the + public PTHREAD_CANCEL_* constants. + + * cancel.c: New file. + + * pthread.h (sched_param): Define this type. + (pthread_attr_getschedparam): Add function prototype. + (pthread_attr_setschedparam): Likewise. + (pthread_setcancelstate): Likewise. + (pthread_setcanceltype): Likewise. + (sched_get_priority_min): Likewise. + (sched_get_priority_max): Likewise. + (pthread_mutexattr_setprotocol): Remove; not supported. + (pthread_mutexattr_getprotocol): Likewise. + (pthread_mutexattr_setprioceiling): Likewise. + (pthread_mutexattr_getprioceiling): Likewise. + (pthread_attr_t): Add canceltype member. Update comments. + (SCHED_OTHER): Define this scheduling policy constant. + (SCHED_FIFO): Likewise. + (SCHED_RR): Likewise. + (SCHED_MIN): Define the lowest possible value for this constant. + (SCHED_MAX): Likewise, the maximum possible value. + (PTHREAD_CANCEL_ASYNCHRONOUS): Redefine. + (PTHREAD_CANCEL_DEFERRED): Likewise. + + * sched.c: New file. + (pthread_setschedparam): Implement. + (pthread_getschedparam): Implement. + (sched_get_priority_max): Validate policy argument. + (sched_get_priority_min): Likewise. + + * mutex.c (pthread_mutexattr_setprotocol): Remove; not supported. + (pthread_mutexattr_getprotocol): Likewise. + (pthread_mutexattr_setprioceiling): Likewise. + (pthread_mutexattr_getprioceiling): Likewise. + +Fri Jul 24 00:21:21 1998 Ross Johnson + + * create.c (pthread_create): Arg to ptw32_new_thread_entry() + changed. See next entry. Move mutex locks out. Changes made yesterday + and today allow us to start the new thread running rather than + temporarily suspended. + + * private.c (ptw32_new_thread_entry): ptw32_thread_table + was changed back to a table of thread structures rather than pointers. + As such we're trading storage for increaded speed. This routine + was modified to work with the new table. Mutex lock put in around + global data accesses. + (ptw32_find_thread_entry): Ditto + (ptw32_delete_thread_entry): Ditto + +Thu Jul 23 23:25:30 1998 Ross Johnson + + * global.c: New. Global data objects declared here. These moved from + pthread.h. + + * pthread.h: Move implementation hidden definitions into + implement.h. + + * implement.h: Move implementation hidden definitions from + pthread.h. Add constants to index into the different handler stacks. + + * cleanup.c (ptw32_handler_push): Simplify args. Restructure. + (ptw32_handler_pop): Simplify args. Restructure. + (ptw32_handler_pop_all): Simplify args. Restructure. + +Wed Jul 22 00:16:22 1998 Ross Johnson + + * attr.c, implement.h, pthread.h, ChangeLog: Resolve CVS merge + conflicts. + + * private.c (ptw32_find_thread_entry): Changes to return type + to support leaner ptw32_threads_table[] which now only stores + ptw32_thread_thread_t *. + (ptw32_new_thread_entry): Internal changes. + (ptw32_delete_thread_entry): Internal changes to avoid contention. + Calling routines changed accordingly. + + * pthread.h: Modified cleanup macros to use new generic push and pop. + Added destructor and atfork stacks to ptw32_threads_thread_t. + + * cleanup.c (ptw32_handler_push, ptw32_handler_pop, + ptw32_handler_pop_all): Renamed cleanup push and pop routines + and made generic to handle destructors and atfork handlers as + well. + + * create.c (ptw32_start_call): New function is a wrapper for + all new threads. It allows us to do some cleanup when the thread + returns, ie. that is otherwise only done if the thread is cancelled. + + * exit.c (ptw32_vacuum): New function contains code from + pthread_exit() that we need in the new ptw32_start_call() + as well. + + * implement.h: Various additions and minor changes. + + * pthread.h: Various additions and minor changes. + Change cleanup handler macros to use generic handler push and pop + functions. + + * attr.c: Minor mods to all functions. + (is_attr): Implemented missing function. + + * create.c (pthread_create): More clean up. + + * private.c (ptw32_find_thread_entry): Implement. + (ptw32_delete_thread_entry): Implement. + (ptw32_new_thread_entry): Implement. + These functions manipulate the implementations internal thread + table and are part of general code cleanup and modularisation. + They replace ptw32_getthreadindex() which was removed. + + * exit.c (pthread_exit): Changed to use the new code above. + + * pthread.h: Add cancelability constants. Update comments. + +1998-07-22 Ben Elliston + + * attr.c (pthread_setstacksize): Update test of attr argument. + (pthread_getstacksize): Likewise. + (pthread_setstackaddr): Likewise. + (pthread_getstackaddr): Likewise. + (pthread_attr_init): No need to allocate any storage. + (pthread_attr_destroy): No need to free any storage. + + * mutex.c (is_attr): Not likely to be needed; remove. + (remove_attr): Likewise. + (insert_attr): Likewise. + + * implement.h (ptw32_mutexattr_t): Moved to a public definition + in pthread.h. There was little gain in hiding these details. + (ptw32_condattr_t): Likewise. + (ptw32_attr_t): Likewise. + + * pthread.h (pthread_atfork): Add function prototype. + (pthread_attr_t): Moved here from implement.h. + + * fork.c (pthread_atfork): Preliminary implementation. + (ptw32_fork): Likewise. + +Wed Jul 22 00:16:22 1998 Ross Johnson + + * cleanup.c (ptw32_cleanup_push): Implement. + (ptw32_cleanup_pop): Implement. + (ptw32_do_cancellation): Implement. + These are private to the implementation. The real cleanup functions + are macros. See below. + + * pthread.h (pthread_cleanup_push): Implement as a macro. + (pthread_cleanup_pop): Implement as a macro. + Because these are macros which start and end a block, the POSIX scoping + requirement is observed. See the comment in the file. + + * exit.c (pthread_exit): Refine the code. + + * create.c (pthread_create): Code cleanup. + + * implement.h (RND_SIZEOF): Add RND_SIZEOF(T) to round sizeof(T) + up to multiple of DWORD. + Add function prototypes. + + * private.c (ptw32_getthreadindex): "*thread" should have been + "thread". Detect empty slot fail condition. + +1998-07-20 Ben Elliston + + * misc.c (pthread_once): Implement. Don't use a per-application + flag and mutex--make `pthread_once_t' contain these elements in + their structure. The earlier version had incorrect semantics. + + * pthread.h (ptw32_once_flag): Add new variable. Remove. + (ptw32_once_lock): Add new mutex lock to ensure integrity of + access to ptw32_once_flag. Remove. + (pthread_once): Add function prototype. + (pthread_once_t): Define this type. + +Mon Jul 20 02:31:05 1998 Ross Johnson + + * private.c (ptw32_getthreadindex): Implement. + + * pthread.h: Add application static data dependent on + _PTHREADS_BUILD_DLL define. This is needed to avoid allocating + non-sharable static data within the pthread DLL. + + * implement.h: Add ptw32_cleanup_stack_t, ptw32_cleanup_node_t + and PTW32_HASH_INDEX. + + * exit.c (pthread_exit): Begin work on cleanup and de-allocate + thread-private storage. + + * create.c (pthread_create): Add thread to thread table. + Keep a thread-private copy of the attributes with default values + filled in when necessary. Same for the cleanup stack. Make + pthread_create C run-time library friendly by using _beginthreadex() + instead of CreateThread(). Fix error returns. + +Sun Jul 19 16:26:23 1998 Ross Johnson + + * implement.h: Rename pthreads_thread_count to ptw32_threads_count. + Create ptw32_threads_thread_t struct to keep thread specific data. + + * create.c: Rename pthreads_thread_count to ptw32_threads_count. + (pthread_create): Handle errors from CreateThread(). + +1998-07-19 Ben Elliston + + * condvar.c (pthread_cond_wait): Generalise. Moved from here .. + (cond_wait): To here. + (pthread_cond_timedwait): Implement; use generalised cond_wait(). + + * pthread.h (pthread_key_t): Define this type. + (pthread_key_create): Add function prototype. + (pthread_setspecific): Likewise. + (pthread_getspecific): Likwise. + (pthread_key_delete): Likewise. + + * tsd.c (pthread_key_create): Implement. + (pthread_setspecific): Likewise. + (pthread_getspecific): Likewise. + (pthread_key_delete): Likewise. + + * mutex.c (pthread_mutex_trylock): Return ENOSYS if this function + is called on a Win32 platform which is not Windows NT. + +1998-07-18 Ben Elliston + + * condvar.c (pthread_condattr_init): Do not attempt to malloc any + storage; none is needed now that condattr_t is an empty struct. + (pthread_condattr_destory): Likewise; do not free storage. + (pthread_condattr_setpshared): No longer supported; return ENOSYS. + (pthread_condattr_getpshared): Likewise. + (pthread_cond_init): Implement with help from Douglas Schmidt. + Remember to initialise the cv's internal mutex. + (pthread_cond_wait): Likewise. + (pthread_cond_signal): Likewise. + (pthread_cond_broadcast): Likewise. + (pthread_cond_timedwait): Preliminary implementation, but I need + to see some API documentation for `WaitForMultipleObject'. + (pthread_destory): Implement. + + * pthread.h (pthread_cond_init): Add function protoype. + (pthread_cond_broadcast): Likewise. + (pthread_cond_signal): Likewise. + (pthread_cond_timedwait): Likewise. + (pthread_cond_wait): Likewise. + (pthread_cond_destroy): Likewise. + (pthread_cond_t): Define this type. Fix for u_int. Do not assume + that the mutex contained withing the pthread_cond_t structure will + be a critical section. Use our new POSIX type! + + * implement.h (ptw32_condattr_t): Remove shared attribute. + +1998-07-17 Ben Elliston + + * pthread.h (PTHREADS_PROCESS_PRIVATE): Remove. + (PTHREAD_PROCESS_SHARED): Likewise. No support for mutexes shared + across processes for now. + (pthread_mutex_t): Use a Win32 CRITICAL_SECTION type for better + performance. + + * implement.h (ptw32_mutexattr_t): Remove shared attribute. + + * mutex.c (pthread_mutexattr_setpshared): This optional function + is no longer supported, since we want to implement POSIX mutex + variables using the much more efficient Win32 critical section + primitives. Critical section objects in Win32 cannot be shared + between processes. + (pthread_mutexattr_getpshared): Likewise. + (pthread_mutexattr_init): No need to malloc any storage; the + attributes structure is now empty. + (pthread_mutexattr_destroy): This is now a nop. + (pthread_mutex_init): Use InitializeCriticalSection(). + (pthread_mutex_destroy): Use DeleteCriticalSection(). + (pthread_mutex_lock): Use EnterCriticalSection(). + (pthread_mutex_trylock): Use TryEnterCriticalSection(). This is + not supported by Windows 9x, but trylock is a hack anyway, IMHO. + (pthread_mutex_unlock): Use LeaveCriticalSection(). + +1998-07-14 Ben Elliston + + * attr.c (pthread_attr_setstacksize): Implement. + (pthread_attr_getstacksize): Likewise. + (pthread_attr_setstackaddr): Likewise. + (pthread_attr_getstackaddr): Likewise. + (pthread_attr_init): Likewise. + (pthread_attr_destroy): Likewise. + + * condvar.c (pthread_condattr_init): Add `_cond' to function name. + + * mutex.c (pthread_mutex_lock): Add `_mutex' to function name. + (pthread_mutex_trylock): Likewise. + (pthread_mutex_unlock): Likewise. + + * pthread.h (pthread_condattr_setpshared): Fix typo. + (pthread_attr_init): Add function prototype. + (pthread_attr_destroy): Likewise. + (pthread_attr_setstacksize): Likewise. + (pthread_attr_getstacksize): Likewise. + (pthread_attr_setstackaddr): Likewise. + (pthread_attr_getstackaddr): Likewise. + +Mon Jul 13 01:09:55 1998 Ross Johnson + + * implement.h: Wrap in #ifndef _IMPLEMENT_H + + * create.c (pthread_create): Map stacksize attr to Win32. + + * mutex.c: Include implement.h + +1998-07-13 Ben Elliston + + * condvar.c (pthread_condattr_init): Implement. + (pthread_condattr_destroy): Likewise. + (pthread_condattr_setpshared): Likewise. + (pthread_condattr_getpshared): Likewise. + + * implement.h (PTHREAD_THREADS_MAX): Remove trailing semicolon. + (PTHREAD_STACK_MIN): Specify; needs confirming. + (ptw32_attr_t): Define this type. + (ptw32_condattr_t): Likewise. + + * pthread.h (pthread_mutex_t): Define this type. + (pthread_condattr_t): Likewise. + (pthread_mutex_destroy): Add function prototype. + (pthread_lock): Likewise. + (pthread_trylock): Likewise. + (pthread_unlock): Likewise. + (pthread_condattr_init): Likewise. + (pthread_condattr_destroy): Likewise. + (pthread_condattr_setpshared): Likewise. + (pthread_condattr_getpshared): Likewise. + + * mutex.c (pthread_mutex_init): Implement. + (pthread_mutex_destroy): Likewise. + (pthread_lock): Likewise. + (pthread_trylock): Likewise. + (pthread_unlock): Likewise. + +1998-07-12 Ben Elliston + + * implement.h (ptw32_mutexattr_t): Define this implementation + internal type. Application programmers only see a mutex attribute + object as a void pointer. + + * pthread.h (pthread_mutexattr_t): Define this type. + (pthread_mutexattr_init): Add function prototype. + (pthread_mutexattr_destroy): Likewise. + (pthread_mutexattr_setpshared): Likewise. + (pthread_mutexattr_getpshared): Likewise. + (pthread_mutexattr_setprotocol): Likewise. + (pthread_mutexattr_getprotocol): Likewise. + (pthread_mutexattr_setprioceiling): Likewise. + (pthread_mutexattr_getprioceiling): Likewise. + (PTHREAD_PROCESS_PRIVATE): Define. + (PTHREAD_PROCESS_SHARED): Define. + + * mutex.c (pthread_mutexattr_init): Implement. + (pthread_mutexattr_destroy): Implement. + (pthread_mutexattr_setprotocol): Implement. + (pthread_mutexattr_getprotocol): Likewise. + (pthread_mutexattr_setprioceiling): Likewise. + (pthread_mutexattr_getprioceiling): Likewise. + (pthread_mutexattr_setpshared): Likewise. + (pthread_mutexattr_getpshared): Likewise. + (insert_attr): New function; very preliminary implementation! + (is_attr): Likewise. + (remove_attr): Likewise. + +Sat Jul 11 14:48:54 1998 Ross Johnson + + * implement.h: Preliminary implementation specific defines. + + * create.c (pthread_create): Preliminary implementation. + +1998-07-11 Ben Elliston + + * sync.c (pthread_join): Implement. + + * misc.c (pthread_equal): Likewise. + + * pthread.h (pthread_join): Add function prototype. + (pthread_equal): Likewise. + +1998-07-10 Ben Elliston + + * misc.c (pthread_self): Implement. + + * exit.c (pthread_exit): Implement. + + * pthread.h (pthread_exit): Add function prototype. + (pthread_self): Likewise. + (pthread_t): Define this type. + +1998-07-09 Ben Elliston + + * create.c (pthread_create): A dummy stub right now. + + * pthread.h (pthread_create): Add function prototype. diff --git a/libs/pthreads/docs/FAQ b/libs/pthreads/docs/FAQ new file mode 100644 index 0000000000..cb1786c5ae --- /dev/null +++ b/libs/pthreads/docs/FAQ @@ -0,0 +1,451 @@ + ========================================= + PTHREADS-WIN32 Frequently Asked Questions + ========================================= + +INDEX +----- + +Q 1 What is it? + +Q 2 Which of the several dll versions do I use? + or, + What are all these pthread*.dll and pthread*.lib files? + +Q 3 What is the library naming convention? + +Q 4 Cleanup code default style or: it used to work when I built + the library myself, but now it doesn't - why? + +Q 5 Why is the default library version now less exception-friendly? + +Q 6 Should I use Cygwin or Mingw32 as a development environment? + +Q 7 Now that pthreads-win32 builds under Mingw32, why do I get + memory access violations (segfaults)? + +Q 8 How do I use pthread.dll for Win32 (Visual C++ 5.0) + +Q 9 Cancelation doesn't work for me, why? + +Q 10 How do I generate pthreadGCE.dll and libpthreadw32.a for use + with Mingw32? + +Q 11 Why isn't pthread_t defined as a scalar (e.g. pointer or int) + like it is for other POSIX threads implementations? + +============================================================================= + +Q 1 What is it? +--- + +Pthreads-win32 is an Open Source Software implementation of the +Threads component of the POSIX 1003.1c 1995 Standard for Microsoft's +Win32 environment. Some functions from POSIX 1003.1b are also +supported including semaphores. Other related functions include +the set of read-write lock functions. The library also supports +some of the functionality of the Open Group's Single Unix +specification, version 2, namely mutex types. + +See the file "ANNOUNCE" for more information including standards +conformance details and list of supported routines. + + +------------------------------------------------------------------------------ + +Q 2 Which of the several dll versions do I use? +--- or, + What are all these pthread*.dll and pthread*.lib files? + +Simply, you only use one of them, but you need to choose carefully. + +The most important choice you need to make is whether to use a +version that uses exceptions internally, or not (there are versions +of the library that use exceptions as part of the thread +cancelation and cleanup implementation, and one that uses +setjmp/longjmp instead). + +There is some contension amongst POSIX threads experts as +to how POSIX threads cancelation and exit should work +with languages that include exceptions and handlers, e.g. +C++ and even C (Microsoft's Structured Exceptions). + +The issue is: should cancelation of a thread in, say, +a C++ application cause object destructors and C++ exception +handlers to be invoked as the stack unwinds during thread +exit, or not? + +There seems to be more opinion in favour of using the +standard C version of the library (no EH) with C++ applications +since this appears to be the assumption commercial pthreads +implementations make. Therefore, if you use an EH version +of pthreads-win32 then you may be under the illusion that +your application will be portable, when in fact it is likely to +behave very differently linked with other pthreads libraries. + +Now you may be asking: why have you kept the EH versions of +the library? + +There are a couple of reasons: +- there is division amongst the experts and so the code may + be needed in the future. (Yes, it's in the repository and we + can get it out anytime in the future, but ...) +- pthreads-win32 is one of the few implementations, and possibly + the only freely available one, that has EH versions. It may be + useful to people who want to play with or study application + behaviour under these conditions. + + +------------------------------------------------------------------------------ + +Q 3 What is the library naming convention? +--- + +Because the library is being built using various exception +handling schemes and compilers - and because the library +may not work reliably if these are mixed in an application, +each different version of the library has it's own name. + +Note 1: the incompatibility is really between EH implementations +of the different compilers. It should be possible to use the +standard C version from either compiler with C++ applications +built with a different compiler. If you use an EH version of +the library, then you must use the same compiler for the +application. This is another complication and dependency that +can be avoided by using only the standard C library version. + +Note 2: if you use a standard C pthread*.dll with a C++ +application, then any functions that you define that are +intended to be called via pthread_cleanup_push() must be +__cdecl. + +Note 3: the intention is to also name either the VC or GC +version (it should be arbitrary) as pthread.dll, including +pthread.lib and libpthread.a as appropriate. + +In general: + pthread[VG]{SE,CE,C}.dll + pthread[VG]{SE,CE,C}.lib + +where: + [VG] indicates the compiler + V - MS VC + G - GNU C + + {SE,CE,C} indicates the exception handling scheme + SE - Structured EH + CE - C++ EH + C - no exceptions - uses setjmp/longjmp + +For example: + pthreadVSE.dll (MSVC/SEH) + pthreadGCE.dll (GNUC/C++ EH) + pthreadGC.dll (GNUC/not dependent on exceptions) + +The GNU library archive file names have changed to: + + libpthreadGCE.a + libpthreadGC.a + + +------------------------------------------------------------------------------ + +Q 4 Cleanup code default style or: it used to work when I built +--- the library myself, but now it doesn't - why? + +Up to and including snapshot 2001-07-12, if not defined, the cleanup +style was determined automatically from the compiler used, and one +of the following was defined accordingly: + + __CLEANUP_SEH MSVC only + __CLEANUP_CXX C++, including MSVC++, GNU G++ + __CLEANUP_C C, including GNU GCC, not MSVC + +These defines determine the style of cleanup (see pthread.h) and, +most importantly, the way that cancelation and thread exit (via +pthread_exit) is performed (see the routine ptw32_throw() in private.c). + +In short, the exceptions versions of the library throw an exception +when a thread is canceled or exits (via pthread_exit()), which is +caught by a handler in the thread startup routine, so that the +the correct stack unwinding occurs regardless of where the thread +is when it's canceled or exits via pthread_exit(). + +After snapshot 2001-07-12, unless your build explicitly defines (e.g. +via a compiler option) __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then +the build now ALWAYS defaults to __CLEANUP_C style cleanup. This style +uses setjmp/longjmp in the cancelation and pthread_exit implementations, +and therefore won't do stack unwinding even when linked to applications +that have it (e.g. C++ apps). This is for consistency with most/all +commercial Unix POSIX threads implementations. + +Although it was not clearly documented before, it is still necessary to +build your application using the same __CLEANUP_* define as was +used for the version of the library that you link with, so that the +correct parts of pthread.h are included. That is, the possible +defines require the following library versions: + + __CLEANUP_SEH pthreadVSE.dll + __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll + __CLEANUP_C pthreadVC.dll or pthreadGC.dll + +THE POINT OF ALL THIS IS: if you have not been defining one of these +explicitly, then the defaults have been set according to the compiler +and language you are using, as described at the top of this +section. + +THIS NOW CHANGES, as has been explained above. For example: + +If you were building your application with MSVC++ i.e. using C++ +exceptions (rather than SEH) and not explicitly defining one of +__CLEANUP_*, then __CLEANUP_C++ was defined for you in pthread.h. +You should have been linking with pthreadVCE.dll, which does +stack unwinding. + +If you now build your application as you had before, pthread.h will now +set __CLEANUP_C as the default style, and you will need to link +with pthreadVC.dll. Stack unwinding will now NOT occur when a +thread is canceled, nor when the thread calls pthread_exit(). + +Your application will now most likely behave differently to previous +versions, and in non-obvious ways. Most likely is that local +objects may not be destroyed or cleaned up after a thread +is canceled. + +If you want the same behaviour as before, then you must now define +__CLEANUP_C++ explicitly using a compiler option and link with +pthreadVCE.dll as you did before. + + +------------------------------------------------------------------------------ + +Q 5 Why is the default library version now less exception-friendly? +--- + +Because most commercial Unix POSIX threads implementations don't allow you to +choose to have stack unwinding. (Compaq's TRU64 Unix is possibly an exception.) + +Therefore, providing it in pthread-win32 as a default could be dangerous +and non-portable. We still provide the choice but you must now consciously +make it. + +WHY NOT REMOVE THE EXCEPTIONS VERSIONS OF THE LIBRARY ALTOGETHER? +There are a few reasons: +- because there are well respected POSIX threads people who believe + that POSIX threads implementations should be exceptions-aware and + do the expected thing in that context. (There are equally respected + people who believe it should not be easily accessible, if it's there + at all.) +- because pthreads-win32 is one of the few implementations that has + the choice, perhaps the only freely available one, and so offers + a laboratory to people who may want to explore the effects; +- although the code will always be around somewhere for anyone who + wants it, once it's removed from the current version it will not be + nearly as visible to people who may have a use for it. + + +------------------------------------------------------------------------------ + +Q 6 Should I use Cygwin or Mingw32 as a development environment? +--- + +Important: see Q7 also. + +Use Mingw32 with the MSVCRT library to build applications that use +the pthreads DLL. + +Cygwin's own internal support for POSIX threads is growing. +Consult that project's documentation for more information. + +------------------------------------------------------------------------------ + +Q 7 Now that pthreads-win32 builds under Mingw32, why do I get +--- memory access violations (segfaults)? + +The latest Mingw32 package has thread-safe exception handling (see Q10). +Also, see Q6 above. + +------------------------------------------------------------------------------ + +Q 8 How do I use pthread.dll for Win32 (Visual C++ 5.0) +--- + +> +> I'm a "rookie" when it comes to your pthread implementation. I'm currently +> desperately trying to install the prebuilt .dll file into my MSVC compiler. +> Could you please provide me with explicit instructions on how to do this (or +> direct me to a resource(s) where I can acquire such information)? +> +> Thank you, +> + +You should have a .dll, .lib, .def, and three .h files. It is recommended +that you use pthreadVC.dll, rather than pthreadVCE.dll or pthreadVSE.dll +(see Q2 above). + +The .dll can go in any directory listed in your PATH environment +variable, so putting it into C:\WINDOWS should work. + +The .lib file can go in any directory listed in your LIB environment +variable. + +The .h files can go in any directory listed in your INCLUDE +environment variable. + +Or you might prefer to put the .lib and .h files into a new directory +and add its path to LIB and INCLUDE. You can probably do this easiest +by editing the file:- + +C:\Program Files\DevStudio\vc\bin\vcvars32.bat + +The .def file isn't used by anything in the pre-compiled version but +is included for information. + +Cheers. +Ross + +------------------------------------------------------------------------------ + +Q 9 Cancelation doesn't work for me, why? +--- + +> I'm investigating a problem regarding thread cancelation. The thread I want +> to cancel has PTHREAD_CANCEL_ASYNCHRONOUS, however, this piece of code +> blocks on the join(): +> +> if ((retv = Pthread_cancel( recvThread )) == 0) +> { +> retv = Pthread_join( recvThread, 0 ); +> } +> +> Pthread_* are just macro's; they call pthread_*. +> +> The thread recvThread seems to block on a select() call. It doesn't get +> cancelled. +> +> Two questions: +> +> 1) is this normal behaviour? +> +> 2) if not, how does the cancel mechanism work? I'm not very familliar to +> win32 programming, so I don't really understand how the *Event() family of +> calls work. + +The answer to your first question is, normal POSIX behaviour would +be to asynchronously cancel the thread. However, even that doesn't +guarantee cancelation as the standard only says it should be +cancelled as soon as possible. + +Snapshot 99-11-02 or earlier only partially supports asynchronous cancellation. +Snapshots since then simulate async cancelation by poking the address of +a cancelation routine into the PC of the threads context. This requires +the thread to be resumed in some way for the cancelation to actually +proceed. This is not true async cancelation, but it is as close as we've +been able to get to it. + +If the thread you're trying to cancel is blocked (for instance, it could be +waiting for data from the network), it will only get cancelled when it unblocks +(when the data arrives). For true pre-emptive cancelation in these cases, +pthreads-win32 from snapshot 2004-05-16 can automatically recognise and use the +QueueUserAPCEx package by Panagiotis E. Hadjidoukas. This package is available +from the pthreads-win32 ftp site and is included in the pthreads-win32 +self-unpacking zip from 2004-05-16 onwards. + +Using deferred cancelation would normally be the way to go, however, +even though the POSIX threads standard lists a number of C library +functions that are defined as deferred cancelation points, there is +no hookup between those which are provided by Windows and the +pthreads-win32 library. + +Incidently, it's worth noting for code portability that the older POSIX +threads standards cancelation point lists didn't include "select" because +(as I read in Butenhof) it wasn't part of POSIX. However, it does appear in +the SUSV3. + +Effectively, the only mandatory cancelation points that pthreads-win32 +recognises are those the library implements itself, ie. + + pthread_testcancel + pthread_cond_wait + pthread_cond_timedwait + pthread_join + sem_wait + sem_timedwait + pthread_delay_np + +The following routines from the non-mandatory list in SUSV3 are +cancelation points in pthreads-win32: + + pthread_rwlock_wrlock + pthread_rwlock_timedwrlock + +The following routines from the non-mandatory list in SUSV3 are not +cancelation points in pthreads-win32: + + pthread_rwlock_rdlock + pthread_rwlock_timedrdlock + +Pthreads-win32 also provides two functions that allow you to create +cancelation points within your application, but only for cases where +a thread is going to block on a Win32 handle. These are: + + pthreadCancelableWait(HANDLE waitHandle) /* Infinite wait */ + + pthreadCancelableTimedWait(HANDLE waitHandle, DWORD timeout) + +------------------------------------------------------------------------------ + + +Q 10 How do I create thread-safe applications using +---- pthreadGCE.dll, libpthreadw32.a and Mingw32? + +This should not be a problem with recent versions of MinGW32. + +For early versions, see Thomas Pfaff's email at: +http://sources.redhat.com/ml/pthreads-win32/2002/msg00000.html +------------------------------------------------------------------------------ + +Q 11 Why isn't pthread_t defined as a scalar (e.g. pointer or int) + like it is for other POSIX threads implementations? +---- + +Originally pthread_t was defined as a pointer (to the opaque pthread_t_ +struct) and later it was changed to a struct containing the original +pointer plus a sequence counter. This is allowed under both the original +POSIX Threads Standard and the current Single Unix Specification. + +When pthread_t is a simple pointer to a struct some very difficult to +debug problems arise from the process of freeing and later allocing +thread structs because new pthread_t handles can acquire the identity of +previously detached threads. The change to a struct was made, along with +some changes to their internal managment, in order to guarantee (for +practical applications) that the pthread_t handle will be unique over the +life of the running process. + +Where application code attempts to compare one pthread_t against another +directly, a compiler error will be emitted because structs can't be +compared at that level. This should signal a potentially serious problem +in the code design, which would go undetected if pthread_t was a scalar. + +The POSIX Threading API provides a function named pthread_equal() to +compare pthread_t thread handles. + +Other pthreads implementations, such as Sun's, use an int as the handle +but do guarantee uniqueness within the process scope. Win32 scalar typed +thread handles also guarantee uniqueness in system scope. It wasn't clear +how well the internal management of these handles would scale as the +number of threads and the fragmentation of the sequence numbering +increased for applications where thousands or millions of threads are +created and detached over time. The current management of threads within +pthreads-win32 using structs for pthread_t, and reusing without ever +freeing them, reduces the management time overheads to a constant, which +could be important given that pthreads-win32 threads are built on top of +Win32 threads and will therefore include that management overhead on top +of their own. The cost is that the memory resources used for thread +handles will remain at the peak level until the process exits. + +While it may be inconvenient for developers to be forced away from making +assumptions about the internals of pthread_t, the advantage for the +future development of pthread-win32, as well as those applications that +use it and other pthread implementations, is that the library is free to +change pthread_t internals and management as better methods arise. + diff --git a/libs/pthreads/docs/GNUmakefile b/libs/pthreads/docs/GNUmakefile new file mode 100644 index 0000000000..e489f002ec --- /dev/null +++ b/libs/pthreads/docs/GNUmakefile @@ -0,0 +1,593 @@ +# +# -------------------------------------------------------------------------- +# +# Pthreads-win32 - POSIX Threads Library for Win32 +# Copyright(C) 1998 John E. Bossom +# Copyright(C) 1999,2005 Pthreads-win32 contributors +# +# Contact Email: rpj@callisto.canberra.edu.au +# +# The current list of contributors is contained +# in the file CONTRIBUTORS included with the source +# code distribution. The list can also be seen at the +# following World Wide Web location: +# http://sources.redhat.com/pthreads-win32/contributors.html +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library in the file COPYING.LIB; +# if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA +# + +DLL_VER = 2 +DLL_VERD= $(DLL_VER)d + +DEVROOT = C:\PTHREADS + +DLLDEST = $(DEVROOT)\DLL +LIBDEST = $(DEVROOT)\DLL + +# If Running MsysDTK +RM = rm -f +MV = mv -f +CP = cp -f + +# If not. +#RM = erase +#MV = rename +#CP = copy + +# For cross compiling use e.g. +# make CROSS=x86_64-w64-mingw32- clean GC-inlined +CROSS = + +AR = $(CROSS)ar +DLLTOOL = $(CROSS)dlltool +CC = $(CROSS)gcc +CXX = $(CROSS)g++ +RANLIB = $(CROSS)ranlib +RC = $(CROSS)windres + +OPT = $(CLEANUP) -O3 # -finline-functions -findirect-inlining +XOPT = + +RCFLAGS = --include-dir=. +# Uncomment this if config.h defines RETAIN_WSALASTERROR +#LFLAGS = -lws2_32 + +# ---------------------------------------------------------------------- +# The library can be built with some alternative behaviour to +# facilitate development of applications on Win32 that will be ported +# to other POSIX systems. Nothing definable here will make the library +# non-compliant, but applications that make assumptions that POSIX +# does not garrantee may fail or misbehave under some settings. +# +# PTW32_THREAD_ID_REUSE_INCREMENT +# Purpose: +# POSIX says that applications should assume that thread IDs can be +# recycled. However, Solaris and some other systems use a [very large] +# sequence number as the thread ID, which provides virtual uniqueness. +# Pthreads-win32 provides pseudo-unique IDs when the default increment +# (1) is used, but pthread_t is not a scalar type like Solaris's. +# +# Usage: +# Set to any value in the range: 0 <= value <= 2^wordsize +# +# Examples: +# Set to 0 to emulate non recycle-unique behaviour like Linux or *BSD. +# Set to 1 for recycle-unique thread IDs (this is the default). +# Set to some other +ve value to emulate smaller word size types +# (i.e. will wrap sooner). +# +#PTW32_FLAGS = "-DPTW32_THREAD_ID_REUSE_INCREMENT=0" +# +# ---------------------------------------------------------------------- + +GC_CFLAGS = $(PTW32_FLAGS) +GCE_CFLAGS = $(PTW32_FLAGS) -mthreads + +## Mingw +MAKE ?= make +CFLAGS = $(OPT) $(XOPT) -I. -DHAVE_PTW32_CONFIG_H -Wall + +DLL_INLINED_OBJS = \ + pthread.o \ + version.o + +# Agregate modules for inlinability +DLL_OBJS = \ + attr.o \ + barrier.o \ + cancel.o \ + cleanup.o \ + condvar.o \ + create.o \ + dll.o \ + errno.o \ + exit.o \ + fork.o \ + global.o \ + misc.o \ + mutex.o \ + nonportable.o \ + private.o \ + rwlock.o \ + sched.o \ + semaphore.o \ + signal.o \ + spin.o \ + sync.o \ + tsd.o \ + version.o + +# Separate modules for minimum size statically linked images +SMALL_STATIC_OBJS = \ + pthread_attr_init.o \ + pthread_attr_destroy.o \ + pthread_attr_getdetachstate.o \ + pthread_attr_setdetachstate.o \ + pthread_attr_getstackaddr.o \ + pthread_attr_setstackaddr.o \ + pthread_attr_getstacksize.o \ + pthread_attr_setstacksize.o \ + pthread_attr_getscope.o \ + pthread_attr_setscope.o \ + pthread_attr_setschedpolicy.o \ + pthread_attr_getschedpolicy.o \ + pthread_attr_setschedparam.o \ + pthread_attr_getschedparam.o \ + pthread_attr_setinheritsched.o \ + pthread_attr_getinheritsched.o \ + pthread_barrier_init.o \ + pthread_barrier_destroy.o \ + pthread_barrier_wait.o \ + pthread_barrierattr_init.o \ + pthread_barrierattr_destroy.o \ + pthread_barrierattr_setpshared.o \ + pthread_barrierattr_getpshared.o \ + pthread_setcancelstate.o \ + pthread_setcanceltype.o \ + pthread_testcancel.o \ + pthread_cancel.o \ + cleanup.o \ + pthread_condattr_destroy.o \ + pthread_condattr_getpshared.o \ + pthread_condattr_init.o \ + pthread_condattr_setpshared.o \ + pthread_cond_destroy.o \ + pthread_cond_init.o \ + pthread_cond_signal.o \ + pthread_cond_wait.o \ + create.o \ + dll.o \ + autostatic.o \ + errno.o \ + pthread_exit.o \ + fork.o \ + global.o \ + pthread_mutex_init.o \ + pthread_mutex_destroy.o \ + pthread_mutexattr_init.o \ + pthread_mutexattr_destroy.o \ + pthread_mutexattr_getpshared.o \ + pthread_mutexattr_setpshared.o \ + pthread_mutexattr_settype.o \ + pthread_mutexattr_gettype.o \ + pthread_mutexattr_setrobust.o \ + pthread_mutexattr_getrobust.o \ + pthread_mutex_lock.o \ + pthread_mutex_timedlock.o \ + pthread_mutex_unlock.o \ + pthread_mutex_trylock.o \ + pthread_mutex_consistent.o \ + pthread_mutexattr_setkind_np.o \ + pthread_mutexattr_getkind_np.o \ + pthread_getw32threadhandle_np.o \ + pthread_getunique_np.o \ + pthread_delay_np.o \ + pthread_num_processors_np.o \ + pthread_win32_attach_detach_np.o \ + pthread_equal.o \ + pthread_getconcurrency.o \ + pthread_once.o \ + pthread_self.o \ + pthread_setconcurrency.o \ + pthread_rwlock_init.o \ + pthread_rwlock_destroy.o \ + pthread_rwlockattr_init.o \ + pthread_rwlockattr_destroy.o \ + pthread_rwlockattr_getpshared.o \ + pthread_rwlockattr_setpshared.o \ + pthread_rwlock_rdlock.o \ + pthread_rwlock_wrlock.o \ + pthread_rwlock_unlock.o \ + pthread_rwlock_tryrdlock.o \ + pthread_rwlock_trywrlock.o \ + pthread_setschedparam.o \ + pthread_getschedparam.o \ + pthread_timechange_handler_np.o \ + ptw32_is_attr.o \ + ptw32_cond_check_need_init.o \ + ptw32_MCS_lock.o \ + ptw32_mutex_check_need_init.o \ + ptw32_processInitialize.o \ + ptw32_processTerminate.o \ + ptw32_threadStart.o \ + ptw32_threadDestroy.o \ + ptw32_tkAssocCreate.o \ + ptw32_tkAssocDestroy.o \ + ptw32_callUserDestroyRoutines.o \ + ptw32_timespec.o \ + ptw32_throw.o \ + ptw32_getprocessors.o \ + ptw32_calloc.o \ + ptw32_new.o \ + ptw32_reuse.o \ + ptw32_semwait.o \ + ptw32_relmillisecs.o \ + ptw32_rwlock_check_need_init.o \ + sched_get_priority_max.o \ + sched_get_priority_min.o \ + sched_setscheduler.o \ + sched_getscheduler.o \ + sched_yield.o \ + sem_init.o \ + sem_destroy.o \ + sem_trywait.o \ + sem_timedwait.o \ + sem_wait.o \ + sem_post.o \ + sem_post_multiple.o \ + sem_getvalue.o \ + sem_open.o \ + sem_close.o \ + sem_unlink.o \ + signal.o \ + pthread_kill.o \ + ptw32_spinlock_check_need_init.o \ + pthread_spin_init.o \ + pthread_spin_destroy.o \ + pthread_spin_lock.o \ + pthread_spin_unlock.o \ + pthread_spin_trylock.o \ + pthread_detach.o \ + pthread_join.o \ + pthread_key_create.o \ + pthread_key_delete.o \ + pthread_setspecific.o \ + pthread_getspecific.o \ + w32_CancelableWait.o \ + version.o + +INCL = \ + config.h \ + implement.h \ + semaphore.h \ + pthread.h \ + need_errno.h + +ATTR_SRCS = \ + pthread_attr_init.c \ + pthread_attr_destroy.c \ + pthread_attr_getdetachstate.c \ + pthread_attr_setdetachstate.c \ + pthread_attr_getstackaddr.c \ + pthread_attr_setstackaddr.c \ + pthread_attr_getstacksize.c \ + pthread_attr_setstacksize.c \ + pthread_attr_getscope.c \ + pthread_attr_setscope.c + +BARRIER_SRCS = \ + pthread_barrier_init.c \ + pthread_barrier_destroy.c \ + pthread_barrier_wait.c \ + pthread_barrierattr_init.c \ + pthread_barrierattr_destroy.c \ + pthread_barrierattr_setpshared.c \ + pthread_barrierattr_getpshared.c + +CANCEL_SRCS = \ + pthread_setcancelstate.c \ + pthread_setcanceltype.c \ + pthread_testcancel.c \ + pthread_cancel.c + +CONDVAR_SRCS = \ + ptw32_cond_check_need_init.c \ + pthread_condattr_destroy.c \ + pthread_condattr_getpshared.c \ + pthread_condattr_init.c \ + pthread_condattr_setpshared.c \ + pthread_cond_destroy.c \ + pthread_cond_init.c \ + pthread_cond_signal.c \ + pthread_cond_wait.c + +EXIT_SRCS = \ + pthread_exit.c + +MISC_SRCS = \ + pthread_equal.c \ + pthread_getconcurrency.c \ + pthread_kill.c \ + pthread_once.c \ + pthread_self.c \ + pthread_setconcurrency.c \ + ptw32_calloc.c \ + ptw32_MCS_lock.c \ + ptw32_new.c \ + ptw32_reuse.c \ + w32_CancelableWait.c + +MUTEX_SRCS = \ + ptw32_mutex_check_need_init.c \ + pthread_mutex_init.c \ + pthread_mutex_destroy.c \ + pthread_mutexattr_init.c \ + pthread_mutexattr_destroy.c \ + pthread_mutexattr_getpshared.c \ + pthread_mutexattr_setpshared.c \ + pthread_mutexattr_settype.c \ + pthread_mutexattr_gettype.c \ + pthread_mutexattr_setrobust.c \ + pthread_mutexattr_getrobust.c \ + pthread_mutex_lock.c \ + pthread_mutex_timedlock.c \ + pthread_mutex_unlock.c \ + pthread_mutex_trylock.c \ + pthread_mutex_consistent.c + +NONPORTABLE_SRCS = \ + pthread_mutexattr_setkind_np.c \ + pthread_mutexattr_getkind_np.c \ + pthread_getw32threadhandle_np.c \ + pthread_getunique_np.c \ + pthread_delay_np.c \ + pthread_num_processors_np.c \ + pthread_win32_attach_detach_np.c \ + pthread_timechange_handler_np.c + +PRIVATE_SRCS = \ + ptw32_is_attr.c \ + ptw32_processInitialize.c \ + ptw32_processTerminate.c \ + ptw32_threadStart.c \ + ptw32_threadDestroy.c \ + ptw32_tkAssocCreate.c \ + ptw32_tkAssocDestroy.c \ + ptw32_callUserDestroyRoutines.c \ + ptw32_semwait.c \ + ptw32_relmillisecs.c \ + ptw32_timespec.c \ + ptw32_throw.c \ + ptw32_getprocessors.c + +RWLOCK_SRCS = \ + ptw32_rwlock_check_need_init.c \ + ptw32_rwlock_cancelwrwait.c \ + pthread_rwlock_init.c \ + pthread_rwlock_destroy.c \ + pthread_rwlockattr_init.c \ + pthread_rwlockattr_destroy.c \ + pthread_rwlockattr_getpshared.c \ + pthread_rwlockattr_setpshared.c \ + pthread_rwlock_rdlock.c \ + pthread_rwlock_timedrdlock.c \ + pthread_rwlock_wrlock.c \ + pthread_rwlock_timedwrlock.c \ + pthread_rwlock_unlock.c \ + pthread_rwlock_tryrdlock.c \ + pthread_rwlock_trywrlock.c + +SCHED_SRCS = \ + pthread_attr_setschedpolicy.c \ + pthread_attr_getschedpolicy.c \ + pthread_attr_setschedparam.c \ + pthread_attr_getschedparam.c \ + pthread_attr_setinheritsched.c \ + pthread_attr_getinheritsched.c \ + pthread_setschedparam.c \ + pthread_getschedparam.c \ + sched_get_priority_max.c \ + sched_get_priority_min.c \ + sched_setscheduler.c \ + sched_getscheduler.c \ + sched_yield.c + +SEMAPHORE_SRCS = \ + sem_init.c \ + sem_destroy.c \ + sem_trywait.c \ + sem_timedwait.c \ + sem_wait.c \ + sem_post.c \ + sem_post_multiple.c \ + sem_getvalue.c \ + sem_open.c \ + sem_close.c \ + sem_unlink.c + +SPIN_SRCS = \ + ptw32_spinlock_check_need_init.c \ + pthread_spin_init.c \ + pthread_spin_destroy.c \ + pthread_spin_lock.c \ + pthread_spin_unlock.c \ + pthread_spin_trylock.c + +SYNC_SRCS = \ + pthread_detach.c \ + pthread_join.c + +TSD_SRCS = \ + pthread_key_create.c \ + pthread_key_delete.c \ + pthread_setspecific.c \ + pthread_getspecific.c + + +GCE_DLL = pthreadGCE$(DLL_VER).dll +GCED_DLL= pthreadGCE$(DLL_VERD).dll +GCE_LIB = libpthreadGCE$(DLL_VER).a +GCED_LIB= libpthreadGCE$(DLL_VERD).a +GCE_INLINED_STAMP = pthreadGCE$(DLL_VER).stamp +GCED_INLINED_STAMP = pthreadGCE$(DLL_VERD).stamp +GCE_STATIC_STAMP = libpthreadGCE$(DLL_VER).stamp +GCED_STATIC_STAMP = libpthreadGCE$(DLL_VERD).stamp + +GC_DLL = pthreadGC$(DLL_VER).dll +GCD_DLL = pthreadGC$(DLL_VERD).dll +GC_LIB = libpthreadGC$(DLL_VER).a +GCD_LIB = libpthreadGC$(DLL_VERD).a +GC_INLINED_STAMP = pthreadGC$(DLL_VER).stamp +GCD_INLINED_STAMP = pthreadGC$(DLL_VERD).stamp +GC_STATIC_STAMP = libpthreadGC$(DLL_VER).stamp +GCD_STATIC_STAMP = libpthreadGC$(DLL_VERD).stamp + +PTHREAD_DEF = pthread.def + +help: + @ echo "Run one of the following command lines:" + @ echo "make clean GC (to build the GNU C dll with C cleanup code)" + @ echo "make clean GCE (to build the GNU C dll with C++ exception handling)" + @ echo "make clean GC-inlined (to build the GNU C inlined dll with C cleanup code)" + @ echo "make clean GCE-inlined (to build the GNU C inlined dll with C++ exception handling)" + @ echo "make clean GC-static (to build the GNU C inlined static lib with C cleanup code)" + @ echo "make clean GC-debug (to build the GNU C debug dll with C cleanup code)" + @ echo "make clean GCE-debug (to build the GNU C debug dll with C++ exception handling)" + @ echo "make clean GC-inlined-debug (to build the GNU C inlined debug dll with C cleanup code)" + @ echo "make clean GCE-inlined-debug (to build the GNU C inlined debug dll with C++ exception handling)" + @ echo "make clean GC-static-debug (to build the GNU C inlined static debug lib with C cleanup code)" + +all: + @ $(MAKE) clean GCE + @ $(MAKE) clean GC + +GC: + $(MAKE) CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_OBJS)" $(GC_DLL) + +GC-debug: + $(MAKE) CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_OBJS)" DLL_VER=$(DLL_VERD) OPT="-D__CLEANUP_C -g -O0" $(GCD_DLL) + +GCE: + $(MAKE) CC=$(CXX) CLEANUP=-D__CLEANUP_CXX XC_FLAGS="$(GCE_CFLAGS)" OBJ="$(DLL_OBJS)" $(GCE_DLL) + +GCE-debug: + $(MAKE) CC=$(CXX) CLEANUP=-D__CLEANUP_CXX XC_FLAGS="$(GCE_CFLAGS)" OBJ="$(DLL_OBJS)" DLL_VER=$(DLL_VERD) OPT="-D__CLEANUP_CXX -g -O0" $(GCED_DLL) + +GC-inlined: + $(MAKE) XOPT="-DPTW32_BUILD_INLINED" CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" $(GC_INLINED_STAMP) + +GC-inlined-debug: + $(MAKE) XOPT="-DPTW32_BUILD_INLINED" CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" DLL_VER=$(DLL_VERD) OPT="-D__CLEANUP_C -g -O0" $(GCD_INLINED_STAMP) + +GCE-inlined: + $(MAKE) CC=$(CXX) XOPT="-DPTW32_BUILD_INLINED" CLEANUP=-D__CLEANUP_CXX XC_FLAGS="$(GCE_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" $(GCE_INLINED_STAMP) + +GCE-inlined-debug: + $(MAKE) CC=$(CXX) XOPT="-DPTW32_BUILD_INLINED" CLEANUP=-D__CLEANUP_CXX XC_FLAGS="$(GCE_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" DLL_VER=$(DLL_VERD) OPT="-D__CLEANUP_CXX -g -O0" $(GCED_INLINED_STAMP) + +GC-static: + $(MAKE) XOPT="-DPTW32_BUILD_INLINED -DPTW32_STATIC_LIB" CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" $(GC_STATIC_STAMP) + +GC-static-debug: + $(MAKE) XOPT="-DPTW32_BUILD_INLINED -DPTW32_STATIC_LIB" CLEANUP=-D__CLEANUP_C XC_FLAGS="$(GC_CFLAGS)" OBJ="$(DLL_INLINED_OBJS)" DLL_VER=$(DLL_VERD) OPT="-D__CLEANUP_C -g -O0" $(GCD_STATIC_STAMP) + +tests: + @ cd tests + @ $(MAKE) auto + +%.pre: %.c + $(CC) -E -o $@ $(CFLAGS) $^ + +%.s: %.c + $(CC) -c $(CFLAGS) -DPTW32_BUILD_INLINED -Wa,-ahl $^ > $@ + +%.o: %.rc + $(RC) $(RCFLAGS) $(CLEANUP) -o $@ -i $< + +.SUFFIXES: .dll .rc .c .o + +.c.o:; $(CC) -c -o $@ $(CFLAGS) $(XC_FLAGS) $< + + +$(GC_DLL) $(GCD_DLL): $(DLL_OBJS) + $(CC) $(OPT) -shared -o $(GC_DLL) $(DLL_OBJS) $(LFLAGS) + $(DLLTOOL) -z pthread.def $(DLL_OBJS) + $(DLLTOOL) -k --dllname $@ --output-lib $(GC_LIB) --def $(PTHREAD_DEF) + +$(GCE_DLL): $(DLL_OBJS) + $(CC) $(OPT) -mthreads -shared -o $(GCE_DLL) $(DLL_OBJS) $(LFLAGS) + $(DLLTOOL) -z pthread.def $(DLL_OBJS) + $(DLLTOOL) -k --dllname $@ --output-lib $(GCE_LIB) --def $(PTHREAD_DEF) + +$(GC_INLINED_STAMP) $(GCD_INLINED_STAMP): $(DLL_INLINED_OBJS) + $(CC) $(OPT) $(XOPT) -shared -o $(GC_DLL) $(DLL_INLINED_OBJS) $(LFLAGS) + $(DLLTOOL) -z pthread.def $(DLL_INLINED_OBJS) + $(DLLTOOL) -k --dllname $(GC_DLL) --output-lib $(GC_LIB) --def $(PTHREAD_DEF) + echo touched > $(GC_INLINED_STAMP) + +$(GCE_INLINED_STAMP) $(GCED_INLINED_STAMP): $(DLL_INLINED_OBJS) + $(CC) $(OPT) $(XOPT) -mthreads -shared -o $(GCE_DLL) $(DLL_INLINED_OBJS) $(LFLAGS) + $(DLLTOOL) -z pthread.def $(DLL_INLINED_OBJS) + $(DLLTOOL) -k --dllname $(GCE_DLL) --output-lib $(GCE_LIB) --def $(PTHREAD_DEF) + echo touched > $(GCE_INLINED_STAMP) + +$(GC_STATIC_STAMP) $(GCD_STATIC_STAMP): $(DLL_INLINED_OBJS) + $(RM) $(GC_LIB) + $(AR) -rv $(GC_LIB) $(DLL_INLINED_OBJS) + $(RANLIB) $(GC_LIB) + echo touched > $(GC_STATIC_STAMP) + +clean: + -$(RM) *~ + -$(RM) *.i + -$(RM) *.s + -$(RM) *.o + -$(RM) *.obj + -$(RM) *.exe + -$(RM) $(PTHREAD_DEF) + +realclean: clean + -$(RM) $(GC_LIB) + -$(RM) $(GCE_LIB) + -$(RM) $(GC_DLL) + -$(RM) $(GCE_DLL) + -$(RM) $(GC_INLINED_STAMP) + -$(RM) $(GCE_INLINED_STAMP) + -$(RM) $(GC_STATIC_STAMP) + -$(RM) $(GCD_LIB) + -$(RM) $(GCED_LIB) + -$(RM) $(GCD_DLL) + -$(RM) $(GCED_DLL) + -$(RM) $(GCD_INLINED_STAMP) + -$(RM) $(GCED_INLINED_STAMP) + -$(RM) $(GCD_STATIC_STAMP) + +attr.o: attr.c $(ATTR_SRCS) $(INCL) +barrier.o: barrier.c $(BARRIER_SRCS) $(INCL) +cancel.o: cancel.c $(CANCEL_SRCS) $(INCL) +condvar.o: condvar.c $(CONDVAR_SRCS) $(INCL) +exit.o: exit.c $(EXIT_SRCS) $(INCL) +misc.o: misc.c $(MISC_SRCS) $(INCL) +mutex.o: mutex.c $(MUTEX_SRCS) $(INCL) +nonportable.o: nonportable.c $(NONPORTABLE_SRCS) $(INCL) +private.o: private.c $(PRIVATE_SRCS) $(INCL) +rwlock.o: rwlock.c $(RWLOCK_SRCS) $(INCL) +sched.o: sched.c $(SCHED_SRCS) $(INCL) +semaphore.o: semaphore.c $(SEMAPHORE_SRCS) $(INCL) +spin.o: spin.c $(SPIN_SRCS) $(INCL) +sync.o: sync.c $(SYNC_SRCS) $(INCL) +tsd.o: tsd.c $(TSD_SRCS) $(INCL) +version.o: version.rc $(INCL) diff --git a/libs/pthreads/docs/MAINTAINERS b/libs/pthreads/docs/MAINTAINERS new file mode 100644 index 0000000000..d253c1f69e --- /dev/null +++ b/libs/pthreads/docs/MAINTAINERS @@ -0,0 +1,4 @@ +CVS Repository maintainers + +Ross Johnson rpj@ise.canberra.edu.au +Ben Elliston bje@cygnus.com diff --git a/libs/pthreads/docs/Makefile b/libs/pthreads/docs/Makefile new file mode 100644 index 0000000000..472969cf9b --- /dev/null +++ b/libs/pthreads/docs/Makefile @@ -0,0 +1,514 @@ +# This makefile is compatible with MS nmake and can be used as a +# replacement for buildlib.bat. I've changed the target from an ordinary dll +# (/LD) to a debugging dll (/LDd). +# +# The variables $DLLDEST and $LIBDEST hold the destination directories for the +# dll and the lib, respectively. Probably all that needs to change is $DEVROOT. + + +# DLL_VER: +# See pthread.h and README - This number is computed as 'current - age' +DLL_VER = 2 +DLL_VERD= $(DLL_VER)d + +DEVROOT = C:\pthreads + +DLLDEST = $(DEVROOT)\dll +LIBDEST = $(DEVROOT)\lib +HDRDEST = $(DEVROOT)\include + +DLLS = pthreadVCE$(DLL_VER).dll pthreadVSE$(DLL_VER).dll pthreadVC$(DLL_VER).dll \ + pthreadVCE$(DLL_VERD).dll pthreadVSE$(DLL_VERD).dll pthreadVC$(DLL_VERD).dll +INLINED_STAMPS = pthreadVCE$(DLL_VER).stamp pthreadVSE$(DLL_VER).stamp pthreadVC$(DLL_VER).stamp \ + pthreadVCE$(DLL_VERD).stamp pthreadVSE$(DLL_VERD).stamp pthreadVC$(DLL_VERD).stamp +STATIC_STAMPS = pthreadVCE$(DLL_VER).static pthreadVSE$(DLL_VER).static pthreadVC$(DLL_VER).static \ + pthreadVCE$(DLL_VERD).static pthreadVSE$(DLL_VERD).static pthreadVC$(DLL_VERD).static + +CC = cl +CPPFLAGS = /I. /DHAVE_PTW32_CONFIG_H +XCFLAGS = /W3 /MD /nologo +CFLAGS = /O2 /Ob2 $(XCFLAGS) +CFLAGSD = /Z7 $(XCFLAGS) + +# Uncomment this if config.h defines RETAIN_WSALASTERROR +#XLIBS = wsock32.lib + +# Default cleanup style +CLEANUP = __CLEANUP_C + +# C++ Exceptions +VCEFLAGS = /EHsc /TP $(CPPFLAGS) $(CFLAGS) +VCEFLAGSD = /EHsc /TP $(CPPFLAGS) $(CFLAGSD) +#Structured Exceptions +VSEFLAGS = $(CPPFLAGS) $(CFLAGS) +VSEFLAGSD = $(CPPFLAGS) $(CFLAGSD) +#C cleanup code +VCFLAGS = $(CPPFLAGS) $(CFLAGS) +VCFLAGSD = $(CPPFLAGS) $(CFLAGSD) + +DLL_INLINED_OBJS = \ + pthread.obj \ + version.res + +# Aggregate modules for inlinability +DLL_OBJS = \ + attr.obj \ + barrier.obj \ + cancel.obj \ + cleanup.obj \ + condvar.obj \ + create.obj \ + dll.obj \ + autostatic.obj \ + errno.obj \ + exit.obj \ + fork.obj \ + global.obj \ + misc.obj \ + mutex.obj \ + nonportable.obj \ + private.obj \ + rwlock.obj \ + sched.obj \ + semaphore.obj \ + signal.obj \ + spin.obj \ + sync.obj \ + tsd.obj \ + version.res + +# Separate modules for minimising the size of statically linked images +SMALL_STATIC_OBJS = \ + pthread_attr_init.obj \ + pthread_attr_destroy.obj \ + pthread_attr_getdetachstate.obj \ + pthread_attr_setdetachstate.obj \ + pthread_attr_getstackaddr.obj \ + pthread_attr_setstackaddr.obj \ + pthread_attr_getstacksize.obj \ + pthread_attr_setstacksize.obj \ + pthread_attr_getscope.obj \ + pthread_attr_setscope.obj \ + pthread_attr_setschedpolicy.obj \ + pthread_attr_getschedpolicy.obj \ + pthread_attr_setschedparam.obj \ + pthread_attr_getschedparam.obj \ + pthread_attr_setinheritsched.obj \ + pthread_attr_getinheritsched.obj \ + pthread_barrier_init.obj \ + pthread_barrier_destroy.obj \ + pthread_barrier_wait.obj \ + pthread_barrierattr_init.obj \ + pthread_barrierattr_destroy.obj \ + pthread_barrierattr_setpshared.obj \ + pthread_barrierattr_getpshared.obj \ + pthread_setcancelstate.obj \ + pthread_setcanceltype.obj \ + pthread_testcancel.obj \ + pthread_cancel.obj \ + cleanup.obj \ + pthread_condattr_destroy.obj \ + pthread_condattr_getpshared.obj \ + pthread_condattr_init.obj \ + pthread_condattr_setpshared.obj \ + pthread_cond_destroy.obj \ + pthread_cond_init.obj \ + pthread_cond_signal.obj \ + pthread_cond_wait.obj \ + create.obj \ + dll.obj \ + autostatic.obj \ + errno.obj \ + pthread_exit.obj \ + fork.obj \ + global.obj \ + pthread_mutex_init.obj \ + pthread_mutex_destroy.obj \ + pthread_mutexattr_init.obj \ + pthread_mutexattr_destroy.obj \ + pthread_mutexattr_getpshared.obj \ + pthread_mutexattr_setpshared.obj \ + pthread_mutexattr_settype.obj \ + pthread_mutexattr_gettype.obj \ + pthread_mutexattr_setrobust.obj \ + pthread_mutexattr_getrobust.obj \ + pthread_mutex_lock.obj \ + pthread_mutex_timedlock.obj \ + pthread_mutex_unlock.obj \ + pthread_mutex_trylock.obj \ + pthread_mutex_consistent.obj \ + pthread_mutexattr_setkind_np.obj \ + pthread_mutexattr_getkind_np.obj \ + pthread_getw32threadhandle_np.obj \ + pthread_getunique_np.obj \ + pthread_delay_np.obj \ + pthread_num_processors_np.obj \ + pthread_win32_attach_detach_np.obj \ + pthread_equal.obj \ + pthread_getconcurrency.obj \ + pthread_once.obj \ + pthread_self.obj \ + pthread_setconcurrency.obj \ + pthread_rwlock_init.obj \ + pthread_rwlock_destroy.obj \ + pthread_rwlockattr_init.obj \ + pthread_rwlockattr_destroy.obj \ + pthread_rwlockattr_getpshared.obj \ + pthread_rwlockattr_setpshared.obj \ + pthread_rwlock_rdlock.obj \ + pthread_rwlock_wrlock.obj \ + pthread_rwlock_unlock.obj \ + pthread_rwlock_tryrdlock.obj \ + pthread_rwlock_trywrlock.obj \ + pthread_setschedparam.obj \ + pthread_getschedparam.obj \ + pthread_timechange_handler_np.obj \ + ptw32_is_attr.obj \ + ptw32_processInitialize.obj \ + ptw32_processTerminate.obj \ + ptw32_threadStart.obj \ + ptw32_threadDestroy.obj \ + ptw32_tkAssocCreate.obj \ + ptw32_tkAssocDestroy.obj \ + ptw32_callUserDestroyRoutines.obj \ + ptw32_timespec.obj \ + ptw32_throw.obj \ + ptw32_getprocessors.obj \ + ptw32_calloc.obj \ + ptw32_new.obj \ + ptw32_reuse.obj \ + ptw32_rwlock_check_need_init.obj \ + ptw32_cond_check_need_init.obj \ + ptw32_mutex_check_need_init.obj \ + ptw32_semwait.obj \ + ptw32_relmillisecs.obj \ + ptw32_MCS_lock.obj \ + sched_get_priority_max.obj \ + sched_get_priority_min.obj \ + sched_setscheduler.obj \ + sched_getscheduler.obj \ + sched_yield.obj \ + sem_init.obj \ + sem_destroy.obj \ + sem_trywait.obj \ + sem_timedwait.obj \ + sem_wait.obj \ + sem_post.obj \ + sem_post_multiple.obj \ + sem_getvalue.obj \ + sem_open.obj \ + sem_close.obj \ + sem_unlink.obj \ + signal.obj \ + pthread_kill.obj \ + ptw32_spinlock_check_need_init.obj \ + pthread_spin_init.obj \ + pthread_spin_destroy.obj \ + pthread_spin_lock.obj \ + pthread_spin_unlock.obj \ + pthread_spin_trylock.obj \ + pthread_detach.obj \ + pthread_join.obj \ + pthread_key_create.obj \ + pthread_key_delete.obj \ + pthread_setspecific.obj \ + pthread_getspecific.obj \ + w32_CancelableWait.obj \ + version.res + +INCL = config.h implement.h semaphore.h pthread.h need_errno.h + +ATTR_SRCS = \ + pthread_attr_init.c \ + pthread_attr_destroy.c \ + pthread_attr_getdetachstate.c \ + pthread_attr_setdetachstate.c \ + pthread_attr_getstackaddr.c \ + pthread_attr_setstackaddr.c \ + pthread_attr_getstacksize.c \ + pthread_attr_setstacksize.c \ + pthread_attr_getscope.c \ + pthread_attr_setscope.c + +BARRIER_SRCS = \ + pthread_barrier_init.c \ + pthread_barrier_destroy.c \ + pthread_barrier_wait.c \ + pthread_barrierattr_init.c \ + pthread_barrierattr_destroy.c \ + pthread_barrierattr_setpshared.c \ + pthread_barrierattr_getpshared.c + +CANCEL_SRCS = \ + pthread_setcancelstate.c \ + pthread_setcanceltype.c \ + pthread_testcancel.c \ + pthread_cancel.c + +CONDVAR_SRCS = \ + ptw32_cond_check_need_init.c \ + pthread_condattr_destroy.c \ + pthread_condattr_getpshared.c \ + pthread_condattr_init.c \ + pthread_condattr_setpshared.c \ + pthread_cond_destroy.c \ + pthread_cond_init.c \ + pthread_cond_signal.c \ + pthread_cond_wait.c + +EXIT_SRCS = \ + pthread_exit.c + +MISC_SRCS = \ + pthread_equal.c \ + pthread_getconcurrency.c \ + pthread_kill.c \ + pthread_once.c \ + pthread_self.c \ + pthread_setconcurrency.c \ + ptw32_calloc.c \ + ptw32_MCS_lock.c \ + ptw32_new.c \ + ptw32_reuse.c \ + ptw32_relmillisecs.c \ + w32_CancelableWait.c + +MUTEX_SRCS = \ + ptw32_mutex_check_need_init.c \ + pthread_mutex_init.c \ + pthread_mutex_destroy.c \ + pthread_mutexattr_init.c \ + pthread_mutexattr_destroy.c \ + pthread_mutexattr_getpshared.c \ + pthread_mutexattr_setpshared.c \ + pthread_mutexattr_settype.c \ + pthread_mutexattr_gettype.c \ + pthread_mutexattr_setrobust.c \ + pthread_mutexattr_getrobust.c \ + pthread_mutex_lock.c \ + pthread_mutex_timedlock.c \ + pthread_mutex_unlock.c \ + pthread_mutex_trylock.c \ + pthread_mutex_consistent.c + +NONPORTABLE_SRCS = \ + pthread_mutexattr_setkind_np.c \ + pthread_mutexattr_getkind_np.c \ + pthread_getw32threadhandle_np.c \ + pthread_getunique_np.c \ + pthread_delay_np.c \ + pthread_num_processors_np.c \ + pthread_win32_attach_detach_np.c \ + pthread_timechange_handler_np.c + +PRIVATE_SRCS = \ + ptw32_is_attr.c \ + ptw32_processInitialize.c \ + ptw32_processTerminate.c \ + ptw32_threadStart.c \ + ptw32_threadDestroy.c \ + ptw32_tkAssocCreate.c \ + ptw32_tkAssocDestroy.c \ + ptw32_callUserDestroyRoutines.c \ + ptw32_semwait.c \ + ptw32_timespec.c \ + ptw32_throw.c \ + ptw32_getprocessors.c + +RWLOCK_SRCS = \ + ptw32_rwlock_check_need_init.c \ + ptw32_rwlock_cancelwrwait.c \ + pthread_rwlock_init.c \ + pthread_rwlock_destroy.c \ + pthread_rwlockattr_init.c \ + pthread_rwlockattr_destroy.c \ + pthread_rwlockattr_getpshared.c \ + pthread_rwlockattr_setpshared.c \ + pthread_rwlock_rdlock.c \ + pthread_rwlock_timedrdlock.c \ + pthread_rwlock_wrlock.c \ + pthread_rwlock_timedwrlock.c \ + pthread_rwlock_unlock.c \ + pthread_rwlock_tryrdlock.c \ + pthread_rwlock_trywrlock.c + +SCHED_SRCS = \ + pthread_attr_setschedpolicy.c \ + pthread_attr_getschedpolicy.c \ + pthread_attr_setschedparam.c \ + pthread_attr_getschedparam.c \ + pthread_attr_setinheritsched.c \ + pthread_attr_getinheritsched.c \ + pthread_setschedparam.c \ + pthread_getschedparam.c \ + sched_get_priority_max.c \ + sched_get_priority_min.c \ + sched_setscheduler.c \ + sched_getscheduler.c \ + sched_yield.c + +SEMAPHORE_SRCS = \ + sem_init.c \ + sem_destroy.c \ + sem_trywait.c \ + sem_timedwait.c \ + sem_wait.c \ + sem_post.c \ + sem_post_multiple.c \ + sem_getvalue.c \ + sem_open.c \ + sem_close.c \ + sem_unlink.c + +SPIN_SRCS = \ + ptw32_spinlock_check_need_init.c \ + pthread_spin_init.c \ + pthread_spin_destroy.c \ + pthread_spin_lock.c \ + pthread_spin_unlock.c \ + pthread_spin_trylock.c + +SYNC_SRCS = \ + pthread_detach.c \ + pthread_join.c + +TSD_SRCS = \ + pthread_key_create.c \ + pthread_key_delete.c \ + pthread_setspecific.c \ + pthread_getspecific.c + + +help: + @ echo Run one of the following command lines: + @ echo nmake clean VCE (to build the MSVC dll with C++ exception handling) + @ echo nmake clean VSE (to build the MSVC dll with structured exception handling) + @ echo nmake clean VC (to build the MSVC dll with C cleanup code) + @ echo nmake clean VCE-inlined (to build the MSVC inlined dll with C++ exception handling) + @ echo nmake clean VSE-inlined (to build the MSVC inlined dll with structured exception handling) + @ echo nmake clean VC-inlined (to build the MSVC inlined dll with C cleanup code) + @ echo nmake clean VC-static (to build the MSVC static lib with C cleanup code) + @ echo nmake clean VCE-debug (to build the debug MSVC dll with C++ exception handling) + @ echo nmake clean VSE-debug (to build the debug MSVC dll with structured exception handling) + @ echo nmake clean VC-debug (to build the debug MSVC dll with C cleanup code) + @ echo nmake clean VCE-inlined-debug (to build the debug MSVC inlined dll with C++ exception handling) + @ echo nmake clean VSE-inlined-debug (to build the debug MSVC inlined dll with structured exception handling) + @ echo nmake clean VC-inlined-debug (to build the debug MSVC inlined dll with C cleanup code) + @ echo nmake clean VC-static-debug (to build the debug MSVC static lib with C cleanup code) + +all: + @ $(MAKE) /E clean VCE-inlined + @ $(MAKE) /E clean VSE-inlined + @ $(MAKE) /E clean VC-inlined + @ $(MAKE) /E clean VCE-inlined-debug + @ $(MAKE) /E clean VSE-inlined-debug + @ $(MAKE) /E clean VC-inlined-debug + +VCE: + @ $(MAKE) /E /nologo EHFLAGS="$(VCEFLAGS)" CLEANUP=__CLEANUP_CXX pthreadVCE$(DLL_VER).dll + +VCE-debug: + @ $(MAKE) /E /nologo EHFLAGS="$(VCEFLAGSD)" CLEANUP=__CLEANUP_CXX pthreadVCE$(DLL_VERD).dll + +VSE: + @ $(MAKE) /E /nologo EHFLAGS="$(VSEFLAGS)" CLEANUP=__CLEANUP_SEH pthreadVSE$(DLL_VER).dll + +VSE-debug: + @ $(MAKE) /E /nologo EHFLAGS="$(VSEFLAGSD)" CLEANUP=__CLEANUP_SEH pthreadVSE$(DLL_VERD).dll + +VC: + @ $(MAKE) /E /nologo EHFLAGS="$(VCFLAGS)" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VER).dll + +VC-debug: + @ $(MAKE) /E /nologo EHFLAGS="$(VCFLAGSD)" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VERD).dll + +# +# The so-called inlined DLL is just a single translation unit with +# inlining optimisation turned on. +# +VCE-inlined: + @ $(MAKE) /E /nologo EHFLAGS="$(VCEFLAGS) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_CXX pthreadVCE$(DLL_VER).stamp + +VCE-inlined-debug: + @ $(MAKE) /E /nologo EHFLAGS="$(VCEFLAGSD) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_CXX pthreadVCE$(DLL_VERD).stamp + +VSE-inlined: + @ $(MAKE) /E /nologo EHFLAGS="$(VSEFLAGS) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_SEH pthreadVSE$(DLL_VER).stamp + +VSE-inlined-debug: + @ $(MAKE) /E /nologo EHFLAGS="$(VSEFLAGSD) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_SEH pthreadVSE$(DLL_VERD).stamp + +VC-inlined: + @ $(MAKE) /E /nologo EHFLAGS="$(VCFLAGS) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VER).stamp + +VC-inlined-debug: + @ $(MAKE) /E /nologo EHFLAGS="$(VCFLAGSD) /DPTW32_BUILD_INLINED" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VERD).stamp + +VC-static: + @ $(MAKE) /E /nologo EHFLAGS="$(VCFLAGS) /DPTW32_BUILD_INLINED /DPTW32_STATIC_LIB" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VER).static + +VC-static-debug: + @ $(MAKE) /E /nologo EHFLAGS="$(VCFLAGSD) /DPTW32_BUILD_INLINED /DPTW32_STATIC_LIB" CLEANUP=__CLEANUP_C pthreadVC$(DLL_VERD).static + +realclean: clean + if exist pthread*.dll del pthread*.dll + if exist pthread*.lib del pthread*.lib + if exist *.manifest del *.manifest + if exist *.stamp del *.stamp + +clean: + if exist *.obj del *.obj + if exist *.def del *.def + if exist *.ilk del *.ilk + if exist *.pdb del *.pdb + if exist *.exp del *.exp + if exist *.map del *.map + if exist *.o del *.o + if exist *.i del *.i + if exist *.res del *.res + + +install: + copy pthread*.dll $(DLLDEST) + copy pthread*.lib $(LIBDEST) + copy pthread.h $(HDRDEST) + copy sched.h $(HDRDEST) + copy semaphore.h $(HDRDEST) + +$(DLLS): $(DLL_OBJS) + $(CC) /LDd /Zi /nologo $(DLL_OBJS) /link /implib:$*.lib $(XLIBS) /out:$@ + +$(INLINED_STAMPS): $(DLL_INLINED_OBJS) + $(CC) /LDd /Zi /nologo $(DLL_INLINED_OBJS) /link /implib:$*.lib $(XLIBS) /out:$*.dll + +$(STATIC_STAMPS): $(DLL_INLINED_OBJS) + if exist $*.lib del $*.lib + lib $(DLL_INLINED_OBJS) /out:$*.lib + +.c.obj: + $(CC) $(EHFLAGS) /D$(CLEANUP) -c $< + +# TARGET_CPU is an environment variable set by Visual Studio Command Prompt +# as provided by the SDK +.rc.res: + rc /dPTW32_ARCH$(TARGET_CPU) /dPTW32_RC_MSC /d$(CLEANUP) $< + +.c.i: + $(CC) /P /O2 /Ob1 $(VCFLAGS) $< + +attr.obj: attr.c $(ATTR_SRCS) $(INCL) +barrier.obj: barrier.c $(BARRIER_SRCS) $(INCL) +cancel.obj: cancel.c $(CANCEL_SRCS) $(INCL) +condvar.obj: condvar.c $(CONDVAR_SRCS) $(INCL) +exit.obj: exit.c $(EXIT_SRCS) $(INCL) +misc.obj: misc.c $(MISC_SRCS) $(INCL) +mutex.obj: mutex.c $(MUTEX_SRCS) $(INCL) +nonportable.obj: nonportable.c $(NONPORTABLE_SRCS) $(INCL) +private.obj: private.c $(PRIVATE_SRCS) $(INCL) +rwlock.obj: rwlock.c $(RWLOCK_SRCS) $(INCL) +sched.obj: sched.c $(SCHED_SRCS) $(INCL) +semaphore.obj: semaphore.c $(SEMAPHORE_SRCS) $(INCL) +spin.obj: spin.c $(SPIN_SRCS) $(INCL) +sync.obj: sync.c $(SYNC_SRCS) $(INCL) +tsd.obj: tsd.c $(TSD_SRCS) $(INCL) +version.res: version.rc $(INCL) diff --git a/libs/pthreads/docs/NEWS b/libs/pthreads/docs/NEWS new file mode 100644 index 0000000000..d1b789635f --- /dev/null +++ b/libs/pthreads/docs/NEWS @@ -0,0 +1,1241 @@ +RELEASE 2.9.0 +------------- +(2012-05-25) + +General +------- +New bug fixes in this release since 2.8.0 have NOT been applied to the +1.x.x series. + +Some changes post 2011-02-26 in CVS may not be compatible with pre +Windows 2000 systems. + +Use of other than the "C" version of the library is now discouraged. +That is, the "C++" version fails some tests and does not provide any +additional functionality. + +Testing and verification +------------------------ +This version has been tested on SMP architecture (Intel x64 Hex Core) +by completing the included test suite, stress and bench tests. + +New Features +------------ +DLL properties now properly includes the target architecture, i.e. +right-click on the file pthreadVC2.dll in explorer and choose the Detail +tab will show the compiler and architecture in the description field, e.g. +"MS C x64" or "MS C x86". +- Ross Johnson + +(MSC and GNU builds) The statically linked library now automatically +initialises and cleans up on program start/exit, i.e. statically linked +applications need not call the routines pthread_win32_process_attach_np() +and pthread_win32_process_detach_np() explicitly. The per-thread routine +pthread_win32_thread_detach_np() is also called at program exit to cleanup +POSIX resources acquired by the primary Windows native thread, if I (RJ) +understand the process correctly. Other Windows native threads that call +POSIX API routines may need to call the thread detach routine on thread +exit if the application depends on reclaimed POSIX resources or running +POSIX TSD (TLS) destructors. +See README.NONPORTABLE for descriptions of these routines. +- Ramiro Polla + +Robust mutexes are implemented within the PROCESS_PRIVATE scope. NOTE that +pthread_mutex_* functions may return different error codes for robust +mutexes than they otherwise do in normal usage, e.g. pthread_mutex_unlock +is required to check ownership for all mutex types when the mutex is +robust, whereas this does not occur for the "normal" non-robust mutex type. +- Ross Johnson + +pthread_getunique_np is implemented for source level compatibility +with some other implementations. This routine returns a 64 bit +sequence number that is uniquely associated with a thread. It can be +used by applications to order or hash POSIX thread handles. +- Ross Johnson + +Bug fixes +--------- +Many more changes for 64 bit systems. +- Kai Tietz + +Various modifications and fixes to build and test for WinCE. +- Marcel Ruff, Sinan Kaya + +Fix pthread_cond_destroy() - should not be a cancellation point. Other +minor build problems fixed. +- Romano Paolo Tenca + +Remove potential deadlock condition from pthread_cond_destroy(). +- Eric Berge + +Various modifications to build and test for Win64. +- Kip Streithorst + +Various fixes to the QueueUserAPCEx async cancellation helper DLL +(this is a separate download) and pthreads code cleanups. +- Sebastian Gottschalk + +Removed potential NULL pointer reference. +- Robert Kindred + +Removed the requirement that applications restrict the number of threads +calling pthread_barrier_wait to just the barrier count. Also reduced the +contention between barrier_wait and barrier_destroy. This change will have +slowed barriers down slightly but halves the number of semaphores consumed +per barrier to one. +- Ross Johnson + +Fixed a handle leak in sched_[gs]etscheduler. +- Mark Pizzolato + +Removed all of the POSIX re-entrant function compatibility macros from pthread.h. +Some were simply not semanticly correct. +- Igor Lubashev + +Threads no longer attempt to pass uncaught exceptions out of thread scope (C++ +and SEH builds only). Uncaught exceptions now cause the thread to exit with +the return code PTHREAD_CANCELED. +- Ross Johnson + +Lots of casting fixes particularly for x64, Interlocked fixes and reworking +for x64. +- Daniel Richard G., John Kamp + +Other changes +------------- +Dependence on the winsock library is now discretionary via +#define RETAIN_WSALASTERROR in config.h. It is undefined by default unless +WINCE is defined (because RJ is unsure of the dependency there). +- Ramiro Polla + +Several static POSIX mutexes used for internal management were replaced by +MCS queue-based locks to reduce resource consumption, in particular use of Win32 +objects. +- Ross Johnson + +For security, the QuserEx.dll if used must now be installed in the Windows System +folder. +- Ross Johnson + +New tests +--------- +robust[1-5].c - Robust mutexes +sequence1.c - per-thread unique sequence numbers + +Modified tests and benchtests +----------------------------- +All mutex*.c tests wherever appropriate have been modified to also test +robust mutexes under the same conditions. +Added robust mutex benchtests to benchtest*.c wherever appropriate. + + +RELEASE 2.8.0 +------------- +(2006-12-22) + +General +------- +New bug fixes in this release since 2.7.0 have not been applied to the +version 1.x.x series. It is probably time to drop version 1. + +Testing and verification +------------------------ +This release has not yet been tested on SMP architechtures. All tests pass +on a uni-processor system. + +Bug fixes +--------- +Sem_destroy could return EBUSY even though no threads were waiting on the +semaphore. Other races around invalidating semaphore structs (internally) +have been removed as well. + +New tests +--------- +semaphore5.c - tests the bug fix referred to above. + + +RELEASE 2.7.0 +------------- +(2005-06-04) + +General +------- +All new features in this release have been back-ported in release 1.11.0, +including the incorporation of MCS locks in pthread_once, however, versions +1 and 2 remain incompatible even though they are now identical in +performance and functionality. + +Testing and verification +------------------------ +This release has been tested (passed the test suite) on both uni-processor +and multi-processor systems. +- Tim Theisen + +Bug fixes +--------- +Pthread_once has been re-implemented to remove priority boosting and other +complexity to improve robustness. Races for Win32 handles that are not +recycle-unique have been removed. The general form of pthread_once is now +the same as that suggested earlier by Alexander Terekhov, but instead of the +'named mutex', a queue-based lock has been implemented which has the required +properties of dynamic self initialisation and destruction. This lock is also +efficient. The ABI is unaffected in as much as the size of pthread_once_t has +not changed and PTHREAD_ONCE_INIT has not changed, however, applications that +peek inside pthread_once_t, which is supposed to be opaque, will break. +- Vladimir Kliatchko + +New features +------------ +* Support for Mingw cross development tools added to GNUmakefile. +Mingw cross tools allow building the libraries on Linux. +- Mikael Magnusson + + +RELEASE 2.6.0 +------------- +(2005-05-19) + +General +------- +All of the bug fixes and new features in this release have been +back-ported in release 1.10.0. + +Testing and verification +------------------------ +This release has been tested (passed the test suite) on both uni-processor +and multi-processor systems. Thanks to Tim Theisen at TomoTherapy for +exhaustively running the MP tests and for providing crutial observations +and data when faults are detected. + +Bugs fixed +---------- + +* pthread_detach() now reclaims remaining thread resources if called after +the target thread has terminated. Previously, this routine did nothing in +this case. + +New tests +--------- + +* detach1.c - tests that pthread_detach properly invalidates the target +thread, which indicates that the thread resources have been reclaimed. + + +RELEASE 2.5.0 +------------- +(2005-05-09) + +General +------- + +The package now includes a reference documentation set consisting of +HTML formatted Unix-style manual pages that have been edited for +consistency with Pthreads-w32. The set can also be read online at: +http://sources.redhat.com/pthreads-win32/manual/index.html + +Thanks again to Tim Theisen for running the test suite pre-release +on an MP system. + +All of the bug fixes and new features in this release have been +back-ported in release 1.9.0. + +Bugs fixed +---------- + +* Thread Specific Data (TSD) key management has been ammended to +eliminate a source of (what was effectively) resource leakage (a HANDLE +plus memory for each key destruct routine/thread association). This was +not a true leak because these resources were eventually reclaimed when +pthread_key_delete was run AND each thread referencing the key had exited. +The problem was that these two conditions are often not met until very +late, and often not until the process is about to exit. + +The ammended implementation avoids the need for the problematic HANDLE +and reclaims the memory as soon as either the key is deleted OR the +thread exits, whichever is first. + +Thanks to Richard Hughes at Aculab for identifying and locating the leak. + +* TSD key destructors are now processed up to PTHREAD_DESTRUCTOR_ITERATIONS +times instead of just once. PTHREAD_DESTRUCTOR_ITERATIONS has been +defined in pthread.h for some time but not used. + +* Fix a semaphore accounting race between sem_post/sem_post_multiple +and sem_wait cancellation. This is the same issue as with +sem_timedwait that was fixed in the last release. + +* sem_init, sem_post, and sem_post_multiple now check that the +semaphore count never exceeds _POSIX_SEM_VALUE_MAX. + +* Although sigwait() is nothing more than a no-op, it should at least +be a cancellation point to be consistent with the standard. + +New tests +--------- + +* stress1.c - attempts to expose problems in condition variable +and semaphore timed wait logic. This test was inspired by Stephan +Mueller's sample test code used to identify the sem_timedwait bug +from the last release. It's not a part of the regular test suite +because it can take awhile to run. To run it: +nmake clean VC-stress + +* tsd2.c - tests that key destructors are re-run if the tsd key value is +not NULL after the destructor routine has run. Also tests that +pthread_setspecific() and pthread_getspecific() are callable from +destructors. + + +RELEASE 2.4.0 +------------- +(2005-04-26) + +General +------- + +There is now no plan to release a version 3.0.0 to fix problems in +pthread_once(). Other possible implementations of pthread_once +will still be investigated for a possible future release in an attempt +to reduce the current implementation's complexity. + +All of the bug fixes and new features in this release have been +back-ported for release 1.8.0. + +Bugs fixed +---------- + +* Fixed pthread_once race (failures on an MP system). Thanks to +Tim Theisen for running exhaustive pre-release testing on his MP system +using a range of compilers: + VC++ 6 + VC++ 7.1 + Intel C++ version 8.0 +All tests passed. +Some minor speed improvements were also done. + +* Fix integer overrun error in pthread_mutex_timedlock() - missed when +sem_timedwait() was fixed in release 2.2.0. This routine no longer returns +ENOTSUP when NEED_SEM is defined - it is supported (NEED_SEM is only +required for WinCE versions prior to 3.0). + +* Fix timeout bug in sem_timedwait(). +- Thanks to Stephan Mueller for reporting, providing diagnostic output +and test code. + +* Fix several problems in the NEED_SEM conditionally included code. +NEED_SEM included code is provided for systems that don't implement W32 +semaphores, such as WinCE prior to version 3.0. An alternate implementation +of POSIX semaphores is built using W32 events for these systems when +NEED_SEM is defined. This code has been completely rewritten in this +release to reuse most of the default POSIX semaphore code, and particularly, +to implement all of the sem_* routines supported by pthreads-win32. Tim +Theisen also run the test suite over the NEED_SEM code on his MP system. All +tests passed. + +* The library now builds without errors for the Borland Builder 5.5 compiler. + +New features +------------ + +* pthread_mutex_timedlock() and all sem_* routines provided by +pthreads-win32 are now implemented for WinCE versions prior to 3.0. Those +versions did not implement W32 semaphores. Define NEED_SEM in config.h when +building the library for these systems. + +Known issues in this release +---------------------------- + +* pthread_once is too complicated - but it works as far as testing can +determine.. + +* The Borland version of the dll fails some of the tests with a memory read +exception. The cause is not yet known but a compiler bug has not been ruled +out. + + +RELEASE 2.3.0 +------------- +(2005-04-12) + +General +------- + +Release 1.7.0 is a backport of features and bug fixes new in +this release. See earlier notes under Release 2.0.0/General. + +Bugs fixed +---------- + +* Fixed pthread_once potential for post once_routine cancellation +hanging due to starvation. See comments in pthread_once.c. +Momentary priority boosting is used to ensure that, after a +once_routine is cancelled, the thread that will run the +once_routine is not starved by higher priority waiting threads at +critical times. Priority boosting occurs only AFTER a once_routine +cancellation, and is applied only to that once_control. The +once_routine is run at the thread's normal base priority. + +New tests +--------- + +* once4.c: Aggressively tests pthread_once() under realtime +conditions using threads with varying priorities. Windows' +random priority boosting does not occur for threads with realtime +priority levels. + + +RELEASE 2.2.0 +------------- +(2005-04-04) + +General +------- + +* Added makefile targets to build static link versions of the library. +Both MinGW and MSVC. Please note that this does not imply any change +to the LGPL licensing, which still imposes psecific conditions on +distributing software that has been statically linked with this library. + +* There is a known bug in pthread_once(). Cancellation of the init_routine +exposes a potential starvation (i.e. deadlock) problem if a waiting thread +has a higher priority than the initting thread. This problem will be fixed +in version 3.0.0 of the library. + +Bugs fixed +---------- + +* Fix integer overrun error in sem_timedwait(). +Kevin Lussier + +* Fix preprocessor directives for static linking. +Dimitar Panayotov + + +RELEASE 2.1.0 +------------- +(2005-03-16) + +Bugs fixed +---------- + +* Reverse change to pthread_setcancelstate() in 2.0.0. + + +RELEASE 2.0.0 +------------- +(2005-03-16) + +General +------- + +This release represents an ABI change and the DLL version naming has +incremented from 1 to 2, e.g. pthreadVC2.dll. + +Version 1.4.0 back-ports the new functionality included in this +release. Please distribute DLLs built from that version with updates +to applications built on pthreads-win32 version 1.x.x. + +The package naming has changed, replacing the snapshot date with +the version number + descriptive information. E.g. this +release is "pthreads-w32-2-0-0-release". + +Bugs fixed +---------- + +* pthread_setcancelstate() no longer checks for a pending +async cancel event if the library is using alertable async +cancel. See the README file (Prerequisites section) for info +on adding alertable async cancelation. + +New features +------------ + +* pthread_once() now supports init_routine cancellability. + +New tests +--------- + +* Agressively test pthread_once() init_routine cancellability. + + +SNAPSHOT 2005-03-08 +------------------- +Version 1.3.0 + +Bug reports (fixed) +------------------- + +* Implicitly created threads leave Win32 handles behind after exiting. +- Dmitrii Semii + +* pthread_once() starvation problem. +- Gottlob Frege + +New tests +--------- + +* More intense testing of pthread_once(). + + +SNAPSHOT 2005-01-25 +------------------- +Version 1.2.0 + +Bug fixes +--------- + +* Attempted acquisition of a recursive mutex could cause waiting threads +to not be woken when the mutex was released. +- Ralf Kubis + +* Various package omissions have been fixed. + + +SNAPSHOT 2005-01-03 +------------------- +Version 1.1.0 + +Bug fixes +--------- + +* Unlocking recursive or errorcheck mutexes would sometimes +unexpectedly return an EPERM error (bug introduced in +snapshot-2004-11-03). +- Konstantin Voronkov + + +SNAPSHOT 2004-11-22 +------------------- +Version 1.0.0 + +This snapshot primarily fixes the condvar bug introduced in +snapshot-2004-11-03. DLL versioning has also been included to allow +applications to runtime check the Microsoft compatible DLL version +information, and to extend the DLL naming system for ABI and major +(non-backward compatible) API changes. See the README file for details. + +Bug fixes +--------- + +* Condition variables no longer deadlock (bug introduced in +snapshot-2004-11-03). +- Alexander Kotliarov and Nicolas at saintmac + +* DLL naming extended to avoid 'DLL hell' in the future, and to +accommodate the ABI change introduced in snapshot-2004-11-03. Snapshot +2004-11-03 will be removed from FTP sites. + +New features +------------ + +* A Microsoft-style version resource has been added to the DLL for +applications that wish to check DLL compatibility at runtime. + +* Pthreads-win32 DLL naming has been extended to allow incompatible DLL +versions to co-exist in the same filesystem. See the README file for details, +but briefly: while the version information inside the DLL will change with +each release from now on, the DLL version names will only change if the new +DLL is not backward compatible with older applications. + +The versioning scheme has been borrowed from GNU Libtool, and the DLL +naming scheme is from Cygwin. Provided the Libtool-style numbering rules are +honoured, the Cygwin DLL naming scheme automatcally ensures that DLL name +changes are minimal and that applications will not load an incompatible +pthreads-win32 DLL. + +Those who use the pre-built DLLs will find that the DLL/LIB names have a new +suffix (1) in this snapshot. E.g. pthreadVC1.dll etc. + +* The POSIX thread ID reuse uniqueness feature introduced in the last snapshot +has been kept as default, but the behaviour can now be controlled when the DLL +is built to effectively switch it off. This makes the library much more +sensitive to applications that assume that POSIX thread IDs are unique, i.e. +are not strictly compliant with POSIX. See the PTW32_THREAD_ID_REUSE_INCREMENT +macro comments in config.h for details. + +Other changes +------------- +Certain POSIX macros have changed. + +These changes are intended to conform to the Single Unix Specification version 3, +which states that, if set to 0 (zero) or not defined, then applications may use +sysconf() to determine their values at runtime. Pthreads-win32 does not +implement sysconf(). + +The following macros are no longer undefined, but defined and set to -1 +(not implemented): + + _POSIX_THREAD_ATTR_STACKADDR + _POSIX_THREAD_PRIO_INHERIT + _POSIX_THREAD_PRIO_PROTECT + _POSIX_THREAD_PROCESS_SHARED + +The following macros are defined and set to 200112L (implemented): + + _POSIX_THREADS + _POSIX_THREAD_SAFE_FUNCTIONS + _POSIX_THREAD_ATTR_STACKSIZE + _POSIX_THREAD_PRIORITY_SCHEDULING + _POSIX_SEMAPHORES + _POSIX_READER_WRITER_LOCKS + _POSIX_SPIN_LOCKS + _POSIX_BARRIERS + +The following macros are defined and set to appropriate values: + + _POSIX_THREAD_THREADS_MAX + _POSIX_SEM_VALUE_MAX + _POSIX_SEM_NSEMS_MAX + PTHREAD_DESTRUCTOR_ITERATIONS + PTHREAD_KEYS_MAX + PTHREAD_STACK_MIN + PTHREAD_THREADS_MAX + + +SNAPSHOT 2004-11-03 +------------------- + +DLLs produced from this snapshot cannot be used with older applications without +recompiling the application, due to a change to pthread_t to provide unique POSIX +thread IDs. + +Although this snapshot passes the extended test suite, many of the changes are +fairly major, and some applications may show different behaviour than previously, +so adopt with care. Hopefully, any changed behaviour will be due to the library +being better at it's job, not worse. + +Bug fixes +--------- + +* pthread_create() no longer accepts NULL as the thread reference arg. +A segfault (memory access fault) will result, and no thread will be +created. + +* pthread_barrier_wait() no longer acts as a cancelation point. + +* Fix potential race condition in pthread_once() +- Tristan Savatier + +* Changes to pthread_cond_destroy() exposed some coding weaknesses in several +test suite mini-apps because pthread_cond_destroy() now returns EBUSY if the CV +is still in use. + +New features +------------ + +* Added for compatibility: +PTHREAD_RECURSIVE_MUTEX_INITIALIZER, +PTHREAD_ERRORCHECK_MUTEX_INITIALIZER, +PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, +PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP + +* Initial support for Digital Mars compiler +- Anuj Goyal + +* Faster Mutexes. These have been been rewritten following a model provided by +Alexander Terekhov that reduces kernel space checks, and eliminates some additional +critical sections used to manage a race between timedlock expiration and unlock. +Please be aware that the new mutexes do not enforce strict absolute FIFO scheduling +of mutexes, however any out-of-order lock acquisition should be very rare. + +* Faster semaphores. Following a similar model to mutexes above, these have been +rewritten to use preliminary users space checks. + +* sem_getvalue() now returns the number of waiters. + +* The POSIX thread ID now has much stronger uniqueness characteristics. The library +garrantees not to reuse the same thread ID for at least 2^(wordsize) thread +destruction/creation cycles. + +New tests +--------- + +* semaphore4.c: Tests cancelation of the new sem_wait(). + +* semaphore4t.c: Likewise for sem_timedwait(). + +* rwlock8.c: Tests and times the slow execution paths of r/w locks, and the CVs, +mutexes, and semaphores that they're built on. + + +SNAPSHOT 2004-05-16 +------------------- + +Attempt to add Watcom to the list of compilers that can build the library. +This failed in the end due to it's non-thread-aware errno. The library +builds but the test suite fails. See README.Watcom for more details. + +Bug fixes +--------- +* Bug and memory leak in sem_init() +- Alex Blanco + +* ptw32_getprocessors() now returns CPU count of 1 for WinCE. +- James Ewing + +* pthread_cond_wait() could be canceled at a point where it should not +be cancelable. Fixed. +- Alexander Terekhov + +* sem_timedwait() had an incorrect timeout calculation. +- Philippe Di Cristo + +* Fix a memory leak left behind after threads are destroyed. +- P. van Bruggen + +New features +------------ +* Ported to AMD64. +- Makoto Kato + +* True pre-emptive asynchronous cancelation of threads. This is optional +and requires that Panagiotis E. Hadjidoukas's QueueUserAPCEx package be +installed. This package is included in the pthreads-win32 self-unpacking +Zip archive starting from this snapshot. See the README.txt file inside +the package for installation details. + +Note: If you don't use async cancelation in your application, or don't need +to cancel threads that are blocked on system resources such as network I/O, +then the default non-preemptive async cancelation is probably good enough. +However, pthreads-win32 auto-detects the availability of these components +at run-time, so you don't need to rebuild the library from source if you +change your mind later. + +All of the advice available in books and elsewhere on the undesirability +of using async cancelation in any application still stands, but this +feature is a welcome addition with respect to the library's conformance to +the POSIX standard. + +SNAPSHOT 2003-09-18 +------------------- + +Cleanup of thread priority management. In particular, setting of thread +priority now attempts to map invalid Win32 values within the range returned +by sched_get_priority_min/max() to useful values. See README.NONPORTABLE +under "Thread priority". + +Bug fixes +--------- +* pthread_getschedparam() now returns the priority given by the most recent +call to pthread_setschedparam() or established by pthread_create(), as +required by the standard. Previously, pthread_getschedparam() incorrectly +returned the running thread priority at the time of the call, which may have +been adjusted or temporarily promoted/demoted. + +* sched_get_priority_min() and sched_get_priority_max() now return -1 on error +and set errno. Previously, they incorrectly returned the error value directly. + + +SNAPSHOT 2003-09-04 +------------------- + +Bug fixes +--------- +* ptw32_cancelableWait() now allows cancelation of waiting implicit POSIX +threads. + +New test +-------- +* cancel8.c tests cancelation of Win32 threads waiting at a POSIX cancelation +point. + + +SNAPSHOT 2003-09-03 +------------------- + +Bug fixes +--------- +* pthread_self() would free the newly created implicit POSIX thread handle if +DuplicateHandle failed instead of recycle it (very unlikely). + +* pthread_exit() was neither freeing nor recycling the POSIX thread struct +for implicit POSIX threads. + +New feature - Cancelation of/by Win32 (non-POSIX) threads +--------------------------------------------------------- +Since John Bossom's original implementation, the library has allowed non-POSIX +initialised threads (Win32 threads) to call pthreads-win32 routines and +therefore interact with POSIX threads. This is done by creating an on-the-fly +POSIX thread ID for the Win32 thread that, once created, allows fully +reciprical interaction. This did not extend to thread cancelation (async or +deferred). Now it does. + +Any thread can be canceled by any other thread (Win32 or POSIX) if the former +thread's POSIX pthread_t value is known. It's TSD destructors and POSIX +cleanup handlers will be run before the thread exits with an exit code of +PTHREAD_CANCELED (retrieved with GetExitCodeThread()). + +This allows a Win32 thread to, for example, call POSIX CV routines in the same way +that POSIX threads would/should, with pthread_cond_wait() cancelability and +cleanup handlers (pthread_cond_wait() is a POSIX cancelation point). + +By adding cancelation, Win32 threads should now be able to call all POSIX +threads routines that make sense including semaphores, mutexes, condition +variables, read/write locks, barriers, spinlocks, tsd, cleanup push/pop, +cancelation, pthread_exit, scheduling, etc. + +Note that these on-the-fly 'implicit' POSIX thread IDs are initialised as detached +(not joinable) with deferred cancelation type. The POSIX thread ID will be created +automatically by any POSIX routines that need a POSIX handle (unless the routine +needs a pthread_t as a parameter of course). A Win32 thread can discover it's own +POSIX thread ID by calling pthread_self(), which will create the handle if +necessary and return the pthread_t value. + +New tests +--------- +Test the above new feature. + + +SNAPSHOT 2003-08-19 +------------------- + +This snapshot fixes some accidental corruption to new test case sources. +There are no changes to the library source code. + + +SNAPSHOT 2003-08-15 +------------------- + +Bug fixes +--------- + +* pthread.dsp now uses correct compile flags (/MD). +- Viv + +* pthread_win32_process_detach_np() fixed memory leak. +- Steven Reddie + +* pthread_mutex_destroy() fixed incorrect return code. +- Nicolas Barry + +* pthread_spin_destroy() fixed memory leak. +- Piet van Bruggen + +* Various changes to tighten arg checking, and to work with later versions of +MinGW32 and MsysDTK. + +* pthread_getschedparam() etc, fixed dangerous thread validity checking. +- Nicolas Barry + +* POSIX thread handles are now reused and their memory is not freed on thread exit. +This allows for stronger thread validity checking. + +New standard routine +-------------------- + +* pthread_kill() added to provide thread validity checking to applications. +It does not accept any non zero values for the signal arg. + +New test cases +-------------- + +* New test cases to confirm validity checking, pthread_kill(), and thread reuse. + + +SNAPSHOT 2003-05-10 +------------------- + +Bug fixes +--------- + +* pthread_mutex_trylock() now returns correct error values. +pthread_mutex_destroy() will no longer destroy a recursively locked mutex. +pthread_mutex_lock() is no longer inadvertantly behaving as a cancelation point. +- Thomas Pfaff + +* pthread_mutex_timedlock() no longer occasionally sets incorrect mutex +ownership, causing deadlocks in some applications. +- Robert Strycek and Alexander Terekhov + + +SNAPSHOT 2002-11-04 +------------------- + +Bug fixes +--------- + +* sem_getvalue() now returns the correct value under Win NT and WinCE. +- Rob Fanner + +* sem_timedwait() now uses tighter checks for unreasonable +abstime values - that would result in unexpected timeout values. + +* ptw32_cond_wait_cleanup() no longer mysteriously consumes +CV signals but may produce more spurious wakeups. It is believed +that the sem_timedwait() call is consuming a CV signal that it +shouldn't. +- Alexander Terekhov + +* Fixed a memory leak in ptw32_threadDestroy() for implicit threads. + +* Fixed potential for deadlock in pthread_cond_destroy(). +A deadlock could occur for statically declared CVs (PTHREAD_COND_INITIALIZER), +when one thread is attempting to destroy the condition variable while another +is attempting to dynamically initialize it. +- Michael Johnson + + +SNAPSHOT 2002-03-02 +------------------- + +Cleanup code default style. (IMPORTANT) +---------------------------------------------------------------------- +Previously, if not defined, the cleanup style was determined automatically +from the compiler/language, and one of the following was defined accordingly: + + __CLEANUP_SEH MSVC only + __CLEANUP_CXX C++, including MSVC++, GNU G++ + __CLEANUP_C C, including GNU GCC, not MSVC + +These defines determine the style of cleanup (see pthread.h) and, +most importantly, the way that cancelation and thread exit (via +pthread_exit) is performed (see the routine ptw32_throw() in private.c). + +In short, the exceptions versions of the library throw an exception +when a thread is canceled or exits (via pthread_exit()), which is +caught by a handler in the thread startup routine, so that the +the correct stack unwinding occurs regardless of where the thread +is when it's canceled or exits via pthread_exit(). + +In this and future snapshots, unless the build explicitly defines (e.g. +via a compiler option) __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then +the build NOW always defaults to __CLEANUP_C style cleanup. This style +uses setjmp/longjmp in the cancelation and pthread_exit implementations, +and therefore won't do stack unwinding even when linked to applications +that have it (e.g. C++ apps). This is for consistency with most +current commercial Unix POSIX threads implementations. Compaq's TRU64 +may be an exception (no pun intended) and possible future trend. + +Although it was not clearly documented before, it is still necessary to +build your application using the same __CLEANUP_* define as was +used for the version of the library that you link with, so that the +correct parts of pthread.h are included. That is, the possible +defines require the following library versions: + + __CLEANUP_SEH pthreadVSE.dll + __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll + __CLEANUP_C pthreadVC.dll or pthreadGC.dll + +E.g. regardless of whether your app is C or C++, if you link with +pthreadVC.lib or libpthreadGC.a, then you must define __CLEANUP_C. + + +THE POINT OF ALL THIS IS: if you have not been defining one of these +explicitly, then the defaults as described at the top of this +section were being used. + +THIS NOW CHANGES, as has been explained above, but to try to make this +clearer here's an example: + +If you were building your application with MSVC++ i.e. using C++ +exceptions and not explicitly defining one of __CLEANUP_*, then +__CLEANUP_C++ was automatically defined for you in pthread.h. +You should have been linking with pthreadVCE.dll, which does +stack unwinding. + +If you now build your application as you had before, pthread.h will now +automatically set __CLEANUP_C as the default style, and you will need to +link with pthreadVC.dll. Stack unwinding will now NOT occur when a thread +is canceled, or the thread calls pthread_exit(). + +Your application will now most likely behave differently to previous +versions, and in non-obvious ways. Most likely is that locally +instantiated objects may not be destroyed or cleaned up after a thread +is canceled. + +If you want the same behaviour as before, then you must now define +__CLEANUP_C++ explicitly using a compiler option and link with +pthreadVCE.dll as you did before. + + +WHY ARE WE MAKING THE DEFAULT STYLE LESS EXCEPTION-FRIENDLY? +Because no commercial Unix POSIX threads implementation allows you to +choose to have stack unwinding. Therefore, providing it in pthread-win32 +as a default is dangerous. We still provide the choice but unless +you consciously choose to do otherwise, your pthreads applications will +now run or crash in similar ways irrespective of the threads platform +you use. Or at least this is the hope. + + +WHY NOT REMOVE THE EXCEPTIONS VERSIONS OF THE LIBRARY ALTOGETHER? +There are a few reasons: +- because there are well respected POSIX threads people who believe + that POSIX threads implementations should be exceptions aware and + do the expected thing in that context. (There are equally respected + people who believe it should not be easily accessible, if it's there + at all, for unconditional conformity to other implementations.) +- because pthreads-win32 is one of the few implementations that has + the choice, perhaps the only freely available one, and so offers + a laboratory to people who may want to explore the effects; +- although the code will always be around somewhere for anyone who + wants it, once it's removed from the current version it will not be + nearly as visible to people who may have a use for it. + + +Source module splitting +----------------------- +In order to enable smaller image sizes to be generated +for applications that link statically with the library, +most routines have been separated out into individual +source code files. + +This is being done in such a way as to be backward compatible. +The old source files are reused to congregate the individual +routine files into larger translation units (via a bunch of +# includes) so that the compiler can still optimise wherever +possible, e.g. through inlining, which can only be done +within the same translation unit. + +It is also possible to build the entire library by compiling +the single file named "pthread.c", which just #includes all +the secondary congregation source files. The compiler +may be able to use this to do more inlining of routines. + +Although the GNU compiler is able to produce libraries with +the necessary separation (the -ffunction-segments switch), +AFAIK, the MSVC and other compilers don't have this feature. + +Finally, since I use makefiles and command-line compilation, +I don't know what havoc this reorganisation may wreak amongst +IDE project file users. You should be able to continue +using your existing project files without modification. + + +New non-portable functions +-------------------------- +pthread_num_processors_np(): + Returns the number of processors in the system that are + available to the process, as determined from the processor + affinity mask. + +pthread_timechange_handler_np(): + To improve tolerance against operator or time service initiated + system clock changes. + + This routine can be called by an application when it + receives a WM_TIMECHANGE message from the system. At present + it broadcasts all condition variables so that waiting threads + can wake up and re-evaluate their conditions and restart + their timed waits if required. + - Suggested by Alexander Terekhov + + +Platform dependence +------------------- +As Win95 doesn't provide one, the library now contains +it's own InterlockedCompareExchange() routine, which is used +whenever Windows doesn't provide it. InterlockedCompareExchange() +is used to implement spinlocks and barriers, and also in mutexes. +This routine relies on the CMPXCHG machine instruction which +is not available on i386 CPUs. This library (from snapshot +20010712 onwards) is therefore no longer supported on i386 +processor platforms. + + +New standard routines +--------------------- +For source code portability only - rwlocks cannot be process shared yet. + + pthread_rwlockattr_init() + pthread_rwlockattr_destroy() + pthread_rwlockattr_setpshared() + pthread_rwlockattr_getpshared() + +As defined in the new POSIX standard, and the Single Unix Spec version 3: + + sem_timedwait() + pthread_mutex_timedlock() - Alexander Terekhov and Thomas Pfaff + pthread_rwlock_timedrdlock() - adapted from pthread_rwlock_rdlock() + pthread_rwlock_timedwrlock() - adapted from pthread_rwlock_wrlock() + + +pthread.h no longer includes windows.h +-------------------------------------- +[Not yet for G++] + +This was done to prevent conflicts. + +HANDLE, DWORD, and NULL are temporarily defined within pthread.h if +they are not already. + + +pthread.h, sched.h and semaphore.h now use dllexport/dllimport +-------------------------------------------------------------- +Not only to avoid the need for the pthread.def file, but to +improve performance. Apparently, declaring functions with dllimport +generates a direct call to the function and avoids the overhead +of a stub function call. + +Bug fixes +--------- +* Fixed potential NULL pointer dereferences in pthread_mutexattr_init, +pthread_mutexattr_getpshared, pthread_barrierattr_init, +pthread_barrierattr_getpshared, and pthread_condattr_getpshared. +- Scott McCaskill + +* Removed potential race condition in pthread_mutex_trylock and +pthread_mutex_lock; +- Alexander Terekhov + +* The behaviour of pthread_mutex_trylock in relation to +recursive mutexes was inconsistent with commercial implementations. +Trylock would return EBUSY if the lock was owned already by the +calling thread regardless of mutex type. Trylock now increments the +recursion count and returns 0 for RECURSIVE mutexes, and will +return EDEADLK rather than EBUSY for ERRORCHECK mutexes. This is +consistent with Solaris. +- Thomas Pfaff + +* Found a fix for the library and workaround for applications for +the known bug #2, i.e. where __CLEANUP_CXX or __CLEANUP_SEH is defined. +See the "Known Bugs in this snapshot" section below. + +This could be made transparent to applications by replacing the macros that +define the current C++ and SEH versions of pthread_cleanup_push/pop +with the C version, but AFAIK cleanup handlers would not then run in the +correct sequence with destructors and exception cleanup handlers when +an exception occurs. + +* Cancelation once started in a thread cannot now be inadvertantly +double canceled. That is, once a thread begins it's cancelation run, +cancelation is disabled and a subsequent cancel request will +return an error (ESRCH). + +* errno: An incorrect compiler directive caused a local version +of errno to be used instead of the Win32 errno. Both instances are +thread-safe but applications checking errno after a pthreads-win32 +call would be wrong. Fixing this also fixed a bad compiler +option in the testsuite (/MT should have been /MD) which is +needed to link with the correct library MSVCRT.LIB. + + +SNAPSHOT 2001-07-12 +------------------- + +To be added + + +SNAPSHOT 2001-07-03 +------------------- + +To be added + + +SNAPSHOT 2000-08-13 +------------------- + +New: +- Renamed DLL and LIB files: + pthreadVSE.dll (MS VC++/Structured EH) + pthreadVSE.lib + pthreadVCE.dll (MS VC++/C++ EH) + pthreadVCE.lib + pthreadGCE.dll (GNU G++/C++ EH) + libpthreadw32.a + + Both your application and the pthread dll should use the + same exception handling scheme. + +Bugs fixed: +- MSVC++ C++ exception handling. + +Some new tests have been added. + + +SNAPSHOT 2000-08-10 +------------------- + +New: +- asynchronous cancelation on X86 (Jason Nye) +- Makefile compatible with MS nmake to replace + buildlib.bat +- GNUmakefile for Mingw32 +- tests/Makefile for MS nmake replaces runall.bat +- tests/GNUmakefile for Mingw32 + +Bugs fixed: +- kernel32 load/free problem +- attempt to hide internel exceptions from application + exception handlers (__try/__except and try/catch blocks) +- Win32 thread handle leakage bug + (David Baggett/Paul Redondo/Eyal Lebedinsky) + +Some new tests have been added. + + +SNAPSHOT 1999-11-02 +------------------- + +Bugs fixed: +- ctime_r macro had an incorrect argument (Erik Hensema), +- threads were not being created + PTHREAD_CANCEL_DEFERRED. This should have + had little effect as deferred is the only + supported type. (Ross Johnson). + +Some compatibility improvements added, eg. +- pthread_setcancelstate accepts NULL pointer + for the previous value argument. Ditto for + pthread_setcanceltype. This is compatible + with Solaris but should not affect + standard applications (Erik Hensema) + +Some new tests have been added. + + +SNAPSHOT 1999-10-17 +------------------- + +Bug fix - Cancelation of threads waiting on condition variables +now works properly (Lorin Hochstein and Peter Slacik) + + +SNAPSHOT 1999-08-12 +------------------- + +Fixed exception stack cleanup if calling pthread_exit() +- (Lorin Hochstein and John Bossom). + +Fixed bugs in condition variables - (Peter Slacik): + - additional contention checks + - properly adjust number of waiting threads after timed + condvar timeout. + + +SNAPSHOT 1999-05-30 +------------------- + +Some minor bugs have been fixed. See the ChangeLog file for details. + +Some more POSIX 1b functions are now included but ony return an +error (ENOSYS) if called. They are: + + sem_open + sem_close + sem_unlink + sem_getvalue + + +SNAPSHOT 1999-04-07 +------------------- + +Some POSIX 1b functions which were internally supported are now +available as exported functions: + + sem_init + sem_destroy + sem_wait + sem_trywait + sem_post + sched_yield + sched_get_priority_min + sched_get_priority_max + +Some minor bugs have been fixed. See the ChangeLog file for details. + + +SNAPSHOT 1999-03-16 +------------------- + +Initial release. + diff --git a/libs/pthreads/docs/Nmakefile b/libs/pthreads/docs/Nmakefile new file mode 100644 index 0000000000..d9e5bf1bc7 --- /dev/null +++ b/libs/pthreads/docs/Nmakefile @@ -0,0 +1,24 @@ +/* + * nmake file for uwin pthread library + */ + +VERSION = - +CCFLAGS = -V -g $(CC.DLL) +HAVE_PTW32_CONFIG_H == 1 +_MT == 1 +_timeb == timeb +_ftime == ftime +_errno == _ast_errno + +$(INCLUDEDIR) :INSTALLDIR: pthread.h sched.h + +pthread $(VERSION) :LIBRARY: attr.c barrier.c cancel.c cleanup.c condvar.c \ + create.c dll.c exit.c fork.c global.c misc.c mutex.c private.c \ + rwlock.c sched.c semaphore.c spin.c sync.c tsd.c nonportable.c + +:: ANNOUNCE CONTRIBUTORS COPYING.LIB ChangeLog FAQ GNUmakefile MAINTAINERS \ + Makefile Makefile.in Makefile.vc NEWS PROGRESS README README.WinCE \ + TODO WinCE-PORT install-sh errno.c tests tests.mk acconfig.h \ + config.guess config.h.in config.sub configure configure.in signal.c \ + README.CV README.NONPORTABLE pthread.dsp pthread.dsw + diff --git a/libs/pthreads/docs/PROGRESS b/libs/pthreads/docs/PROGRESS new file mode 100644 index 0000000000..9abf0bca47 --- /dev/null +++ b/libs/pthreads/docs/PROGRESS @@ -0,0 +1,4 @@ +Please see the ANNOUNCE file "Level of Standards Conformance" +or the web page: + +http://sources.redhat.com/pthreads-win32/conformance.html diff --git a/libs/pthreads/docs/README b/libs/pthreads/docs/README new file mode 100644 index 0000000000..545360bfa7 --- /dev/null +++ b/libs/pthreads/docs/README @@ -0,0 +1,601 @@ +PTHREADS-WIN32 +============== + +Pthreads-win32 is free software, distributed under the GNU Lesser +General Public License (LGPL). See the file 'COPYING.LIB' for terms +and conditions. Also see the file 'COPYING' for information +specific to pthreads-win32, copyrights and the LGPL. + + +What is it? +----------- + +Pthreads-win32 is an Open Source Software implementation of the +Threads component of the POSIX 1003.1c 1995 Standard (or later) +for Microsoft's Win32 environment. Some functions from POSIX +1003.1b are also supported including semaphores. Other related +functions include the set of read-write lock functions. The +library also supports some of the functionality of the Open +Group's Single Unix specification, version 2, namely mutex types, +plus some common and pthreads-win32 specific non-portable +routines (see README.NONPORTABLE). + +See the file "ANNOUNCE" for more information including standards +conformance details and the list of supported and unsupported +routines. + + +Prerequisites +------------- +MSVC or GNU C (MinGW32 MSys development kit) + To build from source. + +QueueUserAPCEx by Panagiotis E. Hadjidoukas + To support any thread cancelation in C++ library builds or + to support cancelation of blocked threads in any build. + This library is not required otherwise. + + For true async cancelation of threads (including blocked threads). + This is a DLL and Windows driver that provides pre-emptive APC + by forcing threads into an alertable state when the APC is queued. + Both the DLL and driver are provided with the pthreads-win32.exe + self-unpacking ZIP, and on the pthreads-win32 FTP site (in source + and pre-built forms). Currently this is a separate LGPL package to + pthreads-win32. See the README in the QueueUserAPCEx folder for + installation instructions. + + Pthreads-win32 will automatically detect if the QueueUserAPCEx DLL + QuserEx.DLL is available and whether the driver AlertDrv.sys is + loaded. If it is not available, pthreads-win32 will simulate async + cancelation, which means that it can async cancel only threads that + are runnable. The simulated async cancellation cannot cancel blocked + threads. + + [FOR SECURITY] To be found Quserex.dll MUST be installed in the + Windows System Folder. This is not an unreasonable constraint given a + driver must also be installed and loaded at system startup. + + +Library naming +-------------- + +Because the library is being built using various exception +handling schemes and compilers - and because the library +may not work reliably if these are mixed in an application, +each different version of the library has it's own name. + +Note 1: the incompatibility is really between EH implementations +of the different compilers. It should be possible to use the +standard C version from either compiler with C++ applications +built with a different compiler. If you use an EH version of +the library, then you must use the same compiler for the +application. This is another complication and dependency that +can be avoided by using only the standard C library version. + +Note 2: if you use a standard C pthread*.dll with a C++ +application, then any functions that you define that are +intended to be called via pthread_cleanup_push() must be +__cdecl. + +Note 3: the intention was to also name either the VC or GC +version (it should be arbitrary) as pthread.dll, including +pthread.lib and libpthread.a as appropriate. This is no longer +likely to happen. + +Note 4: the compatibility number was added so that applications +can differentiate between binary incompatible versions of the +libs and dlls. + +In general: + pthread[VG]{SE,CE,C}[c].dll + pthread[VG]{SE,CE,C}[c].lib + +where: + [VG] indicates the compiler + V - MS VC, or + G - GNU C + + {SE,CE,C} indicates the exception handling scheme + SE - Structured EH, or + CE - C++ EH, or + C - no exceptions - uses setjmp/longjmp + + c - DLL compatibility number indicating ABI and API + compatibility with applications built against + a snapshot with the same compatibility number. + See 'Version numbering' below. + +The name may also be suffixed by a 'd' to indicate a debugging version +of the library. E.g. pthreadVC2d.lib. Debugging versions contain +additional information for debugging (symbols etc) and are often not +optimised in any way (compiled with optimisation turned off). + +Examples: + pthreadVSE.dll (MSVC/SEH) + pthreadGCE.dll (GNUC/C++ EH) + pthreadGC.dll (GNUC/not dependent on exceptions) + pthreadVC1.dll (MSVC/not dependent on exceptions - not binary + compatible with pthreadVC.dll) + pthreadVC2.dll (MSVC/not dependent on exceptions - not binary + compatible with pthreadVC1.dll or pthreadVC.dll) + +The GNU library archive file names have correspondingly changed to: + + libpthreadGCEc.a + libpthreadGCc.a + + +Versioning numbering +-------------------- + +Version numbering is separate from the snapshot dating system, and +is the canonical version identification system embedded within the +DLL using the Microsoft version resource system. The versioning +system chosen follows the GNU Libtool system. See +http://www.gnu.org/software/libtool/manual.html section 6.2. + +See the resource file 'version.rc'. + +Microsoft version numbers use 4 integers: + + 0.0.0.0 + +Pthreads-win32 uses the first 3 following the Libtool convention. +The fourth is commonly used for the build number, but will be reserved +for future use. + + current.revision.age.0 + +The numbers are changed as follows: + +1. If the library source code has changed at all since the last update, + then increment revision (`c:r:a' becomes `c:r+1:a'). +2. If any interfaces have been added, removed, or changed since the last + update, increment current, and set revision to 0. +3. If any interfaces have been added since the last public release, then + increment age. +4. If any interfaces have been removed or changed since the last public + release, then set age to 0. + + +DLL compatibility numbering is an attempt to ensure that applications +always load a compatible pthreads-win32 DLL by using a DLL naming system +that is consistent with the version numbering system. It also allows +older and newer DLLs to coexist in the same filesystem so that older +applications can continue to be used. For pre .NET Windows systems, +this inevitably requires incompatible versions of the same DLLs to have +different names. + +Pthreads-win32 has adopted the Cygwin convention of appending a single +integer number to the DLL name. The number used is based on the library +version number and is computed as 'current' - 'age'. + +(See http://home.att.net/~perlspinr/libversioning.html for a nicely +detailed explanation.) + +Using this method, DLL name/s will only change when the DLL's +backwards compatibility changes. Note that the addition of new +'interfaces' will not of itself change the DLL's compatibility for older +applications. + + +Which of the several dll versions to use? +----------------------------------------- +or, +--- +What are all these pthread*.dll and pthread*.lib files? +------------------------------------------------------- + +Simple, use either pthreadGCv.* if you use GCC, or pthreadVCv.* if you +use MSVC - where 'v' is the DLL versioning (compatibility) number. + +Otherwise, you need to choose carefully and know WHY. + +The most important choice you need to make is whether to use a +version that uses exceptions internally, or not. There are versions +of the library that use exceptions as part of the thread +cancelation and exit implementation. The default version uses +setjmp/longjmp. + +There is some contension amongst POSIX threads experts as +to how POSIX threads cancelation and exit should work +with languages that use exceptions, e.g. C++ and even C +(Microsoft's Structured Exceptions). + +The issue is: should cancelation of a thread in, say, +a C++ application cause object destructors and C++ exception +handlers to be invoked as the stack unwinds during thread +exit, or not? + +There seems to be more opinion in favour of using the +standard C version of the library (no EH) with C++ applications +for the reason that this appears to be the assumption commercial +pthreads implementations make. Therefore, if you use an EH version +of pthreads-win32 then you may be under the illusion that +your application will be portable, when in fact it is likely to +behave differently when linked with other pthreads libraries. + +Now you may be asking: then why have you kept the EH versions of +the library? + +There are a couple of reasons: +- there is division amongst the experts and so the code may + be needed in the future. Yes, it's in the repository and we + can get it out anytime in the future, but it would be difficult + to find. +- pthreads-win32 is one of the few implementations, and possibly + the only freely available one, that has EH versions. It may be + useful to people who want to play with or study application + behaviour under these conditions. + +Notes: + +[If you use either pthreadVCE or pthreadGCE] + +1. [See also the discussion in the FAQ file - Q2, Q4, and Q5] + +If your application contains catch(...) blocks in your POSIX +threads then you will need to replace the "catch(...)" with the macro +"PtW32Catch", eg. + + #ifdef PtW32Catch + PtW32Catch { + ... + } + #else + catch(...) { + ... + } + #endif + +Otherwise neither pthreads cancelation nor pthread_exit() will work +reliably when using versions of the library that use C++ exceptions +for cancelation and thread exit. + +This is due to what is believed to be a C++ compliance error in VC++ +whereby you may not have multiple handlers for the same exception in +the same try/catch block. GNU G++ doesn't have this restriction. + + +Other name changes +------------------ + +All snapshots prior to and including snapshot 2000-08-13 +used "_pthread_" as the prefix to library internal +functions, and "_PTHREAD_" to many library internal +macros. These have now been changed to "ptw32_" and "PTW32_" +respectively so as to not conflict with the ANSI standard's +reservation of identifiers beginning with "_" and "__" for +use by compiler implementations only. + +If you have written any applications and you are linking +statically with the pthreads-win32 library then you may have +included a call to _pthread_processInitialize. You will +now have to change that to ptw32_processInitialize. + + +Cleanup code default style +-------------------------- + +Previously, if not defined, the cleanup style was determined automatically +from the compiler used, and one of the following was defined accordingly: + + __CLEANUP_SEH MSVC only + __CLEANUP_CXX C++, including MSVC++, GNU G++ + __CLEANUP_C C, including GNU GCC, not MSVC + +These defines determine the style of cleanup (see pthread.h) and, +most importantly, the way that cancelation and thread exit (via +pthread_exit) is performed (see the routine ptw32_throw()). + +In short, the exceptions versions of the library throw an exception +when a thread is canceled, or exits via pthread_exit(). This exception is +caught by a handler in the thread startup routine, so that the +the correct stack unwinding occurs regardless of where the thread +is when it's canceled or exits via pthread_exit(). + +In this snapshot, unless the build explicitly defines (e.g. via a +compiler option) __CLEANUP_SEH, __CLEANUP_CXX, or __CLEANUP_C, then +the build NOW always defaults to __CLEANUP_C style cleanup. This style +uses setjmp/longjmp in the cancelation and pthread_exit implementations, +and therefore won't do stack unwinding even when linked to applications +that have it (e.g. C++ apps). This is for consistency with most/all +commercial Unix POSIX threads implementations. + +Although it was not clearly documented before, it is still necessary to +build your application using the same __CLEANUP_* define as was +used for the version of the library that you link with, so that the +correct parts of pthread.h are included. That is, the possible +defines require the following library versions: + + __CLEANUP_SEH pthreadVSE.dll + __CLEANUP_CXX pthreadVCE.dll or pthreadGCE.dll + __CLEANUP_C pthreadVC.dll or pthreadGC.dll + +It is recommended that you let pthread.h use it's default __CLEANUP_C +for both library and application builds. That is, don't define any of +the above, and then link with pthreadVC.lib (MSVC or MSVC++) and +libpthreadGC.a (MinGW GCC or G++). The reason is explained below, but +another reason is that the prebuilt pthreadVCE.dll is currently broken. +Versions built with MSVC++ later than version 6 may not be broken, but I +can't verify this yet. + +WHY ARE WE MAKING THE DEFAULT STYLE LESS EXCEPTION-FRIENDLY? +Because no commercial Unix POSIX threads implementation allows you to +choose to have stack unwinding. Therefore, providing it in pthread-win32 +as a default is dangerous. We still provide the choice but unless +you consciously choose to do otherwise, your pthreads applications will +now run or crash in similar ways irrespective of the pthreads platform +you use. Or at least this is the hope. + + +Building under VC++ using C++ EH, Structured EH, or just C +---------------------------------------------------------- + +From the source directory run nmake without any arguments to list +help information. E.g. + +$ nmake + +Microsoft (R) Program Maintenance Utility Version 6.00.8168.0 +Copyright (C) Microsoft Corp 1988-1998. All rights reserved. + +Run one of the following command lines: +nmake clean VCE (to build the MSVC dll with C++ exception handling) +nmake clean VSE (to build the MSVC dll with structured exception handling) +nmake clean VC (to build the MSVC dll with C cleanup code) +nmake clean VCE-inlined (to build the MSVC inlined dll with C++ exception handling) +nmake clean VSE-inlined (to build the MSVC inlined dll with structured exception handling) +nmake clean VC-inlined (to build the MSVC inlined dll with C cleanup code) +nmake clean VC-static (to build the MSVC static lib with C cleanup code) +nmake clean VCE-debug (to build the debug MSVC dll with C++ exception handling) +nmake clean VSE-debug (to build the debug MSVC dll with structured exception handling) +nmake clean VC-debug (to build the debug MSVC dll with C cleanup code) +nmake clean VCE-inlined-debug (to build the debug MSVC inlined dll with C++ exception handling) +nmake clean VSE-inlined-debug (to build the debug MSVC inlined dll with structured exception handling) +nmake clean VC-inlined-debug (to build the debug MSVC inlined dll with C cleanup code) +nmake clean VC-static-debug (to build the debug MSVC static lib with C cleanup code) + + +The pre-built dlls are normally built using the *-inlined targets. + +You can run the testsuite by changing to the "tests" directory and +running nmake. E.g.: + +$ cd tests +$ nmake + +Microsoft (R) Program Maintenance Utility Version 6.00.8168.0 +Copyright (C) Microsoft Corp 1988-1998. All rights reserved. + +Run one of the following command lines: +nmake clean VC (to test using VC dll with VC (no EH) applications) +nmake clean VCX (to test using VC dll with VC++ (EH) applications) +nmake clean VCE (to test using the VCE dll with VC++ EH applications) +nmake clean VSE (to test using VSE dll with VC (SEH) applications) +nmake clean VC-bench (to benchtest using VC dll with C bench app) +nmake clean VCX-bench (to benchtest using VC dll with C++ bench app) +nmake clean VCE-bench (to benchtest using VCE dll with C++ bench app) +nmake clean VSE-bench (to benchtest using VSE dll with SEH bench app) +nmake clean VC-static (to test using VC static lib with VC (no EH) applications) + + +Building under Mingw32 +---------------------- + +The dll can be built easily with recent versions of Mingw32. +(The distributed versions are built using Mingw32 and MsysDTK +from www.mingw32.org.) + +From the source directory, run make for help information. E.g.: + +$ make +Run one of the following command lines: +make clean GC (to build the GNU C dll with C cleanup code) +make clean GCE (to build the GNU C dll with C++ exception handling) +make clean GC-inlined (to build the GNU C inlined dll with C cleanup code) +make clean GCE-inlined (to build the GNU C inlined dll with C++ exception handling) +make clean GC-static (to build the GNU C inlined static lib with C cleanup code) +make clean GC-debug (to build the GNU C debug dll with C cleanup code) +make clean GCE-debug (to build the GNU C debug dll with C++ exception handling) +make clean GC-inlined-debug (to build the GNU C inlined debug dll with C cleanup code) +make clean GCE-inlined-debug (to build the GNU C inlined debug dll with C++ exception handling) +make clean GC-static-debug (to build the GNU C inlined static debug lib with C cleanup code) + + +The pre-built dlls are normally built using the *-inlined targets. + +You can run the testsuite by changing to the "tests" directory and +running make for help information. E.g.: + +$ cd tests +$ make +Run one of the following command lines: +make clean GC (to test using GC dll with C (no EH) applications) +make clean GCX (to test using GC dll with C++ (EH) applications) +make clean GCE (to test using GCE dll with C++ (EH) applications) +make clean GC-bench (to benchtest using GNU C dll with C cleanup code) +make clean GCE-bench (to benchtest using GNU C dll with C++ exception handling) +make clean GC-static (to test using GC static lib with C (no EH) applications) + + +Building under Linux using the Mingw32 cross development tools +-------------------------------------------------------------- + +You can build the library without leaving Linux by using the Mingw32 cross +development toolchain. See http://www.libsdl.org/extras/win32/cross/ for +tools and info. The GNUmakefile contains some support for this, for example: + +make CROSS=i386-mingw32msvc- clean GC-inlined + +will build pthreadGCn.dll and libpthreadGCn.a (n=version#), provided your +cross-tools/bin directory is in your PATH (or use the cross-make.sh script +at the URL above). + + +Building the library as a statically linkable library +----------------------------------------------------- + +General: PTW32_STATIC_LIB must be defined for both the library build and the +application build. The makefiles supplied and used by the following 'make' +command lines will define this for you. + +MSVC (creates pthreadVCn.lib as a static link lib): + +nmake clean VC-static + + +MinGW32 (creates libpthreadGCn.a as a static link lib): + +make clean GC-static + + +Define PTW32_STATIC_LIB when building your application. Also, your +application must call a two non-portable routines to initialise the +some state on startup and cleanup before exit. One other routine needs +to be called to cleanup after any Win32 threads have called POSIX API +routines. See README.NONPORTABLE or the html reference manual pages for +details on these routines: + +BOOL pthread_win32_process_attach_np (void); +BOOL pthread_win32_process_detach_np (void); +BOOL pthread_win32_thread_attach_np (void); // Currently a no-op +BOOL pthread_win32_thread_detach_np (void); + + +The tests makefiles have the same targets but only check that the +static library is statically linkable. They don't run the full +testsuite. To run the full testsuite, build the dlls and run the +dll test targets. + + +Building the library under Cygwin +--------------------------------- + +Cygwin is implementing it's own POSIX threads routines and these +will be the ones to use if you develop using Cygwin. + + +Ready to run binaries +--------------------- + +For convenience, the following ready-to-run files can be downloaded +from the FTP site (see under "Availability" below): + + pthread.h + semaphore.h + sched.h + pthreadVC.dll - built with MSVC compiler using C setjmp/longjmp + pthreadVC.lib + pthreadVCE.dll - built with MSVC++ compiler using C++ EH + pthreadVCE.lib + pthreadVSE.dll - built with MSVC compiler using SEH + pthreadVSE.lib + pthreadGC.dll - built with Mingw32 GCC + libpthreadGC.a - derived from pthreadGC.dll + pthreadGCE.dll - built with Mingw32 G++ + libpthreadGCE.a - derived from pthreadGCE.dll + +As of August 2003 pthreads-win32 pthreadG* versions are built and tested +using the MinGW + MsysDTK environment current as of that date or later. +The following file MAY be needed for older MinGW environments. + + gcc.dll - needed to build and run applications that use + pthreadGCE.dll. + + +Building applications with GNU compilers +---------------------------------------- + +If you're using pthreadGC.dll: + +With the three header files, pthreadGC.dll and libpthreadGC.a in the +same directory as your application myapp.c, you could compile, link +and run myapp.c under Mingw32 as follows: + + gcc -o myapp.exe myapp.c -I. -L. -lpthreadGC + myapp + +Or put pthreadGC.dll in an appropriate directory in your PATH, +put libpthreadGC.a in your system lib directory, and +put the three header files in your system include directory, +then use: + + gcc -o myapp.exe myapp.c -lpthreadGC + myapp + + +If you're using pthreadGCE.dll: + +With the three header files, pthreadGCE.dll, gcc.dll and libpthreadGCE.a +in the same directory as your application myapp.c, you could compile, +link and run myapp.c under Mingw32 as follows: + + gcc -x c++ -o myapp.exe myapp.c -I. -L. -lpthreadGCE + myapp + +Or put pthreadGCE.dll and gcc.dll in an appropriate directory in +your PATH, put libpthreadGCE.a in your system lib directory, and +put the three header files in your system include directory, +then use: + + gcc -x c++ -o myapp.exe myapp.c -lpthreadGCE + myapp + + +Availability +------------ + +The complete source code in either unbundled, self-extracting +Zip file, or tar/gzipped format can be found at: + + ftp://sources.redhat.com/pub/pthreads-win32 + +The pre-built DLL, export libraries and matching pthread.h can +be found at: + + ftp://sources.redhat.com/pub/pthreads-win32/dll-latest + +Home page: + + http://sources.redhat.com/pthreads-win32/ + + +Mailing list +------------ + +There is a mailing list for discussing pthreads on Win32. +To join, send email to: + + pthreads-win32-subscribe@sources.redhat.com + +Unsubscribe by sending mail to: + + pthreads-win32-unsubscribe@sources.redhat.com + + +Acknowledgements +---------------- + +See the ANNOUNCE file for acknowledgements. +See the 'CONTRIBUTORS' file for the list of contributors. + +As much as possible, the ChangeLog file attributes +contributions and patches that have been incorporated +in the library to the individuals responsible. + +Finally, thanks to all those who work on and contribute to the +POSIX and Single Unix Specification standards. The maturity of an +industry can be measured by it's open standards. + +---- +Ross Johnson + + + + + + + + + diff --git a/libs/pthreads/docs/TODO b/libs/pthreads/docs/TODO new file mode 100644 index 0000000000..fa9efc46e7 --- /dev/null +++ b/libs/pthreads/docs/TODO @@ -0,0 +1,7 @@ + Things that aren't done yet + --------------------------- + +1. Implement PTHREAD_PROCESS_SHARED for semaphores, mutexes, + condition variables, read/write locks, barriers. + + diff --git a/libs/pthreads/docs/WinCE-PORT b/libs/pthreads/docs/WinCE-PORT new file mode 100644 index 0000000000..7bcfdea6cc --- /dev/null +++ b/libs/pthreads/docs/WinCE-PORT @@ -0,0 +1,222 @@ +NOTE: The comments in this file relate to the original WinCE port +done by Tristan Savatier. The semaphore routines have been +completely rewritten since (2005-04-25), having been progressively +broken more and more by changes to the library. All of the semaphore +routines implemented for W9x/WNT/2000 and up should now also work for +WinCE. Also, pthread_mutex_timedlock should now work. + +Additional WinCE updates have been applied since this as well. Check the +ChangeLog file and search for WINCE for example. (2007-01-07) + +[RPJ] + +---- + +Some interesting news: + +I have been able to port pthread-win32 to Windows-CE, +which uses a subset of the WIN32 API. + +Since we intend to keep using pthread-win32 for our +Commercial WinCE developments, I would be very interested +if WinCE support could be added to the main source tree +of pthread-win32. Also, I would like to be credited +for this port :-) + +Now, here is the story... + +The port was performed and tested on a Casio "Cassiopeia" +PalmSize PC, which runs a MIP processor. The OS in the +Casio is WinCE version 2.11, but I used VC++ 6.0 with +the WinCE SDK for version 2.01. + +I used pthread-win32 to port a heavily multithreaded +commercial application (real-time MPEG video player) +from Linux to WinCE. I consider the changes that +I have done to be quite well tested. + +Overall the modifications that we had to do are minor. + +The WinCE port were based on pthread-win32-snap-1999-05-30, +but I am certain that they can be integrated very easiely +to more recent versions of the source. + +I have attached the modified source code: +pthread-win32-snap-1999-05-30-WinCE. + +All the changes do not affect the code compiled on non-WinCE +environment, provided that the macros used for WinCE compilation +are not used, of course! + +Overall description of the WinCE port: +------------------------------------- + +Most of the changes had to be made in areas where +pthread-win32 was relying on some standard-C librairies +(e.g. _ftime, calloc, errno), which are not available +on WinCE. We have changed the code to use native Win32 +API instead (or in some cases we made wrappers). + +The Win32 Semaphores are not available, +so we had to re-implement Semaphores using mutexes +and events. + +Limitations / known problems of the WinCE port: +---------------------------------------------- + +Not all the semaphore routines have been ported +(semaphores are defined by Posix but are not part +pf pthread). I have just done enough to make +pthread routines (that rely internally on semaphores) +work, like signal conditions. + +I noticed that the Win32 threads work slightly +differently on WinCE. This may have some impact +on some tricky parts of pthread-win32, but I have +not really investigated. For example, on WinCE, +the process is killed if the main thread falls off +the bottom (or calls pthread_exit), regardless +of the existence of any other detached thread. +Microsoft manual indicates that this behavior is +deffirent from that of Windows Threads for other +Win32 platforms. + + +Detailed descriptions of the changes and rationals: + +------------------------------------ +- use a new macro NEED_ERRNO. + +If defined, the code in errno.c that defines a reentrant errno +is compiled, regardless of _MT and _REENTRANT. + +Rational: On WinCE, there is no support for , or +any other standard C library, i.e. even if _MT or _REENTRANT +is defined, errno is not provided by any library. NEED_ERRNO +must be set to compile for WinCE. + +------------------------------------ +- In implement.h, change #include to #include "semaphore.h". + +Rational: semaphore.h is provided in pthread-win32 and should not +be searched in the systems standard include. would not compile. +This change does not seem to create problems on "classic" win32 +(e.g. win95). + +------------------------------------ +- use a new macro NEED_CALLOC. + +If defined, some code in misc.c will provide a replacement +for calloc, which is not available on Win32. + + +------------------------------------ +- use a new macro NEED_CREATETHREAD. + +If defined, implement.h defines the macro _beginthreadex +and _endthreadex. + +Rational: On WinCE, the wrappers _beginthreadex and _endthreadex +do not exist. The native Win32 routines must be used. + +------------------------------------ +- in misc.c: + +#ifdef NEED_DUPLICATEHANDLE + /* DuplicateHandle does not exist on WinCE */ + self->threadH = GetCurrentThread(); +#else + if( !DuplicateHandle( + GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), + &self->threadH, + 0, + FALSE, + DUPLICATE_SAME_ACCESS ) ) + { + free( self ); + return (NULL); + } +#endif + +Rational: On WinCE, DuplicateHandle does not exist. I could not understand +why DuplicateHandle must be used. It seems to me that getting the current +thread handle with GetCurrentThread() is sufficient, and it seems to work +perfectly fine, so maybe DuplicateHandle was just plain useless to begin with ? + +------------------------------------ +- In private.c, added some code at the beginning of ptw32_processInitialize +to detect the case of multiple calls to ptw32_processInitialize. + +Rational: In order to debug pthread-win32, it is easier to compile +it as a regular library (it is not possible to debug DLL's on winCE). +In that case, the application must call ptw32_rocessInitialize() +explicitely, to initialize pthread-win32. It is safer in this circumstance +to handle the case where ptw32_processInitialize() is called on +an already initialized library: + +int +ptw32_processInitialize (void) +{ + if (ptw32_processInitialized) { + /* + * ignore if already initialized. this is useful for + * programs that uses a non-dll pthread + * library. such programs must call ptw32_processInitialize() explicitely, + * since this initialization routine is automatically called only when + * the dll is loaded. + */ + return TRUE; + } + ptw32_processInitialized = TRUE; + [...] +} + +------------------------------------ +- in private.c, if macro NEED_FTIME is defined, add routines to +convert timespec_to_filetime and filetime_to_timespec, and modified +code that was using _ftime() to use Win32 API instead. + +Rational: _ftime is not available on WinCE. It is necessary to use +the native Win32 time API instead. + +Note: the routine timespec_to_filetime is provided as a convenience and a mean +to test that filetime_to_timespec works, but it is not used by the library. + +------------------------------------ +- in semaphore.c, if macro NEED_SEM is defined, add code for the routines +_increase_semaphore and _decrease_semaphore, and modify significantly +the implementation of the semaphores so that it does not use CreateSemaphore. + +Rational: CreateSemaphore is not available on WinCE. I had to re-implement +semaphores using mutexes and Events. + +Note: Only the semaphore routines that are used by pthread are implemented +(i.e. signal conditions rely on a subset of the semaphores routines, and +this subset works). Some other semaphore routines (e.g. sem_trywait) are +not yet supported on my WinCE port (and since I don't need them, I am not +planning to do anything about them). + +------------------------------------ +- in tsd.c, changed the code that defines TLS_OUT_OF_INDEXES + +/* TLS_OUT_OF_INDEXES not defined on WinCE */ +#ifndef TLS_OUT_OF_INDEXES +#define TLS_OUT_OF_INDEXES 0xffffffff +#endif + +Rational: TLS_OUT_OF_INDEXES is not defined in any standard include file +on WinCE. + +------------------------------------ +- added file need_errno.h + +Rational: On WinCE, there is no errno.h file. need_errno.h is just a +copy of windows version of errno.h, with minor modifications due to the fact +that some of the error codes are defined by the WinCE socket library. +In pthread.h, if NEED_ERRNO is defined, the file need_errno.h is +included (instead of ). + + +-- eof diff --git a/libs/pthreads/pthreads.vcxproj b/libs/pthreads/pthreads.vcxproj new file mode 100644 index 0000000000..e6eabbca71 --- /dev/null +++ b/libs/pthreads/pthreads.vcxproj @@ -0,0 +1,90 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {E0EBB8A5-B577-414C-A5F9-9B4E2A0A66E9} + Win32Proj + pthreads + Unicode + DynamicLibrary + false + false + v141_xp + + + + + $(SolutionDir)$(Configuration)\Libs\ + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Libs\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + true + false + pthreads + .mir + + + + + Level4 + $(ProjectDir)\src;%(AdditionalIncludeDirectories) + false + + + Windows + true + + + + + Disabled + false + WIN32;HAVE_PTW32_CONFIG_H;PTW32_RC_MSC;PTW32_ARCHx64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + + + + + Full + true + true + true + WIN32;HAVE_PTW32_CONFIG_H;PTW32_RC_MSC;PTW32_ARCHx86;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + + + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/pthreads/pthreads.vcxproj.filters b/libs/pthreads/pthreads.vcxproj.filters new file mode 100644 index 0000000000..3b704a70fe --- /dev/null +++ b/libs/pthreads/pthreads.vcxproj.filters @@ -0,0 +1,505 @@ + + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/libs/pthreads/src/attr.c b/libs/pthreads/src/attr.c new file mode 100644 index 0000000000..a9d55f4a4b --- /dev/null +++ b/libs/pthreads/src/attr.c @@ -0,0 +1,53 @@ +/* + * attr.c + * + * Description: + * This translation unit agregates operations on thread attribute objects. + * It is used for inline optimisation. + * + * The included modules are used separately when static executable sizes + * must be minimised. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#include "pthread_attr_init.c" +#include "pthread_attr_destroy.c" +#include "pthread_attr_getdetachstate.c" +#include "pthread_attr_setdetachstate.c" +#include "pthread_attr_getstackaddr.c" +#include "pthread_attr_setstackaddr.c" +#include "pthread_attr_getstacksize.c" +#include "pthread_attr_setstacksize.c" +#include "pthread_attr_getscope.c" +#include "pthread_attr_setscope.c" diff --git a/libs/pthreads/src/autostatic.c b/libs/pthreads/src/autostatic.c new file mode 100644 index 0000000000..092aff2aee --- /dev/null +++ b/libs/pthreads/src/autostatic.c @@ -0,0 +1,69 @@ +/* + * autostatic.c + * + * Description: + * This translation unit implements static auto-init and auto-exit logic. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if defined(PTW32_STATIC_LIB) + +#if defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) + +#include "pthread.h" +#include "implement.h" + +static void on_process_init(void) +{ + pthread_win32_process_attach_np (); +} + +static void on_process_exit(void) +{ + pthread_win32_thread_detach_np (); + pthread_win32_process_detach_np (); +} + +#if defined(__MINGW64__) || defined(__MINGW32__) +# define attribute_section(a) __attribute__((section(a))) +#elif defined(_MSC_VER) +# define attribute_section(a) __pragma(section(a,long,read)); __declspec(allocate(a)) +#endif + +attribute_section(".ctors") void *gcc_ctor = on_process_init; +attribute_section(".dtors") void *gcc_dtor = on_process_exit; + +attribute_section(".CRT$XCU") void *msc_ctor = on_process_init; +attribute_section(".CRT$XPU") void *msc_dtor = on_process_exit; + +#endif /* defined(__MINGW64__) || defined(__MINGW32__) || defined(_MSC_VER) */ + +#endif /* PTW32_STATIC_LIB */ diff --git a/libs/pthreads/src/barrier.c b/libs/pthreads/src/barrier.c new file mode 100644 index 0000000000..41b950cd12 --- /dev/null +++ b/libs/pthreads/src/barrier.c @@ -0,0 +1,47 @@ +/* + * barrier.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_barrier_init.c" +#include "pthread_barrier_destroy.c" +#include "pthread_barrier_wait.c" +#include "pthread_barrierattr_init.c" +#include "pthread_barrierattr_destroy.c" +#include "pthread_barrierattr_getpshared.c" +#include "pthread_barrierattr_setpshared.c" diff --git a/libs/pthreads/src/cancel.c b/libs/pthreads/src/cancel.c new file mode 100644 index 0000000000..1bd14ebe65 --- /dev/null +++ b/libs/pthreads/src/cancel.c @@ -0,0 +1,44 @@ +/* + * cancel.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_setcancelstate.c" +#include "pthread_setcanceltype.c" +#include "pthread_testcancel.c" +#include "pthread_cancel.c" diff --git a/libs/pthreads/src/cleanup.c b/libs/pthreads/src/cleanup.c new file mode 100644 index 0000000000..381d1e87c8 --- /dev/null +++ b/libs/pthreads/src/cleanup.c @@ -0,0 +1,148 @@ +/* + * cleanup.c + * + * Description: + * This translation unit implements routines associated + * with cleaning up threads. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +/* + * The functions ptw32_pop_cleanup and ptw32_push_cleanup + * are implemented here for applications written in C with no + * SEH or C++ destructor support. + */ + +ptw32_cleanup_t * +ptw32_pop_cleanup (int execute) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function pops the most recently pushed cleanup + * handler. If execute is nonzero, then the cleanup handler + * is executed if non-null. + * + * PARAMETERS + * execute + * if nonzero, execute the cleanup handler + * + * + * DESCRIPTION + * This function pops the most recently pushed cleanup + * handler. If execute is nonzero, then the cleanup handler + * is executed if non-null. + * NOTE: specify 'execute' as nonzero to avoid duplication + * of common cleanup code. + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + ptw32_cleanup_t *cleanup; + + cleanup = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey); + + if (cleanup != NULL) + { + if (execute && (cleanup->routine != NULL)) + { + + (*cleanup->routine) (cleanup->arg); + + } + + pthread_setspecific (ptw32_cleanupKey, (void *) cleanup->prev); + + } + + return (cleanup); + +} /* ptw32_pop_cleanup */ + + +void +ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + ptw32_cleanup_callback_t routine, void *arg) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function pushes a new cleanup handler onto the thread's stack + * of cleanup handlers. Each cleanup handler pushed onto the stack is + * popped and invoked with the argument 'arg' when + * a) the thread exits by calling 'pthread_exit', + * b) when the thread acts on a cancellation request, + * c) or when the thread calls pthread_cleanup_pop with a nonzero + * 'execute' argument + * + * PARAMETERS + * cleanup + * a pointer to an instance of pthread_cleanup_t, + * + * routine + * pointer to a cleanup handler, + * + * arg + * parameter to be passed to the cleanup handler + * + * + * DESCRIPTION + * This function pushes a new cleanup handler onto the thread's stack + * of cleanup handlers. Each cleanup handler pushed onto the stack is + * popped and invoked with the argument 'arg' when + * a) the thread exits by calling 'pthread_exit', + * b) when the thread acts on a cancellation request, + * c) or when the thrad calls pthread_cleanup_pop with a nonzero + * 'execute' argument + * NOTE: pthread_push_cleanup, ptw32_pop_cleanup must be paired + * in the same lexical scope. + * + * RESULTS + * pthread_cleanup_t * + * pointer to the previous cleanup + * + * ------------------------------------------------------ + */ +{ + cleanup->routine = routine; + cleanup->arg = arg; + + cleanup->prev = (ptw32_cleanup_t *) pthread_getspecific (ptw32_cleanupKey); + + pthread_setspecific (ptw32_cleanupKey, (void *) cleanup); + +} /* ptw32_push_cleanup */ diff --git a/libs/pthreads/src/condvar.c b/libs/pthreads/src/condvar.c new file mode 100644 index 0000000000..704f4d7931 --- /dev/null +++ b/libs/pthreads/src/condvar.c @@ -0,0 +1,50 @@ +/* + * condvar.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + */ + +#include "pthread.h" +#include "implement.h" + +#include "ptw32_cond_check_need_init.c" +#include "pthread_condattr_init.c" +#include "pthread_condattr_destroy.c" +#include "pthread_condattr_getpshared.c" +#include "pthread_condattr_setpshared.c" +#include "pthread_cond_init.c" +#include "pthread_cond_destroy.c" +#include "pthread_cond_wait.c" +#include "pthread_cond_signal.c" diff --git a/libs/pthreads/src/config.h b/libs/pthreads/src/config.h new file mode 100644 index 0000000000..e63ce2da46 --- /dev/null +++ b/libs/pthreads/src/config.h @@ -0,0 +1,153 @@ +/* config.h */ + +#ifndef PTW32_CONFIG_H +#define PTW32_CONFIG_H + +/********************************************************************* + * Defaults: see target specific redefinitions below. + *********************************************************************/ + +/* We're building the pthreads-win32 library */ +#define PTW32_BUILD + +/* Do we know about the C type sigset_t? */ +#undef HAVE_SIGSET_T + +/* Define if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define if you have the Borland TASM32 or compatible assembler. */ +#undef HAVE_TASM32 + +/* Define if you don't have Win32 DuplicateHandle. (eg. WinCE) */ +#undef NEED_DUPLICATEHANDLE + +/* Define if you don't have Win32 _beginthreadex. (eg. WinCE) */ +#undef NEED_CREATETHREAD + +/* Define if you don't have Win32 errno. (eg. WinCE) */ +#undef NEED_ERRNO + +/* Define if you don't have Win32 calloc. (eg. WinCE) */ +#undef NEED_CALLOC + +/* Define if you don't have Win32 ftime. (eg. WinCE) */ +#undef NEED_FTIME + +/* Define if you don't have Win32 semaphores. (eg. WinCE 2.1 or earlier) */ +#undef NEED_SEM + +/* Define if you need to convert string parameters to unicode. (eg. WinCE) */ +#undef NEED_UNICODE_CONSTS + +/* Define if your C (not C++) compiler supports "inline" functions. */ +#undef HAVE_C_INLINE + +/* Do we know about type mode_t? */ +#undef HAVE_MODE_T + +/* + * Define if GCC has atomic builtins, i.e. __sync_* intrinsics + * __sync_lock_* is implemented in mingw32 gcc 4.5.2 at least + * so this define does not turn those on or off. If you get an + * error from __sync_lock* then consider upgrading your gcc. + */ +#undef HAVE_GCC_ATOMIC_BUILTINS + +/* Define if you have the timespec struct */ +#define HAVE_STRUCT_TIMESPEC 1 + +/* Define if you don't have the GetProcessAffinityMask() */ +#undef NEED_PROCESS_AFFINITY_MASK + +/* Define if your version of Windows TLSGetValue() clears WSALastError + * and calling SetLastError() isn't enough restore it. You'll also need to + * link against wsock32.lib (or libwsock32.a for MinGW). + */ +#undef RETAIN_WSALASTERROR + +/* +# ---------------------------------------------------------------------- +# The library can be built with some alternative behaviour to better +# facilitate development of applications on Win32 that will be ported +# to other POSIX systems. +# +# Nothing described here will make the library non-compliant and strictly +# compliant applications will not be affected in any way, but +# applications that make assumptions that POSIX does not guarantee are +# not strictly compliant and may fail or misbehave with some settings. +# +# PTW32_THREAD_ID_REUSE_INCREMENT +# Purpose: +# POSIX says that applications should assume that thread IDs can be +# recycled. However, Solaris (and some other systems) use a [very large] +# sequence number as the thread ID, which provides virtual uniqueness. +# This provides a very high but finite level of safety for applications +# that are not meticulous in tracking thread lifecycles e.g. applications +# that call functions which target detached threads without some form of +# thread exit synchronisation. +# +# Usage: +# Set to any value in the range: 0 <= value < 2^wordsize. +# Set to 0 to emulate reusable thread ID behaviour like Linux or *BSD. +# Set to 1 for unique thread IDs like Solaris (this is the default). +# Set to some factor of 2^wordsize to emulate smaller word size types +# (i.e. will wrap sooner). This might be useful to emulate some embedded +# systems. +# +# define PTW32_THREAD_ID_REUSE_INCREMENT 0 +# +# ---------------------------------------------------------------------- + */ +#undef PTW32_THREAD_ID_REUSE_INCREMENT + + +/********************************************************************* + * Target specific groups + * + * If you find that these are incorrect or incomplete please report it + * to the pthreads-win32 maintainer. Thanks. + *********************************************************************/ +#if defined(WINCE) +#define NEED_DUPLICATEHANDLE +#define NEED_CREATETHREAD +#define NEED_ERRNO +#define NEED_CALLOC +#define NEED_FTIME +/* #define NEED_SEM */ +#define NEED_UNICODE_CONSTS +#define NEED_PROCESS_AFFINITY_MASK +/* This may not be needed */ +#define RETAIN_WSALASTERROR +#endif + +#if defined(_UWIN) +#define HAVE_MODE_T +#define HAVE_STRUCT_TIMESPEC +#endif + +#if defined(__GNUC__) +#define HAVE_C_INLINE +#endif + +#if defined(__MINGW64__) +#define HAVE_MODE_T +#define HAVE_STRUCT_TIMESPEC +#elif defined(__MINGW32__) +#define HAVE_MODE_T +#endif + +#if defined(__BORLANDC__) +#endif + +#if defined(__WATCOMC__) +#endif + +#if defined(__DMC__) +#define HAVE_SIGNAL_H +#define HAVE_C_INLINE +#endif + + + +#endif diff --git a/libs/pthreads/src/context.h b/libs/pthreads/src/context.h new file mode 100644 index 0000000000..3d4511f5b3 --- /dev/null +++ b/libs/pthreads/src/context.h @@ -0,0 +1,74 @@ +/* + * context.h + * + * Description: + * POSIX thread macros related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef PTW32_CONTEXT_H +#define PTW32_CONTEXT_H + +#undef PTW32_PROGCTR + +#if defined(_M_IX86) || (defined(_X86_) && !defined(__amd64__)) +#define PTW32_PROGCTR(Context) ((Context).Eip) +#endif + +#if defined (_M_IA64) || defined(_IA64) +#define PTW32_PROGCTR(Context) ((Context).StIIP) +#endif + +#if defined(_MIPS_) || defined(MIPS) +#define PTW32_PROGCTR(Context) ((Context).Fir) +#endif + +#if defined(_ALPHA_) +#define PTW32_PROGCTR(Context) ((Context).Fir) +#endif + +#if defined(_PPC_) +#define PTW32_PROGCTR(Context) ((Context).Iar) +#endif + +#if defined(_AMD64_) || defined(__amd64__) +#define PTW32_PROGCTR(Context) ((Context).Rip) +#endif + +#if defined(_ARM_) || defined(ARM) +#define PTW32_PROGCTR(Context) ((Context).Pc) +#endif + +#if !defined(PTW32_PROGCTR) +#error Module contains CPU-specific code; modify and recompile. +#endif + +#endif diff --git a/libs/pthreads/src/create.c b/libs/pthreads/src/create.c new file mode 100644 index 0000000000..8b036cc2e9 --- /dev/null +++ b/libs/pthreads/src/create.c @@ -0,0 +1,308 @@ +/* + * create.c + * + * Description: + * This translation unit implements routines associated with spawning a new + * thread. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#if ! defined(_UWIN) && ! defined(WINCE) +#include +#endif + +int +pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(PTW32_CDECL *start) (void *), void *arg) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function creates a thread running the start function, + * passing it the parameter value, 'arg'. The 'attr' + * argument specifies optional creation attributes. + * The identity of the new thread is returned + * via 'tid', which should not be NULL. + * + * PARAMETERS + * tid + * pointer to an instance of pthread_t + * + * attr + * optional pointer to an instance of pthread_attr_t + * + * start + * pointer to the starting routine for the new thread + * + * arg + * optional parameter passed to 'start' + * + * + * DESCRIPTION + * This function creates a thread running the start function, + * passing it the parameter value, 'arg'. The 'attr' + * argument specifies optional creation attributes. + * The identity of the new thread is returned + * via 'tid', which should not be the NULL pointer. + * + * RESULTS + * 0 successfully created thread, + * EINVAL attr invalid, + * EAGAIN insufficient resources. + * + * ------------------------------------------------------ + */ +{ + pthread_t thread; + ptw32_thread_t * tp; + register pthread_attr_t a; + HANDLE threadH = 0; + int result = EAGAIN; + int run = PTW32_TRUE; + ThreadParms *parms = NULL; + unsigned int stackSize; + int priority; + pthread_t self; + + /* + * Before doing anything, check that tid can be stored through + * without invoking a memory protection error (segfault). + * Make sure that the assignment below can't be optimised out by the compiler. + * This is assured by conditionally assigning *tid again at the end. + */ + tid->x = 0; + + if (attr != NULL) + { + a = *attr; + } + else + { + a = NULL; + } + + if ((thread = ptw32_new ()).p == NULL) + { + goto FAIL0; + } + + tp = (ptw32_thread_t *) thread.p; + + priority = tp->sched_priority; + + if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL) + { + goto FAIL0; + } + + parms->tid = thread; + parms->start = start; + parms->arg = arg; + +#if defined(HAVE_SIGSET_T) + + /* + * Threads inherit their initial sigmask from their creator thread. + */ + self = pthread_self(); + tp->sigmask = ((ptw32_thread_t *)self.p)->sigmask; + +#endif /* HAVE_SIGSET_T */ + + + if (a != NULL) + { + stackSize = (unsigned int)a->stacksize; + tp->detachState = a->detachstate; + priority = a->param.sched_priority; + +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) + /* WinCE */ +#else + /* Everything else */ + + /* + * Thread priority must be set to a valid system level + * without altering the value set by pthread_attr_setschedparam(). + */ + + /* + * PTHREAD_EXPLICIT_SCHED is the default because Win32 threads + * don't inherit their creator's priority. They are started with + * THREAD_PRIORITY_NORMAL (win32 value). The result of not supplying + * an 'attr' arg to pthread_create() is equivalent to defaulting to + * PTHREAD_EXPLICIT_SCHED and priority THREAD_PRIORITY_NORMAL. + */ + if (PTHREAD_INHERIT_SCHED == a->inheritsched) + { + /* + * If the thread that called pthread_create() is a Win32 thread + * then the inherited priority could be the result of a temporary + * system adjustment. This is not the case for POSIX threads. + */ +#if ! defined(HAVE_SIGSET_T) + self = pthread_self (); +#endif + priority = ((ptw32_thread_t *) self.p)->sched_priority; + } + +#endif + + } + else + { + /* + * Default stackSize + */ + stackSize = PTHREAD_STACK_MIN; + } + + tp->state = run ? PThreadStateInitial : PThreadStateSuspended; + + tp->keys = NULL; + + /* + * Threads must be started in suspended mode and resumed if necessary + * after _beginthreadex returns us the handle. Otherwise we set up a + * race condition between the creating and the created threads. + * Note that we also retain a local copy of the handle for use + * by us in case thread.p->threadH gets NULLed later but before we've + * finished with it here. + */ + +#if ! (defined (__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__) + + tp->threadH = + threadH = + (HANDLE) _beginthreadex ((void *) NULL, /* No security info */ + stackSize, /* default stack size */ + ptw32_threadStart, + parms, + (unsigned) + CREATE_SUSPENDED, + (unsigned *) &(tp->thread)); + + if (threadH != 0) + { + if (a != NULL) + { + (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); + } + + if (run) + { + ResumeThread (threadH); + } + } + +#else + + { + ptw32_mcs_local_node_t stateLock; + + /* + * This lock will force pthread_threadStart() to wait until we have + * the thread handle and have set the priority. + */ + ptw32_mcs_lock_acquire(&tp->stateLock, &stateLock); + + tp->threadH = + threadH = + (HANDLE) _beginthread (ptw32_threadStart, stackSize, /* default stack size */ + parms); + + /* + * Make the return code match _beginthreadex's. + */ + if (threadH == (HANDLE) - 1L) + { + tp->threadH = threadH = 0; + } + else + { + if (!run) + { + /* + * beginthread does not allow for create flags, so we do it now. + * Note that beginthread itself creates the thread in SUSPENDED + * mode, and then calls ResumeThread to start it. + */ + SuspendThread (threadH); + } + + if (a != NULL) + { + (void) ptw32_setthreadpriority (thread, SCHED_OTHER, priority); + } + } + + ptw32_mcs_lock_release (&stateLock); + } +#endif + + result = (threadH != 0) ? 0 : EAGAIN; + + /* + * Fall Through Intentionally + */ + + /* + * ------------ + * Failure Code + * ------------ + */ + +FAIL0: + if (result != 0) + { + + ptw32_threadDestroy (thread); + tp = NULL; + + if (parms != NULL) + { + free (parms); + } + } + else + { + *tid = thread; + } + +#if defined(_UWIN) + if (result == 0) + pthread_count++; +#endif + return (result); + +} /* pthread_create */ diff --git a/libs/pthreads/src/dll.c b/libs/pthreads/src/dll.c new file mode 100644 index 0000000000..05e01bee76 --- /dev/null +++ b/libs/pthreads/src/dll.c @@ -0,0 +1,92 @@ +/* + * dll.c + * + * Description: + * This translation unit implements DLL initialisation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined(PTW32_STATIC_LIB) + +#include "pthread.h" +#include "implement.h" + +#if defined(_MSC_VER) +/* + * lpvReserved yields an unreferenced formal parameter; + * ignore it + */ +#pragma warning( disable : 4100 ) +#endif + +#if defined(__cplusplus) +/* + * Dear c++: Please don't mangle this name. -thanks + */ +extern "C" +#endif /* __cplusplus */ + BOOL WINAPI +DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) +{ + BOOL result = PTW32_TRUE; + + switch (fdwReason) + { + + case DLL_PROCESS_ATTACH: + result = pthread_win32_process_attach_np (); + break; + + case DLL_THREAD_ATTACH: + /* + * A thread is being created + */ + result = pthread_win32_thread_attach_np (); + break; + + case DLL_THREAD_DETACH: + /* + * A thread is exiting cleanly + */ + result = pthread_win32_thread_detach_np (); + break; + + case DLL_PROCESS_DETACH: + (void) pthread_win32_thread_detach_np (); + result = pthread_win32_process_detach_np (); + break; + } + + return (result); + +} /* DllMain */ + +#endif /* PTW32_STATIC_LIB */ diff --git a/libs/pthreads/src/errno.c b/libs/pthreads/src/errno.c new file mode 100644 index 0000000000..78aa920a5b --- /dev/null +++ b/libs/pthreads/src/errno.c @@ -0,0 +1,94 @@ +/* + * errno.c + * + * Description: + * This translation unit implements routines associated with spawning a new + * thread. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if defined(NEED_ERRNO) + +#include "pthread.h" +#include "implement.h" + +static int reallyBad = ENOMEM; + +/* + * Re-entrant errno. + * + * Each thread has it's own errno variable in pthread_t. + * + * The benefit of using the pthread_t structure + * instead of another TSD key is TSD keys are limited + * on Win32 to 64 per process. Secondly, to implement + * it properly without using pthread_t you'd need + * to dynamically allocate an int on starting the thread + * and store it manually into TLS and then ensure that you free + * it on thread termination. We get all that for free + * by simply storing the errno on the pthread_t structure. + * + * MSVC and Mingw32 already have their own thread-safe errno. + * + * #if defined( _REENTRANT ) || defined( _MT ) + * #define errno *_errno() + * + * int *_errno( void ); + * #else + * extern int errno; + * #endif + * + */ + +int * +_errno (void) +{ + pthread_t self; + int *result; + + if ((self = pthread_self ()).p == NULL) + { + /* + * Yikes! unable to allocate a thread! + * Throw an exception? return an error? + */ + result = &reallyBad; + } + else + { + result = (int *)(&self.p->exitStatus); + } + + return (result); + +} /* _errno */ + +#endif /* (NEED_ERRNO) */ diff --git a/libs/pthreads/src/exit.c b/libs/pthreads/src/exit.c new file mode 100644 index 0000000000..94369d007c --- /dev/null +++ b/libs/pthreads/src/exit.c @@ -0,0 +1,44 @@ +/* + * exit.c + * + * Description: + * This translation unit implements routines associated with exiting from + * a thread. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#if ! defined(_UWIN) && ! defined(WINCE) +# include +#endif + +#include "pthread_exit.c" diff --git a/libs/pthreads/src/fork.c b/libs/pthreads/src/fork.c new file mode 100644 index 0000000000..8a29550caf --- /dev/null +++ b/libs/pthreads/src/fork.c @@ -0,0 +1,39 @@ +/* + * fork.c + * + * Description: + * Implementation of fork() for POSIX threads. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "pthread.h" +#include "implement.h" diff --git a/libs/pthreads/src/global.c b/libs/pthreads/src/global.c new file mode 100644 index 0000000000..f1e9b3f669 --- /dev/null +++ b/libs/pthreads/src/global.c @@ -0,0 +1,107 @@ +/* + * global.c + * + * Description: + * This translation unit instantiates data associated with the implementation + * as a whole. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int ptw32_processInitialized = PTW32_FALSE; +ptw32_thread_t * ptw32_threadReuseTop = PTW32_THREAD_REUSE_EMPTY; +ptw32_thread_t * ptw32_threadReuseBottom = PTW32_THREAD_REUSE_EMPTY; +pthread_key_t ptw32_selfThreadKey = NULL; +pthread_key_t ptw32_cleanupKey = NULL; +pthread_cond_t ptw32_cond_list_head = NULL; +pthread_cond_t ptw32_cond_list_tail = NULL; + +int ptw32_concurrency = 0; + +/* What features have been auto-detected */ +int ptw32_features = 0; + +/* + * Global [process wide] thread sequence Number + */ +unsigned __int64 ptw32_threadSeqNumber = 0; + +/* + * Function pointer to QueueUserAPCEx if it exists, otherwise + * it will be set at runtime to a substitute routine which cannot unblock + * blocked threads. + */ +DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD) = NULL; + +/* + * Global lock for managing pthread_t struct reuse. + */ +ptw32_mcs_lock_t ptw32_thread_reuse_lock = 0; + +/* + * Global lock for testing internal state of statically declared mutexes. + */ +ptw32_mcs_lock_t ptw32_mutex_test_init_lock = 0; + +/* + * Global lock for testing internal state of PTHREAD_COND_INITIALIZER + * created condition variables. + */ +ptw32_mcs_lock_t ptw32_cond_test_init_lock = 0; + +/* + * Global lock for testing internal state of PTHREAD_RWLOCK_INITIALIZER + * created read/write locks. + */ +ptw32_mcs_lock_t ptw32_rwlock_test_init_lock = 0; + +/* + * Global lock for testing internal state of PTHREAD_SPINLOCK_INITIALIZER + * created spin locks. + */ +ptw32_mcs_lock_t ptw32_spinlock_test_init_lock = 0; + +/* + * Global lock for condition variable linked list. The list exists + * to wake up CVs when a WM_TIMECHANGE message arrives. See + * w32_TimeChangeHandler.c. + */ +ptw32_mcs_lock_t ptw32_cond_list_lock = 0; + +#if defined(_UWIN) +/* + * Keep a count of the number of threads. + */ +int pthread_count = 0; +#endif diff --git a/libs/pthreads/src/implement.h b/libs/pthreads/src/implement.h new file mode 100644 index 0000000000..693be26a24 --- /dev/null +++ b/libs/pthreads/src/implement.h @@ -0,0 +1,943 @@ +/* + * implement.h + * + * Definitions that don't need to be public. + * + * Keeps all the internals out of pthread.h + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: Ross.Johnson@homemail.com.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined(_IMPLEMENT_H) +#define _IMPLEMENT_H + +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0400 +#endif + +#include + +/* + * In case windows.h doesn't define it (e.g. WinCE perhaps) + */ +#if defined(WINCE) +typedef VOID (APIENTRY *PAPCFUNC)(DWORD dwParam); +#endif + +/* + * note: ETIMEDOUT is correctly defined in winsock.h + */ +#include + +/* + * In case ETIMEDOUT hasn't been defined above somehow. + */ +#if !defined(ETIMEDOUT) +# define ETIMEDOUT 10060 /* This is the value in winsock.h. */ +#endif + +#if !defined(malloc) +#include +#endif + +#if defined(__CLEANUP_C) +# include +#endif + +#if !defined(INT_MAX) +#include +#endif + +/* use local include files during development */ +#include "semaphore.h" +#include "sched.h" + +#if defined(HAVE_C_INLINE) || defined(__cplusplus) +#define INLINE inline +#else +#define INLINE +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 +/* + * MSVC 6 does not use the "volatile" qualifier + */ +#define PTW32_INTERLOCKED_VOLATILE +#else +#define PTW32_INTERLOCKED_VOLATILE volatile +#endif +#define PTW32_INTERLOCKED_LONG long +#define PTW32_INTERLOCKED_SIZE size_t +#define PTW32_INTERLOCKED_PVOID PVOID +#define PTW32_INTERLOCKED_LONGPTR PTW32_INTERLOCKED_VOLATILE long* +#define PTW32_INTERLOCKED_SIZEPTR PTW32_INTERLOCKED_VOLATILE size_t* +#define PTW32_INTERLOCKED_PVOID_PTR PTW32_INTERLOCKED_VOLATILE PVOID* + +#if defined(__MINGW64__) || defined(__MINGW32__) +# include +#elif defined(__BORLANDC__) +# define int64_t ULONGLONG +#else +# define int64_t _int64 +# if defined(_MSC_VER) && _MSC_VER < 1300 + typedef long intptr_t; +# endif +#endif + +typedef enum +{ + /* + * This enumeration represents the state of the thread; + * The thread is still "alive" if the numeric value of the + * state is greater or equal "PThreadStateRunning". + */ + PThreadStateInitial = 0, /* Thread not running */ + PThreadStateRunning, /* Thread alive & kicking */ + PThreadStateSuspended, /* Thread alive but suspended */ + PThreadStateCancelPending, /* Thread alive but */ + /* has cancelation pending. */ + PThreadStateCanceling, /* Thread alive but is */ + /* in the process of terminating */ + /* due to a cancellation request */ + PThreadStateExiting, /* Thread alive but exiting */ + /* due to an exception */ + PThreadStateLast, /* All handlers have been run and now */ + /* final cleanup can be done. */ + PThreadStateReuse /* In reuse pool. */ +} +PThreadState; + +typedef struct ptw32_mcs_node_t_ ptw32_mcs_local_node_t; +typedef struct ptw32_mcs_node_t_* ptw32_mcs_lock_t; +typedef struct ptw32_robust_node_t_ ptw32_robust_node_t; +typedef struct ptw32_thread_t_ ptw32_thread_t; + + +struct ptw32_thread_t_ +{ + unsigned __int64 seqNumber; /* Process-unique thread sequence number */ + HANDLE threadH; /* Win32 thread handle - POSIX thread is invalid if threadH == 0 */ + pthread_t ptHandle; /* This thread's permanent pthread_t handle */ + ptw32_thread_t * prevReuse; /* Links threads on reuse stack */ + volatile PThreadState state; + ptw32_mcs_lock_t threadLock; /* Used for serialised access to public thread state */ + ptw32_mcs_lock_t stateLock; /* Used for async-cancel safety */ + HANDLE cancelEvent; + void *exitStatus; + void *parms; + void *keys; + void *nextAssoc; +#if defined(__CLEANUP_C) + jmp_buf start_mark; /* Jump buffer follows void* so should be aligned */ +#endif /* __CLEANUP_C */ +#if defined(HAVE_SIGSET_T) + sigset_t sigmask; +#endif /* HAVE_SIGSET_T */ + ptw32_mcs_lock_t + robustMxListLock; /* robustMxList lock */ + ptw32_robust_node_t* + robustMxList; /* List of currenty held robust mutexes */ + int ptErrno; + int detachState; + int sched_priority; /* As set, not as currently is */ + int cancelState; + int cancelType; + int implicit:1; + DWORD thread; /* Win32 thread ID */ +#if defined(_UWIN) + DWORD dummy[5]; +#endif + size_t align; /* Force alignment if this struct is packed */ +}; + + +/* + * Special value to mark attribute objects as valid. + */ +#define PTW32_ATTR_VALID ((unsigned long) 0xC4C0FFEE) + +struct pthread_attr_t_ +{ + unsigned long valid; + void *stackaddr; + size_t stacksize; + int detachstate; + struct sched_param param; + int inheritsched; + int contentionscope; +#if defined(HAVE_SIGSET_T) + sigset_t sigmask; +#endif /* HAVE_SIGSET_T */ +}; + + +/* + * ==================== + * ==================== + * Semaphores, Mutexes and Condition Variables + * ==================== + * ==================== + */ + +struct sem_t_ +{ + int value; + pthread_mutex_t lock; + HANDLE sem; +#if defined(NEED_SEM) + int leftToUnblock; +#endif +}; + +#define PTW32_OBJECT_AUTO_INIT ((void *)(size_t) -1) +#define PTW32_OBJECT_INVALID NULL + +struct pthread_mutex_t_ +{ + LONG lock_idx; /* Provides exclusive access to mutex state + via the Interlocked* mechanism. + 0: unlocked/free. + 1: locked - no other waiters. + -1: locked - with possible other waiters. + */ + int recursive_count; /* Number of unlocks a thread needs to perform + before the lock is released (recursive + mutexes only). */ + int kind; /* Mutex type. */ + pthread_t ownerThread; + HANDLE event; /* Mutex release notification to waiting + threads. */ + ptw32_robust_node_t* + robustNode; /* Extra state for robust mutexes */ +}; + +enum ptw32_robust_state_t_ +{ + PTW32_ROBUST_CONSISTENT, + PTW32_ROBUST_INCONSISTENT, + PTW32_ROBUST_NOTRECOVERABLE +}; + +typedef enum ptw32_robust_state_t_ ptw32_robust_state_t; + +/* + * Node used to manage per-thread lists of currently-held robust mutexes. + */ +struct ptw32_robust_node_t_ +{ + pthread_mutex_t mx; + ptw32_robust_state_t stateInconsistent; + ptw32_robust_node_t* prev; + ptw32_robust_node_t* next; +}; + +struct pthread_mutexattr_t_ +{ + int pshared; + int kind; + int robustness; +}; + +/* + * Possible values, other than PTW32_OBJECT_INVALID, + * for the "interlock" element in a spinlock. + * + * In this implementation, when a spinlock is initialised, + * the number of cpus available to the process is checked. + * If there is only one cpu then "interlock" is set equal to + * PTW32_SPIN_USE_MUTEX and u.mutex is an initialised mutex. + * If the number of cpus is greater than 1 then "interlock" + * is set equal to PTW32_SPIN_UNLOCKED and the number is + * stored in u.cpus. This arrangement allows the spinlock + * routines to attempt an InterlockedCompareExchange on "interlock" + * immediately and, if that fails, to try the inferior mutex. + * + * "u.cpus" isn't used for anything yet, but could be used at + * some point to optimise spinlock behaviour. + */ +#define PTW32_SPIN_INVALID (0) +#define PTW32_SPIN_UNLOCKED (1) +#define PTW32_SPIN_LOCKED (2) +#define PTW32_SPIN_USE_MUTEX (3) + +struct pthread_spinlock_t_ +{ + long interlock; /* Locking element for multi-cpus. */ + union + { + int cpus; /* No. of cpus if multi cpus, or */ + pthread_mutex_t mutex; /* mutex if single cpu. */ + } u; +}; + +/* + * MCS lock queue node - see ptw32_MCS_lock.c + */ +struct ptw32_mcs_node_t_ +{ + struct ptw32_mcs_node_t_ **lock; /* ptr to tail of queue */ + struct ptw32_mcs_node_t_ *next; /* ptr to successor in queue */ + HANDLE readyFlag; /* set after lock is released by + predecessor */ + HANDLE nextFlag; /* set after 'next' ptr is set by + successor */ +}; + + +struct pthread_barrier_t_ +{ + unsigned int nCurrentBarrierHeight; + unsigned int nInitialBarrierHeight; + int pshared; + sem_t semBarrierBreeched; + ptw32_mcs_lock_t lock; + ptw32_mcs_local_node_t proxynode; +}; + +struct pthread_barrierattr_t_ +{ + int pshared; +}; + +struct pthread_key_t_ +{ + DWORD key; + void (PTW32_CDECL *destructor) (void *); + ptw32_mcs_lock_t keyLock; + void *threads; +}; + + +typedef struct ThreadParms ThreadParms; + +struct ThreadParms +{ + pthread_t tid; + void *(PTW32_CDECL *start) (void *); + void *arg; +}; + + +struct pthread_cond_t_ +{ + long nWaitersBlocked; /* Number of threads blocked */ + long nWaitersGone; /* Number of threads timed out */ + long nWaitersToUnblock; /* Number of threads to unblock */ + sem_t semBlockQueue; /* Queue up threads waiting for the */ + /* condition to become signalled */ + sem_t semBlockLock; /* Semaphore that guards access to */ + /* | waiters blocked count/block queue */ + /* +-> Mandatory Sync.LEVEL-1 */ + pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */ + /* | waiters (to)unblock(ed) counts */ + /* +-> Optional* Sync.LEVEL-2 */ + pthread_cond_t next; /* Doubly linked list */ + pthread_cond_t prev; +}; + + +struct pthread_condattr_t_ +{ + int pshared; +}; + +#define PTW32_RWLOCK_MAGIC 0xfacade2 + +struct pthread_rwlock_t_ +{ + pthread_mutex_t mtxExclusiveAccess; + pthread_mutex_t mtxSharedAccessCompleted; + pthread_cond_t cndSharedAccessCompleted; + int nSharedAccessCount; + int nExclusiveAccessCount; + int nCompletedSharedAccessCount; + int nMagic; +}; + +struct pthread_rwlockattr_t_ +{ + int pshared; +}; + +typedef struct ThreadKeyAssoc ThreadKeyAssoc; + +struct ThreadKeyAssoc +{ + /* + * Purpose: + * This structure creates an association between a thread and a key. + * It is used to implement the implicit invocation of a user defined + * destroy routine for thread specific data registered by a user upon + * exiting a thread. + * + * Graphically, the arrangement is as follows, where: + * + * K - Key with destructor + * (head of chain is key->threads) + * T - Thread that has called pthread_setspecific(Kn) + * (head of chain is thread->keys) + * A - Association. Each association is a node at the + * intersection of two doubly-linked lists. + * + * T1 T2 T3 + * | | | + * | | | + * K1 -----+-----A-----A-----> + * | | | + * | | | + * K2 -----A-----A-----+-----> + * | | | + * | | | + * K3 -----A-----+-----A-----> + * | | | + * | | | + * V V V + * + * Access to the association is guarded by two locks: the key's + * general lock (guarding the row) and the thread's general + * lock (guarding the column). This avoids the need for a + * dedicated lock for each association, which not only consumes + * more handles but requires that the lock resources persist + * until both the key is deleted and the thread has called the + * destructor. The two-lock arrangement allows those resources + * to be freed as soon as either thread or key is concluded. + * + * To avoid deadlock, whenever both locks are required both the + * key and thread locks are acquired consistently in the order + * "key lock then thread lock". An exception to this exists + * when a thread calls the destructors, however, this is done + * carefully (but inelegantly) to avoid deadlock. + * + * An association is created when a thread first calls + * pthread_setspecific() on a key that has a specified + * destructor. + * + * An association is destroyed either immediately after the + * thread calls the key destructor function on thread exit, or + * when the key is deleted. + * + * Attributes: + * thread + * reference to the thread that owns the + * association. This is actually the pointer to the + * thread struct itself. Since the association is + * destroyed before the thread exits, this can never + * point to a different logical thread to the one that + * created the assoc, i.e. after thread struct reuse. + * + * key + * reference to the key that owns the association. + * + * nextKey + * The pthread_t->keys attribute is the head of a + * chain of associations that runs through the nextKey + * link. This chain provides the 1 to many relationship + * between a pthread_t and all pthread_key_t on which + * it called pthread_setspecific. + * + * prevKey + * Similarly. + * + * nextThread + * The pthread_key_t->threads attribute is the head of + * a chain of associations that runs through the + * nextThreads link. This chain provides the 1 to many + * relationship between a pthread_key_t and all the + * PThreads that have called pthread_setspecific for + * this pthread_key_t. + * + * prevThread + * Similarly. + * + * Notes: + * 1) As soon as either the key or the thread is no longer + * referencing the association, it can be destroyed. The + * association will be removed from both chains. + * + * 2) Under WIN32, an association is only created by + * pthread_setspecific if the user provided a + * destroyRoutine when they created the key. + * + * + */ + ptw32_thread_t * thread; + pthread_key_t key; + ThreadKeyAssoc *nextKey; + ThreadKeyAssoc *nextThread; + ThreadKeyAssoc *prevKey; + ThreadKeyAssoc *prevThread; +}; + + +#if defined(__CLEANUP_SEH) +/* + * -------------------------------------------------------------- + * MAKE_SOFTWARE_EXCEPTION + * This macro constructs a software exception code following + * the same format as the standard Win32 error codes as defined + * in WINERROR.H + * Values are 32 bit values laid out as follows: + * + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +---+-+-+-----------------------+-------------------------------+ + * |Sev|C|R| Facility | Code | + * +---+-+-+-----------------------+-------------------------------+ + * + * Severity Values: + */ +#define SE_SUCCESS 0x00 +#define SE_INFORMATION 0x01 +#define SE_WARNING 0x02 +#define SE_ERROR 0x03 + +#define MAKE_SOFTWARE_EXCEPTION( _severity, _facility, _exception ) \ +( (DWORD) ( ( (_severity) << 30 ) | /* Severity code */ \ + ( 1 << 29 ) | /* MS=0, User=1 */ \ + ( 0 << 28 ) | /* Reserved */ \ + ( (_facility) << 16 ) | /* Facility Code */ \ + ( (_exception) << 0 ) /* Exception Code */ \ + ) ) + +/* + * We choose one specific Facility/Error code combination to + * identify our software exceptions vs. WIN32 exceptions. + * We store our actual component and error code within + * the optional information array. + */ +#define EXCEPTION_PTW32_SERVICES \ + MAKE_SOFTWARE_EXCEPTION( SE_ERROR, \ + PTW32_SERVICES_FACILITY, \ + PTW32_SERVICES_ERROR ) + +#define PTW32_SERVICES_FACILITY 0xBAD +#define PTW32_SERVICES_ERROR 0xDEED + +#endif /* __CLEANUP_SEH */ + +/* + * Services available through EXCEPTION_PTW32_SERVICES + * and also used [as parameters to ptw32_throw()] as + * generic exception selectors. + */ + +#define PTW32_EPS_EXIT (1) +#define PTW32_EPS_CANCEL (2) + + +/* Useful macros */ +#define PTW32_MAX(a,b) ((a)<(b)?(b):(a)) +#define PTW32_MIN(a,b) ((a)>(b)?(b):(a)) + + +/* Declared in pthread_cancel.c */ +extern DWORD (*ptw32_register_cancelation) (PAPCFUNC, HANDLE, DWORD); + +/* Thread Reuse stack bottom marker. Must not be NULL or any valid pointer to memory. */ +#define PTW32_THREAD_REUSE_EMPTY ((ptw32_thread_t *)(size_t) 1) + +extern int ptw32_processInitialized; +extern ptw32_thread_t * ptw32_threadReuseTop; +extern ptw32_thread_t * ptw32_threadReuseBottom; +extern pthread_key_t ptw32_selfThreadKey; +extern pthread_key_t ptw32_cleanupKey; +extern pthread_cond_t ptw32_cond_list_head; +extern pthread_cond_t ptw32_cond_list_tail; + +extern int ptw32_mutex_default_kind; + +extern unsigned __int64 ptw32_threadSeqNumber; + +extern int ptw32_concurrency; + +extern int ptw32_features; + +extern ptw32_mcs_lock_t ptw32_thread_reuse_lock; +extern ptw32_mcs_lock_t ptw32_mutex_test_init_lock; +extern ptw32_mcs_lock_t ptw32_cond_list_lock; +extern ptw32_mcs_lock_t ptw32_cond_test_init_lock; +extern ptw32_mcs_lock_t ptw32_rwlock_test_init_lock; +extern ptw32_mcs_lock_t ptw32_spinlock_test_init_lock; + +#if defined(_UWIN) +extern int pthread_count; +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ===================== + * ===================== + * Forward Declarations + * ===================== + * ===================== + */ + + int ptw32_is_attr (const pthread_attr_t * attr); + + int ptw32_cond_check_need_init (pthread_cond_t * cond); + int ptw32_mutex_check_need_init (pthread_mutex_t * mutex); + int ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock); + + int ptw32_robust_mutex_inherit(pthread_mutex_t * mutex); + void ptw32_robust_mutex_add(pthread_mutex_t* mutex, pthread_t self); + void ptw32_robust_mutex_remove(pthread_mutex_t* mutex, ptw32_thread_t* otp); + + DWORD + ptw32_RegisterCancelation (PAPCFUNC callback, + HANDLE threadH, DWORD callback_arg); + + int ptw32_processInitialize (void); + + void ptw32_processTerminate (void); + + void ptw32_threadDestroy (pthread_t tid); + + void ptw32_pop_cleanup_all (int execute); + + pthread_t ptw32_new (void); + + pthread_t ptw32_threadReusePop (void); + + void ptw32_threadReusePush (pthread_t thread); + + int ptw32_getprocessors (int *count); + + int ptw32_setthreadpriority (pthread_t thread, int policy, int priority); + + void ptw32_rwlock_cancelwrwait (void *arg); + +#if ! (defined (__MINGW64__) || defined(__MINGW32__)) || (defined(__MSVCRT__) && ! defined(__DMC__)) + unsigned __stdcall +#else + void +#endif + ptw32_threadStart (void *vthreadParms); + + void ptw32_callUserDestroyRoutines (pthread_t thread); + + int ptw32_tkAssocCreate (ptw32_thread_t * thread, pthread_key_t key); + + void ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc); + + int ptw32_semwait (sem_t * sem); + + DWORD ptw32_relmillisecs (const struct timespec * abstime); + + void ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node); + + int ptw32_mcs_lock_try_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node); + + void ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node); + + void ptw32_mcs_node_transfer (ptw32_mcs_local_node_t * new_node, ptw32_mcs_local_node_t * old_node); + +#if defined(NEED_FTIME) + void ptw32_timespec_to_filetime (const struct timespec *ts, FILETIME * ft); + void ptw32_filetime_to_timespec (const FILETIME * ft, struct timespec *ts); +#endif + +/* Declared in misc.c */ +#if defined(NEED_CALLOC) +#define calloc(n, s) ptw32_calloc(n, s) + void *ptw32_calloc (size_t n, size_t s); +#endif + +/* Declared in private.c */ +#if defined(_MSC_VER) +/* + * Ignore the warning: + * "C++ exception specification ignored except to indicate that + * the function is not __declspec(nothrow)." + */ +#pragma warning(disable:4290) +#endif + void ptw32_throw (DWORD exception) +#if defined(__CLEANUP_CXX) + throw(ptw32_exception_cancel,ptw32_exception_exit) +#endif +; + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + + +#if defined(_UWIN_) +# if defined(_MT) +# if defined(__cplusplus) +extern "C" +{ +# endif + _CRTIMP unsigned long __cdecl _beginthread (void (__cdecl *) (void *), + unsigned, void *); + _CRTIMP void __cdecl _endthread (void); + _CRTIMP unsigned long __cdecl _beginthreadex (void *, unsigned, + unsigned (__stdcall *) (void *), + void *, unsigned, unsigned *); + _CRTIMP void __cdecl _endthreadex (unsigned); +# if defined(__cplusplus) +} +# endif +# endif +#else +# include +# endif + + +/* + * Use intrinsic versions wherever possible. VC will do this + * automatically where possible and GCC define these if available: + * __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 + * __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 + * __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + * __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 + * __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 + * + * The full set of Interlocked intrinsics in GCC are (check versions): + * type __sync_fetch_and_add (type *ptr, type value, ...) + * type __sync_fetch_and_sub (type *ptr, type value, ...) + * type __sync_fetch_and_or (type *ptr, type value, ...) + * type __sync_fetch_and_and (type *ptr, type value, ...) + * type __sync_fetch_and_xor (type *ptr, type value, ...) + * type __sync_fetch_and_nand (type *ptr, type value, ...) + * type __sync_add_and_fetch (type *ptr, type value, ...) + * type __sync_sub_and_fetch (type *ptr, type value, ...) + * type __sync_or_and_fetch (type *ptr, type value, ...) + * type __sync_and_and_fetch (type *ptr, type value, ...) + * type __sync_xor_and_fetch (type *ptr, type value, ...) + * type __sync_nand_and_fetch (type *ptr, type value, ...) + * bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...) + * type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...) + * __sync_synchronize (...) // Full memory barrier + * type __sync_lock_test_and_set (type *ptr, type value, ...) // Acquire barrier + * void __sync_lock_release (type *ptr, ...) // Release barrier + * + * These are all overloaded and take 1,2,4,8 byte scalar or pointer types. + * + * The above aren't available in Mingw32 as of gcc 4.5.2 so define our own. + */ +#if defined(__GNUC__) +# if defined(_WIN64) +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_64(location, value, comparand) \ + ({ \ + __typeof (value) _result; \ + __asm__ __volatile__ \ + ( \ + "lock\n\t" \ + "cmpxchgq %2,(%1)" \ + :"=a" (_result) \ + :"r" (location), "r" (value), "a" (comparand) \ + :"memory", "cc"); \ + _result; \ + }) +# define PTW32_INTERLOCKED_EXCHANGE_64(location, value) \ + ({ \ + __typeof (value) _result; \ + __asm__ __volatile__ \ + ( \ + "xchgq %0,(%1)" \ + :"=r" (_result) \ + :"r" (location), "0" (value) \ + :"memory", "cc"); \ + _result; \ + }) +# define PTW32_INTERLOCKED_EXCHANGE_ADD_64(location, value) \ + ({ \ + __typeof (value) _result; \ + __asm__ __volatile__ \ + ( \ + "lock\n\t" \ + "xaddq %0,(%1)" \ + :"=r" (_result) \ + :"r" (location), "0" (value) \ + :"memory", "cc"); \ + _result; \ + }) +# define PTW32_INTERLOCKED_INCREMENT_64(location) \ + ({ \ + PTW32_INTERLOCKED_LONG _temp = 1; \ + __asm__ __volatile__ \ + ( \ + "lock\n\t" \ + "xaddq %0,(%1)" \ + :"+r" (_temp) \ + :"r" (location) \ + :"memory", "cc"); \ + ++_temp; \ + }) +# define PTW32_INTERLOCKED_DECREMENT_64(location) \ + ({ \ + PTW32_INTERLOCKED_LONG _temp = -1; \ + __asm__ __volatile__ \ + ( \ + "lock\n\t" \ + "xaddq %2,(%1)" \ + :"+r" (_temp) \ + :"r" (location) \ + :"memory", "cc"); \ + --_temp; \ + }) +#endif +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(location, value, comparand) \ + ({ \ + __typeof (value) _result; \ + __asm__ __volatile__ \ + ( \ + "lock\n\t" \ + "cmpxchgl %2,(%1)" \ + :"=a" (_result) \ + :"r" (location), "r" (value), "a" (comparand) \ + :"memory", "cc"); \ + _result; \ + }) +# define PTW32_INTERLOCKED_EXCHANGE_LONG(location, value) \ + ({ \ + __typeof (value) _result; \ + __asm__ __volatile__ \ + ( \ + "xchgl %0,(%1)" \ + :"=r" (_result) \ + :"r" (location), "0" (value) \ + :"memory", "cc"); \ + _result; \ + }) +# define PTW32_INTERLOCKED_EXCHANGE_ADD_LONG(location, value) \ + ({ \ + __typeof (value) _result; \ + __asm__ __volatile__ \ + ( \ + "lock\n\t" \ + "xaddl %0,(%1)" \ + :"=r" (_result) \ + :"r" (location), "0" (value) \ + :"memory", "cc"); \ + _result; \ + }) +# define PTW32_INTERLOCKED_INCREMENT_LONG(location) \ + ({ \ + PTW32_INTERLOCKED_LONG _temp = 1; \ + __asm__ __volatile__ \ + ( \ + "lock\n\t" \ + "xaddl %0,(%1)" \ + :"+r" (_temp) \ + :"r" (location) \ + :"memory", "cc"); \ + ++_temp; \ + }) +# define PTW32_INTERLOCKED_DECREMENT_LONG(location) \ + ({ \ + PTW32_INTERLOCKED_LONG _temp = -1; \ + __asm__ __volatile__ \ + ( \ + "lock\n\t" \ + "xaddl %0,(%1)" \ + :"+r" (_temp) \ + :"r" (location) \ + :"memory", "cc"); \ + --_temp; \ + }) +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR(location, value, comparand) \ + PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE((PTW32_INTERLOCKED_SIZEPTR)location, \ + (PTW32_INTERLOCKED_SIZE)value, \ + (PTW32_INTERLOCKED_SIZE)comparand) +# define PTW32_INTERLOCKED_EXCHANGE_PTR(location, value) \ + PTW32_INTERLOCKED_EXCHANGE_SIZE((PTW32_INTERLOCKED_SIZEPTR)location, \ + (PTW32_INTERLOCKED_SIZE)value) +#else +# if defined(_WIN64) +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_64 InterlockedCompareExchange64 +# define PTW32_INTERLOCKED_EXCHANGE_64 InterlockedExchange64 +# define PTW32_INTERLOCKED_EXCHANGE_ADD_64 InterlockedExchangeAdd64 +# define PTW32_INTERLOCKED_INCREMENT_64 InterlockedIncrement64 +# define PTW32_INTERLOCKED_DECREMENT_64 InterlockedDecrement64 +# endif +# if defined(_MSC_VER) && _MSC_VER < 1300 && !defined(_WIN64) /* MSVC 6 */ +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG(location, value, comparand) \ + ((LONG)InterlockedCompareExchange((PVOID *)(location), (PVOID)(value), (PVOID)(comparand))) +# else +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG InterlockedCompareExchange +# endif +# define PTW32_INTERLOCKED_EXCHANGE_LONG InterlockedExchange +# define PTW32_INTERLOCKED_EXCHANGE_ADD_LONG InterlockedExchangeAdd +# define PTW32_INTERLOCKED_INCREMENT_LONG InterlockedIncrement +# define PTW32_INTERLOCKED_DECREMENT_LONG InterlockedDecrement +# if defined(_MSC_VER) && _MSC_VER < 1300 && !defined(_WIN64) /* MSVC 6 */ +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR InterlockedCompareExchange +# define PTW32_INTERLOCKED_EXCHANGE_PTR(location, value) \ + ((PVOID)InterlockedExchange((LPLONG)(location), (LONG)(value))) +# else +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR InterlockedCompareExchangePointer +# define PTW32_INTERLOCKED_EXCHANGE_PTR InterlockedExchangePointer +# endif +#endif +#if defined(_WIN64) +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE PTW32_INTERLOCKED_COMPARE_EXCHANGE_64 +# define PTW32_INTERLOCKED_EXCHANGE_SIZE PTW32_INTERLOCKED_EXCHANGE_64 +# define PTW32_INTERLOCKED_EXCHANGE_ADD_SIZE PTW32_INTERLOCKED_EXCHANGE_ADD_64 +# define PTW32_INTERLOCKED_INCREMENT_SIZE PTW32_INTERLOCKED_INCREMENT_64 +# define PTW32_INTERLOCKED_DECREMENT_SIZE PTW32_INTERLOCKED_DECREMENT_64 +#else +# define PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG +# define PTW32_INTERLOCKED_EXCHANGE_SIZE PTW32_INTERLOCKED_EXCHANGE_LONG +# define PTW32_INTERLOCKED_EXCHANGE_ADD_SIZE PTW32_INTERLOCKED_EXCHANGE_ADD_LONG +# define PTW32_INTERLOCKED_INCREMENT_SIZE PTW32_INTERLOCKED_INCREMENT_LONG +# define PTW32_INTERLOCKED_DECREMENT_SIZE PTW32_INTERLOCKED_DECREMENT_LONG +#endif + +#if defined(NEED_CREATETHREAD) + +/* + * Macro uses args so we can cast start_proc to LPTHREAD_START_ROUTINE + * in order to avoid warnings because of return type + */ + +#define _beginthreadex(security, \ + stack_size, \ + start_proc, \ + arg, \ + flags, \ + pid) \ + CreateThread(security, \ + stack_size, \ + (LPTHREAD_START_ROUTINE) start_proc, \ + arg, \ + flags, \ + pid) + +#define _endthreadex ExitThread + +#endif /* NEED_CREATETHREAD */ + + +#endif /* _IMPLEMENT_H */ diff --git a/libs/pthreads/src/misc.c b/libs/pthreads/src/misc.c new file mode 100644 index 0000000000..06d1d21374 --- /dev/null +++ b/libs/pthreads/src/misc.c @@ -0,0 +1,50 @@ +/* + * misc.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_kill.c" +#include "pthread_once.c" +#include "pthread_self.c" +#include "pthread_equal.c" +#include "pthread_setconcurrency.c" +#include "pthread_getconcurrency.c" +#include "ptw32_new.c" +#include "ptw32_calloc.c" +#include "ptw32_reuse.c" +#include "w32_CancelableWait.c" diff --git a/libs/pthreads/src/mutex.c b/libs/pthreads/src/mutex.c new file mode 100644 index 0000000000..c2b3607ca2 --- /dev/null +++ b/libs/pthreads/src/mutex.c @@ -0,0 +1,62 @@ +/* + * mutex.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if ! defined(_UWIN) && ! defined(WINCE) +# include +#endif +#if !defined(NEED_FTIME) +#include +#endif +#include "pthread.h" +#include "implement.h" + + +#include "ptw32_mutex_check_need_init.c" +#include "pthread_mutex_init.c" +#include "pthread_mutex_destroy.c" +#include "pthread_mutexattr_init.c" +#include "pthread_mutexattr_destroy.c" +#include "pthread_mutexattr_getpshared.c" +#include "pthread_mutexattr_setpshared.c" +#include "pthread_mutexattr_settype.c" +#include "pthread_mutexattr_gettype.c" +#include "pthread_mutexattr_setrobust.c" +#include "pthread_mutexattr_getrobust.c" +#include "pthread_mutex_lock.c" +#include "pthread_mutex_timedlock.c" +#include "pthread_mutex_unlock.c" +#include "pthread_mutex_trylock.c" +#include "pthread_mutex_consistent.c" diff --git a/libs/pthreads/src/need_errno.h b/libs/pthreads/src/need_errno.h new file mode 100644 index 0000000000..abf1c95574 --- /dev/null +++ b/libs/pthreads/src/need_errno.h @@ -0,0 +1,145 @@ +/*** +* errno.h - system wide error numbers (set by system calls) +* +* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. +* +* Purpose: +* This file defines the system-wide error numbers (set by +* system calls). Conforms to the XENIX standard. Extended +* for compatibility with Uniforum standard. +* [System V] +* +* [Public] +* +****/ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if !defined(_INC_ERRNO) +#define _INC_ERRNO + +#if !defined(_WIN32) +#error ERROR: Only Win32 targets supported! +#endif + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + + +/* Define _CRTIMP */ + +#ifndef _CRTIMP +#if defined(_DLL) +#define _CRTIMP __declspec(dllimport) +#else /* ndef _DLL */ +#define _CRTIMP +#endif /* _DLL */ +#endif /* _CRTIMP */ + + +/* Define __cdecl for non-Microsoft compilers */ + +#if ( !defined(_MSC_VER) && !defined(__cdecl) ) +#define __cdecl +#endif + +/* Define _CRTAPI1 (for compatibility with the NT SDK) */ + +#if !defined(_CRTAPI1) +#if _MSC_VER >= 800 && _M_IX86 >= 300 +#define _CRTAPI1 __cdecl +#else +#define _CRTAPI1 +#endif +#endif + +#if !defined(PTW32_STATIC_LIB) +# if defined(PTW32_BUILD) +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* declare reference to errno */ + +#if (defined(_MT) || defined(_MD) || defined(_DLL)) && !defined(_MAC) +PTW32_DLLPORT int * __cdecl _errno(void); +#define errno (*_errno()) +#else /* ndef _MT && ndef _MD && ndef _DLL */ +_CRTIMP extern int errno; +#endif /* _MT || _MD || _DLL */ + +/* Error Codes */ + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 36 + +/* defined differently in winsock.h on WinCE */ +#if !defined(ENAMETOOLONG) +#define ENAMETOOLONG 38 +#endif + +#define ENOLCK 39 +#define ENOSYS 40 + +/* defined differently in winsock.h on WinCE */ +#if !defined(ENOTEMPTY) +#define ENOTEMPTY 41 +#endif + +#define EILSEQ 42 + +/* POSIX 2008 - robust mutexes */ +#define EOWNERDEAD 43 +#define ENOTRECOVERABLE 44 + +/* + * Support EDEADLOCK for compatibiity with older MS-C versions. + */ +#define EDEADLOCK EDEADLK + +#if defined(__cplusplus) +} +#endif + +#endif /* _INC_ERRNO */ diff --git a/libs/pthreads/src/nonportable.c b/libs/pthreads/src/nonportable.c new file mode 100644 index 0000000000..742cb969b4 --- /dev/null +++ b/libs/pthreads/src/nonportable.c @@ -0,0 +1,47 @@ +/* + * nonportable.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#include "pthread_mutexattr_setkind_np.c" +#include "pthread_mutexattr_getkind_np.c" +#include "pthread_getw32threadhandle_np.c" +#include "pthread_getunique_np.c" +#include "pthread_delay_np.c" +#include "pthread_num_processors_np.c" +#include "pthread_win32_attach_detach_np.c" +#include "pthread_timechange_handler_np.c" diff --git a/libs/pthreads/src/private.c b/libs/pthreads/src/private.c new file mode 100644 index 0000000000..1b1ccb7c52 --- /dev/null +++ b/libs/pthreads/src/private.c @@ -0,0 +1,54 @@ +/* + * private.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#include "ptw32_MCS_lock.c" +#include "ptw32_is_attr.c" +#include "ptw32_processInitialize.c" +#include "ptw32_processTerminate.c" +#include "ptw32_threadStart.c" +#include "ptw32_threadDestroy.c" +#include "ptw32_tkAssocCreate.c" +#include "ptw32_tkAssocDestroy.c" +#include "ptw32_callUserDestroyRoutines.c" +#include "ptw32_semwait.c" +#include "ptw32_timespec.c" +#include "ptw32_relmillisecs.c" +#include "ptw32_throw.c" +#include "ptw32_getprocessors.c" diff --git a/libs/pthreads/src/pthread.c b/libs/pthreads/src/pthread.c new file mode 100644 index 0000000000..60b53412be --- /dev/null +++ b/libs/pthreads/src/pthread.c @@ -0,0 +1,66 @@ +/* + * pthread.c + * + * Description: + * This translation unit agregates pthreads-win32 translation units. + * It is used for inline optimisation of the library, + * maximising for speed at the expense of size. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* The following are ordered for inlining */ + +#include "private.c" +#include "attr.c" +#include "barrier.c" +#include "cancel.c" +#include "cleanup.c" +#include "condvar.c" +#include "create.c" +#include "dll.c" +#include "autostatic.c" +#include "errno.c" +#include "exit.c" +#include "fork.c" +#include "global.c" +#include "misc.c" +#include "mutex.c" +#include "nonportable.c" +#include "rwlock.c" +#include "sched.c" +#include "semaphore.c" +#include "signal.c" +#include "spin.c" +#include "sync.c" +#include "tsd.c" diff --git a/libs/pthreads/src/pthread.h b/libs/pthreads/src/pthread.h new file mode 100644 index 0000000000..32ff72bb54 --- /dev/null +++ b/libs/pthreads/src/pthread.h @@ -0,0 +1,1368 @@ +/* This is an implementation of the threads API of POSIX 1003.1-2001. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined( PTHREAD_H ) +#define PTHREAD_H + +/* + * See the README file for an explanation of the pthreads-win32 version + * numbering scheme and how the DLL is named etc. + */ +#define PTW32_VERSION 2,9,1,0 +#define PTW32_VERSION_STRING "2, 9, 1, 0\0" + +/* There are three implementations of cancel cleanup. + * Note that pthread.h is included in both application + * compilation units and also internally for the library. + * The code here and within the library aims to work + * for all reasonable combinations of environments. + * + * The three implementations are: + * + * WIN32 SEH + * C + * C++ + * + * Please note that exiting a push/pop block via + * "return", "exit", "break", or "continue" will + * lead to different behaviour amongst applications + * depending upon whether the library was built + * using SEH, C++, or C. For example, a library built + * with SEH will call the cleanup routine, while both + * C++ and C built versions will not. + */ + +/* + * Define defaults for cleanup code. + * Note: Unless the build explicitly defines one of the following, then + * we default to standard C style cleanup. This style uses setjmp/longjmp + * in the cancelation and thread exit implementations and therefore won't + * do stack unwinding if linked to applications that have it (e.g. + * C++ apps). This is currently consistent with most/all commercial Unix + * POSIX threads implementations. + */ +#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) +# define __CLEANUP_C +#endif + +#if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) +#error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. +#endif + +/* + * Stop here if we are being included by the resource compiler. + */ +#if !defined(RC_INVOKED) + +#undef PTW32_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_LEVEL +#define PTW32_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_LEVEL +#define PTW32_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_LEVEL_MAX 3 + +#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_LEVEL) +#define PTW32_LEVEL PTW32_LEVEL_MAX +/* Include everything */ +#endif + +#if defined(_UWIN) +# define HAVE_STRUCT_TIMESPEC 1 +# define HAVE_SIGNAL_H 1 +# undef HAVE_PTW32_CONFIG_H +# pragma comment(lib, "pthread") +#endif + +/* + * ------------------------------------------------------------- + * + * + * Module: pthread.h + * + * Purpose: + * Provides an implementation of PThreads based upon the + * standard: + * + * POSIX 1003.1-2001 + * and + * The Single Unix Specification version 3 + * + * (these two are equivalent) + * + * in order to enhance code portability between Windows, + * various commercial Unix implementations, and Linux. + * + * See the ANNOUNCE file for a full list of conforming + * routines and defined constants, and a list of missing + * routines and constants not defined in this implementation. + * + * Authors: + * There have been many contributors to this library. + * The initial implementation was contributed by + * John Bossom, and several others have provided major + * sections or revisions of parts of the implementation. + * Often significant effort has been contributed to + * find and fix important bugs and other problems to + * improve the reliability of the library, which sometimes + * is not reflected in the amount of code which changed as + * result. + * As much as possible, the contributors are acknowledged + * in the ChangeLog file in the source code distribution + * where their changes are noted in detail. + * + * Contributors are listed in the CONTRIBUTORS file. + * + * As usual, all bouquets go to the contributors, and all + * brickbats go to the project maintainer. + * + * Maintainer: + * The code base for this project is coordinated and + * eventually pre-tested, packaged, and made available by + * + * Ross Johnson + * + * QA Testers: + * Ultimately, the library is tested in the real world by + * a host of competent and demanding scientists and + * engineers who report bugs and/or provide solutions + * which are then fixed or incorporated into subsequent + * versions of the library. Each time a bug is fixed, a + * test case is written to prove the fix and ensure + * that later changes to the code don't reintroduce the + * same error. The number of test cases is slowly growing + * and therefore so is the code reliability. + * + * Compliance: + * See the file ANNOUNCE for the list of implemented + * and not-implemented routines and defined options. + * Of course, these are all defined is this file as well. + * + * Web site: + * The source code and other information about this library + * are available from + * + * http://sources.redhat.com/pthreads-win32/ + * + * ------------------------------------------------------------- + */ + +/* Try to avoid including windows.h */ +#if (defined(__MINGW64__) || defined(__MINGW32__)) && defined(__cplusplus) +#define PTW32_INCLUDE_WINDOWS_H +#endif + +#if defined(PTW32_INCLUDE_WINDOWS_H) +#include +#endif + +#if defined(_MSC_VER) && _MSC_VER < 1300 || defined(__DMC__) +/* + * VC++6.0 or early compiler's header has no DWORD_PTR type. + */ +typedef unsigned long DWORD_PTR; +typedef unsigned long ULONG_PTR; +#endif +/* + * ----------------- + * autoconf switches + * ----------------- + */ + +#if defined(HAVE_PTW32_CONFIG_H) +#include "config.h" +#endif /* HAVE_PTW32_CONFIG_H */ + +#if !defined(NEED_FTIME) +#include +#else /* NEED_FTIME */ +/* use native WIN32 time API */ +#endif /* NEED_FTIME */ + +#if defined(HAVE_SIGNAL_H) +#include +#endif /* HAVE_SIGNAL_H */ + +#include + +/* + * Boolean values to make us independent of system includes. + */ +enum { + PTW32_FALSE = 0, + PTW32_TRUE = (! PTW32_FALSE) +}; + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#if !defined(PTW32_CONFIG_H) +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_MSC_VER) || defined(__MINGW64__) +# define HAVE_STRUCT_TIMESPEC +# define HAVE_MODE_T +# elif defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +#if defined(NEED_ERRNO) +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Several systems don't define some error numbers. + */ +#if !defined(ENOTSUP) +# define ENOTSUP 48 /* This is the value in Solaris. */ +#endif + +#if !defined(ETIMEDOUT) +# define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */ +#endif + +#if !defined(ENOSYS) +# define ENOSYS 140 /* Semi-arbitrary value */ +#endif + +#if !defined(EDEADLK) +# if defined(EDEADLOCK) +# define EDEADLK EDEADLOCK +# else +# define EDEADLK 36 /* This is the value in MSVC. */ +# endif +#endif + +/* POSIX 2008 - related to robust mutexes */ +#if !defined(EOWNERDEAD) +# define EOWNERDEAD 43 +#endif +#if !defined(ENOTRECOVERABLE) +# define ENOTRECOVERABLE 44 +#endif + +#include + +/* + * To avoid including windows.h we define only those things that we + * actually need from it. + */ +#if !defined(PTW32_INCLUDE_WINDOWS_H) +#if !defined(HANDLE) +# define PTW32__HANDLE_DEF +# define HANDLE void * +#endif +#if !defined(DWORD) +# define PTW32__DWORD_DEF +# define DWORD unsigned long +#endif +#endif + +#if !defined(HAVE_STRUCT_TIMESPEC) +#define HAVE_STRUCT_TIMESPEC +#if !defined(_TIMESPEC_DEFINED) +#define _TIMESPEC_DEFINED +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif /* _TIMESPEC_DEFINED */ +#endif /* HAVE_STRUCT_TIMESPEC */ + +#if !defined(SIG_BLOCK) +#define SIG_BLOCK 0 +#endif /* SIG_BLOCK */ + +#if !defined(SIG_UNBLOCK) +#define SIG_UNBLOCK 1 +#endif /* SIG_UNBLOCK */ + +#if !defined(SIG_SETMASK) +#define SIG_SETMASK 2 +#endif /* SIG_SETMASK */ + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +/* + * ------------------------------------------------------------- + * + * POSIX 1003.1-2001 Options + * ========================= + * + * Options are normally set in , which is not provided + * with pthreads-win32. + * + * For conformance with the Single Unix Specification (version 3), all of the + * options below are defined, and have a value of either -1 (not supported) + * or 200112L (supported). + * + * These options can neither be left undefined nor have a value of 0, because + * either indicates that sysconf(), which is not implemented, may be used at + * runtime to check the status of the option. + * + * _POSIX_THREADS (== 200112L) + * If == 200112L, you can use threads + * + * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) + * If == 200112L, you can control the size of a thread's + * stack + * pthread_attr_getstacksize + * pthread_attr_setstacksize + * + * _POSIX_THREAD_ATTR_STACKADDR (== -1) + * If == 200112L, you can allocate and control a thread's + * stack. If not supported, the following functions + * will return ENOSYS, indicating they are not + * supported: + * pthread_attr_getstackaddr + * pthread_attr_setstackaddr + * + * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) + * If == 200112L, you can use realtime scheduling. + * This option indicates that the behaviour of some + * implemented functions conforms to the additional TPS + * requirements in the standard. E.g. rwlocks favour + * writers over readers when threads have equal priority. + * + * _POSIX_THREAD_PRIO_INHERIT (== -1) + * If == 200112L, you can create priority inheritance + * mutexes. + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PRIO_PROTECT (== -1) + * If == 200112L, you can create priority ceiling mutexes + * Indicates the availability of: + * pthread_mutex_getprioceiling + * pthread_mutex_setprioceiling + * pthread_mutexattr_getprioceiling + * pthread_mutexattr_getprotocol + + * pthread_mutexattr_setprioceiling + * pthread_mutexattr_setprotocol + + * + * _POSIX_THREAD_PROCESS_SHARED (== -1) + * If set, you can create mutexes and condition + * variables that can be shared with another + * process.If set, indicates the availability + * of: + * pthread_mutexattr_getpshared + * pthread_mutexattr_setpshared + * pthread_condattr_getpshared + * pthread_condattr_setpshared + * + * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) + * If == 200112L you can use the special *_r library + * functions that provide thread-safe behaviour + * + * _POSIX_READER_WRITER_LOCKS (== 200112L) + * If == 200112L, you can use read/write locks + * + * _POSIX_SPIN_LOCKS (== 200112L) + * If == 200112L, you can use spin locks + * + * _POSIX_BARRIERS (== 200112L) + * If == 200112L, you can use barriers + * + * + These functions provide both 'inherit' and/or + * 'protect' protocol, based upon these macro + * settings. + * + * ------------------------------------------------------------- + */ + +/* + * POSIX Options + */ +#undef _POSIX_THREADS +#define _POSIX_THREADS 200809L + +#undef _POSIX_READER_WRITER_LOCKS +#define _POSIX_READER_WRITER_LOCKS 200809L + +#undef _POSIX_SPIN_LOCKS +#define _POSIX_SPIN_LOCKS 200809L + +#undef _POSIX_BARRIERS +#define _POSIX_BARRIERS 200809L + +#undef _POSIX_THREAD_SAFE_FUNCTIONS +#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L + +#undef _POSIX_THREAD_ATTR_STACKSIZE +#define _POSIX_THREAD_ATTR_STACKSIZE 200809L + +/* + * The following options are not supported + */ +#undef _POSIX_THREAD_ATTR_STACKADDR +#define _POSIX_THREAD_ATTR_STACKADDR -1 + +#undef _POSIX_THREAD_PRIO_INHERIT +#define _POSIX_THREAD_PRIO_INHERIT -1 + +#undef _POSIX_THREAD_PRIO_PROTECT +#define _POSIX_THREAD_PRIO_PROTECT -1 + +/* TPS is not fully supported. */ +#undef _POSIX_THREAD_PRIORITY_SCHEDULING +#define _POSIX_THREAD_PRIORITY_SCHEDULING -1 + +#undef _POSIX_THREAD_PROCESS_SHARED +#define _POSIX_THREAD_PROCESS_SHARED -1 + + +/* + * POSIX 1003.1-2001 Limits + * =========================== + * + * These limits are normally set in , which is not provided with + * pthreads-win32. + * + * PTHREAD_DESTRUCTOR_ITERATIONS + * Maximum number of attempts to destroy + * a thread's thread-specific data on + * termination (must be at least 4) + * + * PTHREAD_KEYS_MAX + * Maximum number of thread-specific data keys + * available per process (must be at least 128) + * + * PTHREAD_STACK_MIN + * Minimum supported stack size for a thread + * + * PTHREAD_THREADS_MAX + * Maximum number of threads supported per + * process (must be at least 64). + * + * SEM_NSEMS_MAX + * The maximum number of semaphores a process can have. + * (must be at least 256) + * + * SEM_VALUE_MAX + * The maximum value a semaphore can have. + * (must be at least 32767) + * + */ +#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS +#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 + +#undef PTHREAD_DESTRUCTOR_ITERATIONS +#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS + +#undef _POSIX_THREAD_KEYS_MAX +#define _POSIX_THREAD_KEYS_MAX 128 + +#undef PTHREAD_KEYS_MAX +#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX + +#undef PTHREAD_STACK_MIN +#define PTHREAD_STACK_MIN 0 + +#undef _POSIX_THREAD_THREADS_MAX +#define _POSIX_THREAD_THREADS_MAX 64 + + /* Arbitrary value */ +#undef PTHREAD_THREADS_MAX +#define PTHREAD_THREADS_MAX 2019 + +#undef _POSIX_SEM_NSEMS_MAX +#define _POSIX_SEM_NSEMS_MAX 256 + + /* Arbitrary value */ +#undef SEM_NSEMS_MAX +#define SEM_NSEMS_MAX 1024 + +#undef _POSIX_SEM_VALUE_MAX +#define _POSIX_SEM_VALUE_MAX 32767 + +#undef SEM_VALUE_MAX +#define SEM_VALUE_MAX INT_MAX + + +#if defined(__GNUC__) && !defined(__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#if !defined(PTW32_STATIC_LIB) +# if defined(PTW32_BUILD) +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * The Open Watcom C/C++ compiler uses a non-standard calling convention + * that passes function args in registers unless __cdecl is explicitly specified + * in exposed function prototypes. + * + * We force all calls to cdecl even though this could slow Watcom code down + * slightly. If you know that the Watcom compiler will be used to build both + * the DLL and application, then you can probably define this as a null string. + * Remember that pthread.h (this file) is used for both the DLL and application builds. + */ +#define PTW32_CDECL __cdecl + +#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX +# include +#else +/* + * Generic handle type - intended to extend uniqueness beyond + * that available with a simple pointer. It should scale for either + * IA-32 or IA-64. + */ +typedef struct { + void * p; /* Pointer to actual object */ + unsigned int x; /* Extra information - reuse count etc */ +} ptw32_handle_t; + +typedef ptw32_handle_t pthread_t; +typedef struct pthread_attr_t_ * pthread_attr_t; +typedef struct pthread_once_t_ pthread_once_t; +typedef struct pthread_key_t_ * pthread_key_t; +typedef struct pthread_mutex_t_ * pthread_mutex_t; +typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; +typedef struct pthread_cond_t_ * pthread_cond_t; +typedef struct pthread_condattr_t_ * pthread_condattr_t; +#endif +typedef struct pthread_rwlock_t_ * pthread_rwlock_t; +typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; +typedef struct pthread_spinlock_t_ * pthread_spinlock_t; +typedef struct pthread_barrier_t_ * pthread_barrier_t; +typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; + +/* + * ==================== + * ==================== + * POSIX Threads + * ==================== + * ==================== + */ + +enum { +/* + * pthread_attr_{get,set}detachstate + */ + PTHREAD_CREATE_JOINABLE = 0, /* Default */ + PTHREAD_CREATE_DETACHED = 1, + +/* + * pthread_attr_{get,set}inheritsched + */ + PTHREAD_INHERIT_SCHED = 0, + PTHREAD_EXPLICIT_SCHED = 1, /* Default */ + +/* + * pthread_{get,set}scope + */ + PTHREAD_SCOPE_PROCESS = 0, + PTHREAD_SCOPE_SYSTEM = 1, /* Default */ + +/* + * pthread_setcancelstate paramters + */ + PTHREAD_CANCEL_ENABLE = 0, /* Default */ + PTHREAD_CANCEL_DISABLE = 1, + +/* + * pthread_setcanceltype parameters + */ + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_DEFERRED = 1, /* Default */ + +/* + * pthread_mutexattr_{get,set}pshared + * pthread_condattr_{get,set}pshared + */ + PTHREAD_PROCESS_PRIVATE = 0, + PTHREAD_PROCESS_SHARED = 1, + +/* + * pthread_mutexattr_{get,set}robust + */ + PTHREAD_MUTEX_STALLED = 0, /* Default */ + PTHREAD_MUTEX_ROBUST = 1, + +/* + * pthread_barrier_wait + */ + PTHREAD_BARRIER_SERIAL_THREAD = -1 +}; + +/* + * ==================== + * ==================== + * Cancelation + * ==================== + * ==================== + */ +#define PTHREAD_CANCELED ((void *)(size_t) -1) + + +/* + * ==================== + * ==================== + * Once Key + * ==================== + * ==================== + */ +#define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} + +struct pthread_once_t_ +{ + int done; /* indicates if user function has been executed */ + void * lock; + int reserved1; + int reserved2; +}; + + +/* + * ==================== + * ==================== + * Object initialisers + * ==================== + * ==================== + */ +#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -1) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -2) +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -3) + +/* + * Compatibility with LinuxThreads + */ +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER +#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER + +#define PTHREAD_COND_INITIALIZER ((pthread_cond_t)(size_t) -1) + +#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t)(size_t) -1) + +#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t)(size_t) -1) + + +/* + * Mutex types. + */ +enum +{ + /* Compatibility with LinuxThreads */ + PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, + /* For compatibility with POSIX */ + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + + +typedef struct ptw32_cleanup_t ptw32_cleanup_t; + +#if defined(_MSC_VER) +/* Disable MSVC 'anachronism used' warning */ +#pragma warning( disable : 4229 ) +#endif + +typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); + +#if defined(_MSC_VER) +#pragma warning( default : 4229 ) +#endif + +struct ptw32_cleanup_t +{ + ptw32_cleanup_callback_t routine; + void *arg; + struct ptw32_cleanup_t *prev; +}; + +#if defined(__CLEANUP_SEH) + /* + * WIN32 SEH version of cancel cleanup. + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ + _cleanup.arg = (_arg); \ + __try \ + { \ + +#define pthread_cleanup_pop( _execute ) \ + } \ + __finally \ + { \ + if( _execute || AbnormalTermination()) \ + { \ + (*(_cleanup.routine))( _cleanup.arg ); \ + } \ + } \ + } + +#else /* __CLEANUP_SEH */ + +#if defined(__CLEANUP_C) + + /* + * C implementation of PThreads cancel cleanup + */ + +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + ptw32_cleanup_t _cleanup; \ + \ + ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ + +#define pthread_cleanup_pop( _execute ) \ + (void) ptw32_pop_cleanup( _execute ); \ + } + +#else /* __CLEANUP_C */ + +#if defined(__CLEANUP_CXX) + + /* + * C++ version of cancel cleanup. + * - John E. Bossom. + */ + + class PThreadCleanup { + /* + * PThreadCleanup + * + * Purpose + * This class is a C++ helper class that is + * used to implement pthread_cleanup_push/ + * pthread_cleanup_pop. + * The destructor of this class automatically + * pops the pushed cleanup routine regardless + * of how the code exits the scope + * (i.e. such as by an exception) + */ + ptw32_cleanup_callback_t cleanUpRout; + void * obj; + int executeIt; + + public: + PThreadCleanup() : + cleanUpRout( 0 ), + obj( 0 ), + executeIt( 0 ) + /* + * No cleanup performed + */ + { + } + + PThreadCleanup( + ptw32_cleanup_callback_t routine, + void * arg ) : + cleanUpRout( routine ), + obj( arg ), + executeIt( 1 ) + /* + * Registers a cleanup routine for 'arg' + */ + { + } + + ~PThreadCleanup() + { + if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) + { + (void) (*cleanUpRout)( obj ); + } + } + + void execute( int exec ) + { + executeIt = exec; + } + }; + + /* + * C++ implementation of PThreads cancel cleanup; + * This implementation takes advantage of a helper + * class who's destructor automatically calls the + * cleanup routine if we exit our scope weirdly + */ +#define pthread_cleanup_push( _rout, _arg ) \ + { \ + PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ + (void *) (_arg) ); + +#define pthread_cleanup_pop( _execute ) \ + cleanup.execute( _execute ); \ + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + +/* + * =============== + * =============== + * Methods + * =============== + * =============== + */ + +/* + * PThread Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, + int *detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, + void **stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, + size_t * stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, + int detachstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, + void *stackaddr); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, + size_t stacksize); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (const pthread_attr_t *, + int *); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, + int inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(const pthread_attr_t * attr, + int * inheritsched); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, + int); + +PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, + int *); + +/* + * PThread Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, + const pthread_attr_t * attr, + void *(PTW32_CDECL *start) (void *), + void *arg); + +PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); + +PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, + pthread_t t2); + +PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); + +PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, + void **value_ptr); + +PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, + int *oldstate); + +PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, + int *oldtype); + +PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); + +PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, + void (PTW32_CDECL *init_routine) (void)); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX +PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); + +PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, + ptw32_cleanup_callback_t routine, + void *arg); +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread Specific Data Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, + void (PTW32_CDECL *destructor) (void *)); + +PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); + +PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, + const void *value); + +PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); + + +/* + * Mutex Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, + int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust( + pthread_mutexattr_t *attr, + int robust); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust( + const pthread_mutexattr_t * attr, + int * robust); + +/* + * Barrier Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t + * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, + int pshared); + +/* + * Mutex Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex); + +/* + * Spinlock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); + +/* + * Barrier Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned int count); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); + +PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); + +/* + * Condition Variable Attribute Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, + int pshared); + +/* + * Condition Variable Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, + const pthread_condattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, + pthread_mutex_t * mutex); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); + +PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); + +/* + * Scheduling + */ +PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, + int policy, + const struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, + int *policy, + struct sched_param *param); + +PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); + +PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); + +/* + * Read-Write Lock Functions + */ +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, + const pthread_rwlockattr_t *attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, + const struct timespec *abstime); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared); + +PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, + int pshared); + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 + +/* + * Signal Functions. Should be defined in but MSVC and MinGW32 + * already have signal.h that don't define these. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); + +/* + * Non-portable functions + */ + +/* + * Compatibility with Linux. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, + int kind); +PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, + int *kind); + +/* + * Possibly supported by other POSIX threads implementations + */ +PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); +PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); +PTW32_DLLPORT unsigned __int64 PTW32_CDECL pthread_getunique_np(pthread_t thread); + +/* + * Useful if an application wants to statically link + * the lib rather than load the DLL at run-time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); +PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); + +/* + * Features that are auto-detected at load/run time. + */ +PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); +enum ptw32_features { + PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ + PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ +}; + +/* + * Register a system time change with the library. + * Causes the library to perform various functions + * in response to the change. Should be called whenever + * the application's top level window receives a + * WM_TIMECHANGE message. It can be passed directly to + * pthread_create() as a new thread if desired. + */ +PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); + +#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* + * Returns the Win32 HANDLE for the POSIX thread. + */ +PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); +/* + * Returns the win32 thread ID for POSIX thread. + */ +PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np (pthread_t thread); + + +/* + * Protected Methods + * + * This function blocks until the given WIN32 handle + * is signaled or pthread_cancel had been called. + * This function allows the caller to hook into the + * PThreads cancel mechanism. It is implemented using + * + * WaitForMultipleObjects + * + * on 'waitHandle' and a manually reset WIN32 Event + * used to implement pthread_cancel. The 'timeout' + * argument to TimedWait is simply passed to + * WaitForMultipleObjects. + */ +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); +PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, + DWORD timeout); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +/* + * Thread-Safe C Runtime Library Mappings. + */ +#if !defined(_UWIN) +# if defined(NEED_ERRNO) + PTW32_DLLPORT int * PTW32_CDECL _errno( void ); +# else +# if !defined(errno) +# if (defined(_MT) || defined(_DLL)) + __declspec(dllimport) extern int * __cdecl _errno(void); +# define errno (*_errno()) +# endif +# endif +# endif +#endif + +/* + * Some compiler environments don't define some things. + */ +#if defined(__BORLANDC__) +# define _ftime ftime +# define _timeb timeb +#endif + +#if defined(__cplusplus) + +/* + * Internal exceptions + */ +class ptw32_exception {}; +class ptw32_exception_cancel : public ptw32_exception {}; +class ptw32_exception_exit : public ptw32_exception {}; + +#endif + +#if PTW32_LEVEL >= PTW32_LEVEL_MAX + +/* FIXME: This is only required if the library was built using SEH */ +/* + * Get internal SEH tag + */ +PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); + +#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ + +#if !defined(PTW32_BUILD) + +#if defined(__CLEANUP_SEH) + +/* + * Redefine the SEH __except keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#define __except( E ) \ + __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ + ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) + +#endif /* __CLEANUP_SEH */ + +#if defined(__CLEANUP_CXX) + +/* + * Redefine the C++ catch keyword to ensure that applications + * propagate our internal exceptions up to the library's internal handlers. + */ +#if defined(_MSC_VER) + /* + * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' + * if you want Pthread-Win32 cancelation and pthread_exit to work. + */ + +#if !defined(PtW32NoCatchWarn) + +#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") +#pragma message("------------------------------------------------------------------") +#pragma message("When compiling applications with MSVC++ and C++ exception handling:") +#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") +#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") +#pragma message(" cancelation and pthread_exit to work. For example:") +#pragma message("") +#pragma message(" #if defined(PtW32CatchAll)") +#pragma message(" PtW32CatchAll") +#pragma message(" #else") +#pragma message(" catch(...)") +#pragma message(" #endif") +#pragma message(" {") +#pragma message(" /* Catchall block processing */") +#pragma message(" }") +#pragma message("------------------------------------------------------------------") + +#endif + +#define PtW32CatchAll \ + catch( ptw32_exception & ) { throw; } \ + catch( ... ) + +#else /* _MSC_VER */ + +#define catch( E ) \ + catch( ptw32_exception & ) { throw; } \ + catch( E ) + +#endif /* _MSC_VER */ + +#endif /* __CLEANUP_CXX */ + +#endif /* ! PTW32_BUILD */ + +#if defined(__cplusplus) +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#if defined(PTW32__HANDLE_DEF) +# undef HANDLE +#endif +#if defined(PTW32__DWORD_DEF) +# undef DWORD +#endif + +#undef PTW32_LEVEL +#undef PTW32_LEVEL_MAX + +#endif /* ! RC_INVOKED */ + +#endif /* PTHREAD_H */ diff --git a/libs/pthreads/src/pthread_attr_destroy.c b/libs/pthreads/src/pthread_attr_destroy.c new file mode 100644 index 0000000000..8b3e04c536 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_destroy.c @@ -0,0 +1,79 @@ +/* + * pthread_attr_destroy.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_destroy (pthread_attr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a thread attributes object. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * + * DESCRIPTION + * Destroys a thread attributes object. + * + * NOTES: + * 1) Does not affect threads created with 'attr'. + * + * RESULTS + * 0 successfully destroyed attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + /* + * Set the attribute object to a specific invalid value. + */ + (*attr)->valid = 0; + free (*attr); + *attr = NULL; + + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_getdetachstate.c b/libs/pthreads/src/pthread_attr_getdetachstate.c new file mode 100644 index 0000000000..188533b13c --- /dev/null +++ b/libs/pthreads/src/pthread_attr_getdetachstate.c @@ -0,0 +1,86 @@ +/* + * pthread_attr_getdetachstate.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_getdetachstate (const pthread_attr_t * attr, int *detachstate) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function determines whether threads created with + * 'attr' will run detached. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * detachstate + * pointer to an integer into which is returned one + * of: + * + * PTHREAD_CREATE_JOINABLE + * Thread ID is valid, must be joined + * + * PTHREAD_CREATE_DETACHED + * Thread ID is invalid, cannot be joined, + * canceled, or modified + * + * + * DESCRIPTION + * This function determines whether threads created with + * 'attr' will run detached. + * + * NOTES: + * 1) You cannot join or cancel detached threads. + * + * RESULTS + * 0 successfully retrieved detach state, + * EINVAL 'attr' is invalid + * + * ------------------------------------------------------ + */ +{ + if (ptw32_is_attr (attr) != 0 || detachstate == NULL) + { + return EINVAL; + } + + *detachstate = (*attr)->detachstate; + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_getinheritsched.c b/libs/pthreads/src/pthread_attr_getinheritsched.c new file mode 100644 index 0000000000..9c6885ed92 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_getinheritsched.c @@ -0,0 +1,51 @@ +/* + * pthread_attr_getinheritsched.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_getinheritsched (const pthread_attr_t * attr, int *inheritsched) +{ + if (ptw32_is_attr (attr) != 0 || inheritsched == NULL) + { + return EINVAL; + } + + *inheritsched = (*attr)->inheritsched; + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_getschedparam.c b/libs/pthreads/src/pthread_attr_getschedparam.c new file mode 100644 index 0000000000..ab89b2241a --- /dev/null +++ b/libs/pthreads/src/pthread_attr_getschedparam.c @@ -0,0 +1,52 @@ +/* + * pthread_attr_getschedparam.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_getschedparam (const pthread_attr_t * attr, + struct sched_param *param) +{ + if (ptw32_is_attr (attr) != 0 || param == NULL) + { + return EINVAL; + } + + memcpy (param, &(*attr)->param, sizeof (*param)); + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_getschedpolicy.c b/libs/pthreads/src/pthread_attr_getschedpolicy.c new file mode 100644 index 0000000000..94a257d609 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_getschedpolicy.c @@ -0,0 +1,61 @@ +/* + * pthread_attr_getschedpolicy.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_getschedpolicy (const pthread_attr_t * attr, int *policy) +{ + if (ptw32_is_attr (attr) != 0 || policy == NULL) + { + return EINVAL; + } + + /* + * Validate the policy arg. + * Check that a policy constant wasn't passed rather than &policy. + */ + if (policy <= (int *) SCHED_MAX) + { + return EINVAL; + } + + *policy = SCHED_OTHER; + + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_getscope.c b/libs/pthreads/src/pthread_attr_getscope.c new file mode 100644 index 0000000000..2efdb2fe6d --- /dev/null +++ b/libs/pthreads/src/pthread_attr_getscope.c @@ -0,0 +1,54 @@ +/* + * pthread_attr_getscope.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#if defined(_MSC_VER) +#pragma warning( disable : 4100 ) +#endif + +int +pthread_attr_getscope (const pthread_attr_t * attr, int *contentionscope) +{ +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + *contentionscope = (*attr)->contentionscope; + return 0; +#else + return ENOSYS; +#endif +} diff --git a/libs/pthreads/src/pthread_attr_getstackaddr.c b/libs/pthreads/src/pthread_attr_getstackaddr.c new file mode 100644 index 0000000000..1a2da01c78 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_getstackaddr.c @@ -0,0 +1,97 @@ +/* + * pthread_attr_getstackaddr.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#if defined(_MSC_VER) +#pragma warning( disable : 4100 ) +#endif + +int +pthread_attr_getstackaddr (const pthread_attr_t * attr, void **stackaddr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function determines the address of the stack + * on which threads created with 'attr' will run. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stackaddr + * pointer into which is returned the stack address. + * + * + * DESCRIPTION + * This function determines the address of the stack + * on which threads created with 'attr' will run. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKADDR + * + * 2) Create only one thread for each stack + * address.. + * + * RESULTS + * 0 successfully retreived stack address, + * EINVAL 'attr' is invalid + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ +{ +#if defined( _POSIX_THREAD_ATTR_STACKADDR ) + + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + *stackaddr = (*attr)->stackaddr; + return 0; + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKADDR */ +} diff --git a/libs/pthreads/src/pthread_attr_getstacksize.c b/libs/pthreads/src/pthread_attr_getstacksize.c new file mode 100644 index 0000000000..dff9230f28 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_getstacksize.c @@ -0,0 +1,100 @@ +/* + * pthread_attr_getstacksize.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#if defined(_MSC_VER) +#pragma warning( disable : 4100 ) +#endif + +int +pthread_attr_getstacksize (const pthread_attr_t * attr, size_t * stacksize) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function determines the size of the stack on + * which threads created with 'attr' will run. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stacksize + * pointer to size_t into which is returned the + * stack size, in bytes. + * + * + * DESCRIPTION + * This function determines the size of the stack on + * which threads created with 'attr' will run. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKSIZE + * + * 2) Use on newly created attributes object to + * find the default stack size. + * + * RESULTS + * 0 successfully retrieved stack size, + * EINVAL 'attr' is invalid + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ +{ +#if defined(_POSIX_THREAD_ATTR_STACKSIZE) + + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + /* Everything is okay. */ + *stacksize = (*attr)->stacksize; + return 0; + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKSIZE */ + +} diff --git a/libs/pthreads/src/pthread_attr_init.c b/libs/pthreads/src/pthread_attr_init.c new file mode 100644 index 0000000000..ae9d3eb5f4 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_init.c @@ -0,0 +1,117 @@ +/* + * pthread_attr_init.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_init (pthread_attr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a thread attributes object with default + * attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * + * DESCRIPTION + * Initializes a thread attributes object with default + * attributes. + * + * NOTES: + * 1) Used to define thread attributes + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + pthread_attr_t attr_result; + + if (attr == NULL) + { + /* This is disallowed. */ + return EINVAL; + } + + attr_result = (pthread_attr_t) malloc (sizeof (*attr_result)); + + if (attr_result == NULL) + { + return ENOMEM; + } + +#if defined(_POSIX_THREAD_ATTR_STACKSIZE) + /* + * Default to zero size. Unless changed explicitly this + * will allow Win32 to set the size to that of the + * main thread. + */ + attr_result->stacksize = 0; +#endif + +#if defined(_POSIX_THREAD_ATTR_STACKADDR) + /* FIXME: Set this to something sensible when we support it. */ + attr_result->stackaddr = NULL; +#endif + + attr_result->detachstate = PTHREAD_CREATE_JOINABLE; + +#if defined(HAVE_SIGSET_T) + memset (&(attr_result->sigmask), 0, sizeof (sigset_t)); +#endif /* HAVE_SIGSET_T */ + + /* + * Win32 sets new threads to THREAD_PRIORITY_NORMAL and + * not to that of the parent thread. We choose to default to + * this arrangement. + */ + attr_result->param.sched_priority = THREAD_PRIORITY_NORMAL; + attr_result->inheritsched = PTHREAD_EXPLICIT_SCHED; + attr_result->contentionscope = PTHREAD_SCOPE_SYSTEM; + + attr_result->valid = PTW32_ATTR_VALID; + + *attr = attr_result; + + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_setdetachstate.c b/libs/pthreads/src/pthread_attr_setdetachstate.c new file mode 100644 index 0000000000..784642a807 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_setdetachstate.c @@ -0,0 +1,91 @@ +/* + * pthread_attr_setdetachstate.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_setdetachstate (pthread_attr_t * attr, int detachstate) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function specifies whether threads created with + * 'attr' will run detached. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * detachstate + * an integer containing one of: + * + * PTHREAD_CREATE_JOINABLE + * Thread ID is valid, must be joined + * + * PTHREAD_CREATE_DETACHED + * Thread ID is invalid, cannot be joined, + * canceled, or modified + * + * + * DESCRIPTION + * This function specifies whether threads created with + * 'attr' will run detached. + * + * NOTES: + * 1) You cannot join or cancel detached threads. + * + * RESULTS + * 0 successfully set detach state, + * EINVAL 'attr' or 'detachstate' is invalid + * + * ------------------------------------------------------ + */ +{ + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + if (detachstate != PTHREAD_CREATE_JOINABLE && + detachstate != PTHREAD_CREATE_DETACHED) + { + return EINVAL; + } + + (*attr)->detachstate = detachstate; + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_setinheritsched.c b/libs/pthreads/src/pthread_attr_setinheritsched.c new file mode 100644 index 0000000000..e0a407a3b7 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_setinheritsched.c @@ -0,0 +1,57 @@ +/* + * pthread_attr_setinheritsched.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_setinheritsched (pthread_attr_t * attr, int inheritsched) +{ + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + if (PTHREAD_INHERIT_SCHED != inheritsched + && PTHREAD_EXPLICIT_SCHED != inheritsched) + { + return EINVAL; + } + + (*attr)->inheritsched = inheritsched; + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_setschedparam.c b/libs/pthreads/src/pthread_attr_setschedparam.c new file mode 100644 index 0000000000..f246bfae7a --- /dev/null +++ b/libs/pthreads/src/pthread_attr_setschedparam.c @@ -0,0 +1,63 @@ +/* + * pthread_attr_setschedparam.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_setschedparam (pthread_attr_t * attr, + const struct sched_param *param) +{ + int priority; + + if (ptw32_is_attr (attr) != 0 || param == NULL) + { + return EINVAL; + } + + priority = param->sched_priority; + + /* Validate priority level. */ + if (priority < sched_get_priority_min (SCHED_OTHER) || + priority > sched_get_priority_max (SCHED_OTHER)) + { + return EINVAL; + } + + memcpy (&(*attr)->param, param, sizeof (*param)); + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_setschedpolicy.c b/libs/pthreads/src/pthread_attr_setschedpolicy.c new file mode 100644 index 0000000000..45ff165973 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_setschedpolicy.c @@ -0,0 +1,55 @@ +/* + * pthread_attr_setschedpolicy.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_attr_setschedpolicy (pthread_attr_t * attr, int policy) +{ + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + if (policy != SCHED_OTHER) + { + return ENOTSUP; + } + + return 0; +} diff --git a/libs/pthreads/src/pthread_attr_setscope.c b/libs/pthreads/src/pthread_attr_setscope.c new file mode 100644 index 0000000000..39a51df887 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_setscope.c @@ -0,0 +1,62 @@ +/* + * pthread_attr_setscope.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#if defined(_MSC_VER) +#pragma warning( disable : 4100 ) +#endif + +int +pthread_attr_setscope (pthread_attr_t * attr, int contentionscope) +{ +#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) + switch (contentionscope) + { + case PTHREAD_SCOPE_SYSTEM: + (*attr)->contentionscope = contentionscope; + return 0; + case PTHREAD_SCOPE_PROCESS: + return ENOTSUP; + default: + return EINVAL; + } +#else + return ENOSYS; +#endif +} diff --git a/libs/pthreads/src/pthread_attr_setstackaddr.c b/libs/pthreads/src/pthread_attr_setstackaddr.c new file mode 100644 index 0000000000..1316c06592 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_setstackaddr.c @@ -0,0 +1,97 @@ +/* + * pthread_attr_setstackaddr.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_setstackaddr (pthread_attr_t * attr, void *stackaddr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Threads created with 'attr' will run on the stack + * starting at 'stackaddr'. + * Stack must be at least PTHREAD_STACK_MIN bytes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stackaddr + * the address of the stack to use + * + * + * DESCRIPTION + * Threads created with 'attr' will run on the stack + * starting at 'stackaddr'. + * Stack must be at least PTHREAD_STACK_MIN bytes. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKADDR + * + * 2) Create only one thread for each stack + * address.. + * + * 3) Ensure that stackaddr is aligned. + * + * RESULTS + * 0 successfully set stack address, + * EINVAL 'attr' is invalid + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ +{ +#if defined( _POSIX_THREAD_ATTR_STACKADDR ) + + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + (*attr)->stackaddr = stackaddr; + return 0; + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKADDR */ +} diff --git a/libs/pthreads/src/pthread_attr_setstacksize.c b/libs/pthreads/src/pthread_attr_setstacksize.c new file mode 100644 index 0000000000..eb13589a00 --- /dev/null +++ b/libs/pthreads/src/pthread_attr_setstacksize.c @@ -0,0 +1,110 @@ +/* + * pthread_attr_setstacksize.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_attr_setstacksize (pthread_attr_t * attr, size_t stacksize) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function specifies the size of the stack on + * which threads created with 'attr' will run. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_attr_t + * + * stacksize + * stack size, in bytes. + * + * + * DESCRIPTION + * This function specifies the size of the stack on + * which threads created with 'attr' will run. + * + * NOTES: + * 1) Function supported only if this macro is + * defined: + * + * _POSIX_THREAD_ATTR_STACKSIZE + * + * 2) Find the default first (using + * pthread_attr_getstacksize), then increase + * by multiplying. + * + * 3) Only use if thread needs more than the + * default. + * + * RESULTS + * 0 successfully set stack size, + * EINVAL 'attr' is invalid or stacksize too + * small or too big. + * ENOSYS function not supported + * + * ------------------------------------------------------ + */ +{ +#if defined(_POSIX_THREAD_ATTR_STACKSIZE) + +#if PTHREAD_STACK_MIN > 0 + + /* Verify that the stack size is within range. */ + if (stacksize < PTHREAD_STACK_MIN) + { + return EINVAL; + } + +#endif + + if (ptw32_is_attr (attr) != 0) + { + return EINVAL; + } + + /* Everything is okay. */ + (*attr)->stacksize = stacksize; + return 0; + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_ATTR_STACKSIZE */ + +} diff --git a/libs/pthreads/src/pthread_barrier_destroy.c b/libs/pthreads/src/pthread_barrier_destroy.c new file mode 100644 index 0000000000..55163cc858 --- /dev/null +++ b/libs/pthreads/src/pthread_barrier_destroy.c @@ -0,0 +1,103 @@ +/* + * pthread_barrier_destroy.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +pthread_barrier_destroy (pthread_barrier_t * barrier) +{ + int result = 0; + pthread_barrier_t b; + ptw32_mcs_local_node_t node; + + if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) + { + return EINVAL; + } + + if (0 != ptw32_mcs_lock_try_acquire(&(*barrier)->lock, &node)) + { + return EBUSY; + } + + b = *barrier; + + if (b->nCurrentBarrierHeight < b->nInitialBarrierHeight) + { + result = EBUSY; + } + else + { + if (0 == (result = sem_destroy (&(b->semBarrierBreeched)))) + { + *barrier = (pthread_barrier_t) PTW32_OBJECT_INVALID; + /* + * Release the lock before freeing b. + * + * FIXME: There may be successors which, when we release the lock, + * will be linked into b->lock, which will be corrupted at some + * point with undefined results for the application. To fix this + * will require changing pthread_barrier_t from a pointer to + * pthread_barrier_t_ to an instance. This is a change to the ABI + * and will require a major version number increment. + */ + ptw32_mcs_lock_release(&node); + (void) free (b); + return 0; + } + else + { + /* + * This should not ever be reached. + * Restore the barrier to working condition before returning. + */ + (void) sem_init (&(b->semBarrierBreeched), b->pshared, 0); + } + + if (result != 0) + { + /* + * The barrier still exists and is valid + * in the event of any error above. + */ + result = EBUSY; + } + } + + ptw32_mcs_lock_release(&node); + return (result); +} diff --git a/libs/pthreads/src/pthread_barrier_init.c b/libs/pthreads/src/pthread_barrier_init.c new file mode 100644 index 0000000000..618bfae264 --- /dev/null +++ b/libs/pthreads/src/pthread_barrier_init.c @@ -0,0 +1,69 @@ +/* + * pthread_barrier_init.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrier_init (pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, unsigned int count) +{ + pthread_barrier_t b; + + if (barrier == NULL || count == 0) + { + return EINVAL; + } + + if (NULL != (b = (pthread_barrier_t) calloc (1, sizeof (*b)))) + { + b->pshared = (attr != NULL && *attr != NULL + ? (*attr)->pshared : PTHREAD_PROCESS_PRIVATE); + + b->nCurrentBarrierHeight = b->nInitialBarrierHeight = count; + b->lock = 0; + + if (0 == sem_init (&(b->semBarrierBreeched), b->pshared, 0)) + { + *barrier = b; + return 0; + } + (void) free (b); + } + + return ENOMEM; +} diff --git a/libs/pthreads/src/pthread_barrier_wait.c b/libs/pthreads/src/pthread_barrier_wait.c new file mode 100644 index 0000000000..e0e97e6c78 --- /dev/null +++ b/libs/pthreads/src/pthread_barrier_wait.c @@ -0,0 +1,104 @@ +/* + * pthread_barrier_wait.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrier_wait (pthread_barrier_t * barrier) +{ + int result; + pthread_barrier_t b; + + ptw32_mcs_local_node_t node; + + if (barrier == NULL || *barrier == (pthread_barrier_t) PTW32_OBJECT_INVALID) + { + return EINVAL; + } + + ptw32_mcs_lock_acquire(&(*barrier)->lock, &node); + + b = *barrier; + if (--b->nCurrentBarrierHeight == 0) + { + /* + * We are the last thread to arrive at the barrier before it releases us. + * Move our MCS local node to the global scope barrier handle so that the + * last thread out (not necessarily us) can release the lock. + */ + ptw32_mcs_node_transfer(&b->proxynode, &node); + + /* + * Any threads that have not quite entered sem_wait below when the + * multiple_post has completed will nevertheless continue through + * the semaphore (barrier). + */ + result = (b->nInitialBarrierHeight > 1 + ? sem_post_multiple (&(b->semBarrierBreeched), + b->nInitialBarrierHeight - 1) : 0); + } + else + { + ptw32_mcs_lock_release(&node); + /* + * Use the non-cancelable version of sem_wait(). + * + * It is possible that all nInitialBarrierHeight-1 threads are + * at this point when the last thread enters the barrier, resets + * nCurrentBarrierHeight = nInitialBarrierHeight and leaves. + * If pthread_barrier_destroy is called at that moment then the + * barrier will be destroyed along with the semas. + */ + result = ptw32_semwait (&(b->semBarrierBreeched)); + } + + if ((PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_INCREMENT_LONG((PTW32_INTERLOCKED_LONGPTR)&b->nCurrentBarrierHeight) + == (PTW32_INTERLOCKED_LONG)b->nInitialBarrierHeight) + { + /* + * We are the last thread to cross this barrier + */ + ptw32_mcs_lock_release(&b->proxynode); + if (0 == result) + { + result = PTHREAD_BARRIER_SERIAL_THREAD; + } + } + + return (result); +} diff --git a/libs/pthreads/src/pthread_barrierattr_destroy.c b/libs/pthreads/src/pthread_barrierattr_destroy.c new file mode 100644 index 0000000000..5ab662e3f4 --- /dev/null +++ b/libs/pthreads/src/pthread_barrierattr_destroy.c @@ -0,0 +1,83 @@ +/* + * pthread_barrier_attr_destroy.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrierattr_destroy (pthread_barrierattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a barrier attributes object. The object can + * no longer be used. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_barrierattr_t + * + * + * DESCRIPTION + * Destroys a barrier attributes object. The object can + * no longer be used. + * + * NOTES: + * 1) Does not affect barrieres created using 'attr' + * + * RESULTS + * 0 successfully released attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (attr == NULL || *attr == NULL) + { + result = EINVAL; + } + else + { + pthread_barrierattr_t ba = *attr; + + *attr = NULL; + free (ba); + } + + return (result); +} /* pthread_barrierattr_destroy */ diff --git a/libs/pthreads/src/pthread_barrierattr_getpshared.c b/libs/pthreads/src/pthread_barrierattr_getpshared.c new file mode 100644 index 0000000000..44c467e2bf --- /dev/null +++ b/libs/pthreads/src/pthread_barrierattr_getpshared.c @@ -0,0 +1,95 @@ +/* + * pthread_barrier_attr_getpshared.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrierattr_getpshared (const pthread_barrierattr_t * attr, + int *pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Determine whether barriers created with 'attr' can be + * shared between processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_barrierattr_t + * + * pshared + * will be set to one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_barrier_t variable is allocated + * in memory shared by these processes. + * NOTES: + * 1) pshared barriers MUST be allocated in shared + * memory. + * 2) The following macro is defined if shared barriers + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully retrieved attribute, + * EINVAL 'attr' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && (pshared != NULL)) + { + *pshared = (*attr)->pshared; + result = 0; + } + else + { + result = EINVAL; + } + + return (result); +} /* pthread_barrierattr_getpshared */ diff --git a/libs/pthreads/src/pthread_barrierattr_init.c b/libs/pthreads/src/pthread_barrierattr_init.c new file mode 100644 index 0000000000..342f8b0c69 --- /dev/null +++ b/libs/pthreads/src/pthread_barrierattr_init.c @@ -0,0 +1,85 @@ +/* + * pthread_barrier_attr_init.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrierattr_init (pthread_barrierattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a barrier attributes object with default + * attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_barrierattr_t + * + * + * DESCRIPTION + * Initializes a barrier attributes object with default + * attributes. + * + * NOTES: + * 1) Used to define barrier types + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + pthread_barrierattr_t ba; + int result = 0; + + ba = (pthread_barrierattr_t) calloc (1, sizeof (*ba)); + + if (ba == NULL) + { + result = ENOMEM; + } + else + { + ba->pshared = PTHREAD_PROCESS_PRIVATE; + } + + *attr = ba; + + return (result); +} /* pthread_barrierattr_init */ diff --git a/libs/pthreads/src/pthread_barrierattr_setpshared.c b/libs/pthreads/src/pthread_barrierattr_setpshared.c new file mode 100644 index 0000000000..08c6fde30b --- /dev/null +++ b/libs/pthreads/src/pthread_barrierattr_setpshared.c @@ -0,0 +1,119 @@ +/* + * pthread_barrier_attr_setpshared.c + * + * Description: + * This translation unit implements barrier primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, int pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Barriers created with 'attr' can be shared between + * processes if pthread_barrier_t variable is allocated + * in memory shared by these processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_barrierattr_t + * + * pshared + * must be one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_barrier_t variable is allocated + * in memory shared by these processes. + * + * NOTES: + * 1) pshared barriers MUST be allocated in shared + * memory. + * + * 2) The following macro is defined if shared barriers + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && + ((pshared == PTHREAD_PROCESS_SHARED) || + (pshared == PTHREAD_PROCESS_PRIVATE))) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + +#if !defined( _POSIX_THREAD_PROCESS_SHARED ) + + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; + +#else + + result = 0; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + else + { + result = 0; + } + + (*attr)->pshared = pshared; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_barrierattr_setpshared */ diff --git a/libs/pthreads/src/pthread_cancel.c b/libs/pthreads/src/pthread_cancel.c new file mode 100644 index 0000000000..ae60b72936 --- /dev/null +++ b/libs/pthreads/src/pthread_cancel.c @@ -0,0 +1,189 @@ +/* + * pthread_cancel.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "context.h" + +static void +ptw32_cancel_self (void) +{ + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ +} + +static void CALLBACK +ptw32_cancel_callback (ULONG_PTR unused) +{ + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ +} + +/* + * ptw32_RegisterCancelation() - + * Must have args of same type as QueueUserAPCEx because this function + * is a substitute for QueueUserAPCEx if it's not available. + */ +DWORD +ptw32_RegisterCancelation (PAPCFUNC unused1, HANDLE threadH, DWORD unused2) +{ + CONTEXT context; + + context.ContextFlags = CONTEXT_CONTROL; + GetThreadContext (threadH, &context); + PTW32_PROGCTR (context) = (DWORD_PTR) ptw32_cancel_self; + SetThreadContext (threadH, &context); + return 0; +} + +int +pthread_cancel (pthread_t thread) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function requests cancellation of 'thread'. + * + * PARAMETERS + * thread + * reference to an instance of pthread_t + * + * + * DESCRIPTION + * This function requests cancellation of 'thread'. + * NOTE: cancellation is asynchronous; use pthread_join to + * wait for termination of 'thread' if necessary. + * + * RESULTS + * 0 successfully requested cancellation, + * ESRCH no thread found corresponding to 'thread', + * ENOMEM implicit self thread create failed. + * ------------------------------------------------------ + */ +{ + int result; + int cancel_self; + pthread_t self; + ptw32_thread_t * tp; + ptw32_mcs_local_node_t stateLock; + + result = pthread_kill (thread, 0); + + if (0 != result) + { + return result; + } + + if ((self = pthread_self ()).p == NULL) + { + return ENOMEM; + }; + + /* + * For self cancellation we need to ensure that a thread can't + * deadlock itself trying to cancel itself asynchronously + * (pthread_cancel is required to be an async-cancel + * safe function). + */ + cancel_self = pthread_equal (thread, self); + + tp = (ptw32_thread_t *) thread.p; + + /* + * Lock for async-cancel safety. + */ + ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock); + + if (tp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS + && tp->cancelState == PTHREAD_CANCEL_ENABLE + && tp->state < PThreadStateCanceling) + { + if (cancel_self) + { + tp->state = PThreadStateCanceling; + tp->cancelState = PTHREAD_CANCEL_DISABLE; + + ptw32_mcs_lock_release (&stateLock); + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ + } + else + { + HANDLE threadH = tp->threadH; + + SuspendThread (threadH); + + if (WaitForSingleObject (threadH, 0) == WAIT_TIMEOUT) + { + tp->state = PThreadStateCanceling; + tp->cancelState = PTHREAD_CANCEL_DISABLE; + /* + * If alertdrv and QueueUserAPCEx is available then the following + * will result in a call to QueueUserAPCEx with the args given, otherwise + * this will result in a call to ptw32_RegisterCancelation and only + * the threadH arg will be used. + */ + ptw32_register_cancelation ((PAPCFUNC)ptw32_cancel_callback, threadH, 0); + ptw32_mcs_lock_release (&stateLock); + ResumeThread (threadH); + } + } + } + else + { + /* + * Set for deferred cancellation. + */ + if (tp->state < PThreadStateCancelPending) + { + tp->state = PThreadStateCancelPending; + if (!SetEvent (tp->cancelEvent)) + { + result = ESRCH; + } + } + else if (tp->state >= PThreadStateCanceling) + { + result = ESRCH; + } + + ptw32_mcs_lock_release (&stateLock); + } + + return (result); +} diff --git a/libs/pthreads/src/pthread_cond_destroy.c b/libs/pthreads/src/pthread_cond_destroy.c new file mode 100644 index 0000000000..40d4a0896c --- /dev/null +++ b/libs/pthreads/src/pthread_cond_destroy.c @@ -0,0 +1,253 @@ +/* + * pthread_cond_destroy.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +pthread_cond_destroy (pthread_cond_t * cond) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function destroys a condition variable + * + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * + * DESCRIPTION + * This function destroys a condition variable. + * + * NOTES: + * 1) A condition variable can be destroyed + * immediately after all the threads that + * are blocked on it are awakened. e.g. + * + * struct list { + * pthread_mutex_t lm; + * ... + * } + * + * struct elt { + * key k; + * int busy; + * pthread_cond_t notbusy; + * ... + * } + * + * + * struct elt * + * list_find(struct list *lp, key k) + * { + * struct elt *ep; + * + * pthread_mutex_lock(&lp->lm); + * while ((ep = find_elt(l,k) != NULL) && ep->busy) + * pthread_cond_wait(&ep->notbusy, &lp->lm); + * if (ep != NULL) + * ep->busy = 1; + * pthread_mutex_unlock(&lp->lm); + * return(ep); + * } + * + * delete_elt(struct list *lp, struct elt *ep) + * { + * pthread_mutex_lock(&lp->lm); + * assert(ep->busy); + * ... remove ep from list ... + * ep->busy = 0; + * (A) pthread_cond_broadcast(&ep->notbusy); + * pthread_mutex_unlock(&lp->lm); + * (B) pthread_cond_destroy(&rp->notbusy); + * free(ep); + * } + * + * In this example, the condition variable + * and its list element may be freed (line B) + * immediately after all threads waiting for + * it are awakened (line A), since the mutex + * and the code ensure that no other thread + * can touch the element to be deleted. + * + * RESULTS + * 0 successfully released condition variable, + * EINVAL 'cond' is invalid, + * EBUSY 'cond' is in use, + * + * ------------------------------------------------------ + */ +{ + pthread_cond_t cv; + int result = 0, result1 = 0, result2 = 0; + + /* + * Assuming any race condition here is harmless. + */ + if (cond == NULL || *cond == NULL) + { + return EINVAL; + } + + if (*cond != PTHREAD_COND_INITIALIZER) + { + ptw32_mcs_local_node_t node; + ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node); + + cv = *cond; + + /* + * Close the gate; this will synchronize this thread with + * all already signaled waiters to let them retract their + * waiter status - SEE NOTE 1 ABOVE!!! + */ + if (ptw32_semwait (&(cv->semBlockLock)) != 0) /* Non-cancelable */ + { + result = errno; + } + else + { + /* + * !TRY! lock mtxUnblockLock; try will detect busy condition + * and will not cause a deadlock with respect to concurrent + * signal/broadcast. + */ + if ((result = pthread_mutex_trylock (&(cv->mtxUnblockLock))) != 0) + { + (void) sem_post (&(cv->semBlockLock)); + } + } + + if (result != 0) + { + ptw32_mcs_lock_release(&node); + return result; + } + + /* + * Check whether cv is still busy (still has waiters) + */ + if (cv->nWaitersBlocked > cv->nWaitersGone) + { + if (sem_post (&(cv->semBlockLock)) != 0) + { + result = errno; + } + result1 = pthread_mutex_unlock (&(cv->mtxUnblockLock)); + result2 = EBUSY; + } + else + { + /* + * Now it is safe to destroy + */ + *cond = NULL; + + if (sem_destroy (&(cv->semBlockLock)) != 0) + { + result = errno; + } + if (sem_destroy (&(cv->semBlockQueue)) != 0) + { + result1 = errno; + } + if ((result2 = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) + { + result2 = pthread_mutex_destroy (&(cv->mtxUnblockLock)); + } + + /* Unlink the CV from the list */ + + if (ptw32_cond_list_head == cv) + { + ptw32_cond_list_head = cv->next; + } + else + { + cv->prev->next = cv->next; + } + + if (ptw32_cond_list_tail == cv) + { + ptw32_cond_list_tail = cv->prev; + } + else + { + cv->next->prev = cv->prev; + } + + (void) free (cv); + } + + ptw32_mcs_lock_release(&node); + } + else + { + ptw32_mcs_local_node_t node; + /* + * See notes in ptw32_cond_check_need_init() above also. + */ + ptw32_mcs_lock_acquire(&ptw32_cond_test_init_lock, &node); + + /* + * Check again. + */ + if (*cond == PTHREAD_COND_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised cond that has not yet been used (initialised). + * If we get to here, another thread waiting to initialise + * this cond will get an EINVAL. That's OK. + */ + *cond = NULL; + } + else + { + /* + * The cv has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + + ptw32_mcs_lock_release(&node); + } + + return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); +} diff --git a/libs/pthreads/src/pthread_cond_init.c b/libs/pthreads/src/pthread_cond_init.c new file mode 100644 index 0000000000..f28fd67b43 --- /dev/null +++ b/libs/pthreads/src/pthread_cond_init.c @@ -0,0 +1,167 @@ +/* + * pthread_cond_init.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function initializes a condition variable. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * attr + * specifies optional creation attributes. + * + * + * DESCRIPTION + * This function initializes a condition variable. + * + * RESULTS + * 0 successfully created condition variable, + * EINVAL 'attr' is invalid, + * EAGAIN insufficient resources (other than + * memory, + * ENOMEM insufficient memory, + * EBUSY 'cond' is already initialized, + * + * ------------------------------------------------------ + */ +{ + int result; + pthread_cond_t cv = NULL; + + if (cond == NULL) + { + return EINVAL; + } + + if ((attr != NULL && *attr != NULL) && + ((*attr)->pshared == PTHREAD_PROCESS_SHARED)) + { + /* + * Creating condition variable that can be shared between + * processes. + */ + result = ENOSYS; + goto DONE; + } + + cv = (pthread_cond_t) calloc (1, sizeof (*cv)); + + if (cv == NULL) + { + result = ENOMEM; + goto DONE; + } + + cv->nWaitersBlocked = 0; + cv->nWaitersToUnblock = 0; + cv->nWaitersGone = 0; + + if (sem_init (&(cv->semBlockLock), 0, 1) != 0) + { + result = errno; + goto FAIL0; + } + + if (sem_init (&(cv->semBlockQueue), 0, 0) != 0) + { + result = errno; + goto FAIL1; + } + + if ((result = pthread_mutex_init (&(cv->mtxUnblockLock), 0)) != 0) + { + goto FAIL2; + } + + result = 0; + + goto DONE; + + /* + * ------------- + * Failed... + * ------------- + */ +FAIL2: + (void) sem_destroy (&(cv->semBlockQueue)); + +FAIL1: + (void) sem_destroy (&(cv->semBlockLock)); + +FAIL0: + (void) free (cv); + cv = NULL; + +DONE: + if (0 == result) + { + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node); + + cv->next = NULL; + cv->prev = ptw32_cond_list_tail; + + if (ptw32_cond_list_tail != NULL) + { + ptw32_cond_list_tail->next = cv; + } + + ptw32_cond_list_tail = cv; + + if (ptw32_cond_list_head == NULL) + { + ptw32_cond_list_head = cv; + } + + ptw32_mcs_lock_release(&node); + } + + *cond = cv; + + return result; + +} /* pthread_cond_init */ diff --git a/libs/pthreads/src/pthread_cond_signal.c b/libs/pthreads/src/pthread_cond_signal.c new file mode 100644 index 0000000000..2b4f6d4d44 --- /dev/null +++ b/libs/pthreads/src/pthread_cond_signal.c @@ -0,0 +1,231 @@ +/* + * pthread_cond_signal.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * ------------------------------------------------------------- + * Algorithm: + * See the comments at the top of pthread_cond_wait.c. + */ + +#include "pthread.h" +#include "implement.h" + +static INLINE int +ptw32_cond_unblock (pthread_cond_t * cond, int unblockAll) + /* + * Notes. + * + * Does not use the external mutex for synchronisation, + * therefore semBlockLock is needed. + * mtxUnblockLock is for LEVEL-2 synch. LEVEL-2 is the + * state where the external mutex is not necessarily locked by + * any thread, ie. between cond_wait unlocking and re-acquiring + * the lock after having been signaled or a timeout or + * cancellation. + * + * Uses the following CV elements: + * nWaitersBlocked + * nWaitersToUnblock + * nWaitersGone + * mtxUnblockLock + * semBlockLock + * semBlockQueue + */ +{ + int result; + pthread_cond_t cv; + int nSignalsToIssue; + + if (cond == NULL || *cond == NULL) + { + return EINVAL; + } + + cv = *cond; + + /* + * No-op if the CV is static and hasn't been initialised yet. + * Assuming that any race condition is harmless. + */ + if (cv == PTHREAD_COND_INITIALIZER) + { + return 0; + } + + if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0) + { + return result; + } + + if (0 != cv->nWaitersToUnblock) + { + if (0 == cv->nWaitersBlocked) + { + return pthread_mutex_unlock (&(cv->mtxUnblockLock)); + } + if (unblockAll) + { + cv->nWaitersToUnblock += (nSignalsToIssue = cv->nWaitersBlocked); + cv->nWaitersBlocked = 0; + } + else + { + nSignalsToIssue = 1; + cv->nWaitersToUnblock++; + cv->nWaitersBlocked--; + } + } + else if (cv->nWaitersBlocked > cv->nWaitersGone) + { + /* Use the non-cancellable version of sem_wait() */ + if (ptw32_semwait (&(cv->semBlockLock)) != 0) + { + result = errno; + (void) pthread_mutex_unlock (&(cv->mtxUnblockLock)); + return result; + } + if (0 != cv->nWaitersGone) + { + cv->nWaitersBlocked -= cv->nWaitersGone; + cv->nWaitersGone = 0; + } + if (unblockAll) + { + nSignalsToIssue = cv->nWaitersToUnblock = cv->nWaitersBlocked; + cv->nWaitersBlocked = 0; + } + else + { + nSignalsToIssue = cv->nWaitersToUnblock = 1; + cv->nWaitersBlocked--; + } + } + else + { + return pthread_mutex_unlock (&(cv->mtxUnblockLock)); + } + + if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) == 0) + { + if (sem_post_multiple (&(cv->semBlockQueue), nSignalsToIssue) != 0) + { + result = errno; + } + } + + return result; + +} /* ptw32_cond_unblock */ + +int +pthread_cond_signal (pthread_cond_t * cond) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function signals a condition variable, waking + * one waiting thread. + * If SCHED_FIFO or SCHED_RR policy threads are waiting + * the highest priority waiter is awakened; otherwise, + * an unspecified waiter is awakened. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * + * DESCRIPTION + * This function signals a condition variable, waking + * one waiting thread. + * If SCHED_FIFO or SCHED_RR policy threads are waiting + * the highest priority waiter is awakened; otherwise, + * an unspecified waiter is awakened. + * + * NOTES: + * + * 1) Use when any waiter can respond and only one need + * respond (all waiters being equal). + * + * RESULTS + * 0 successfully signaled condition, + * EINVAL 'cond' is invalid, + * + * ------------------------------------------------------ + */ +{ + /* + * The '0'(FALSE) unblockAll arg means unblock ONE waiter. + */ + return (ptw32_cond_unblock (cond, 0)); + +} /* pthread_cond_signal */ + +int +pthread_cond_broadcast (pthread_cond_t * cond) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function broadcasts the condition variable, + * waking all current waiters. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * + * DESCRIPTION + * This function signals a condition variable, waking + * all waiting threads. + * + * NOTES: + * + * 1) Use when more than one waiter may respond to + * predicate change or if any waiting thread may + * not be able to respond + * + * RESULTS + * 0 successfully signalled condition to all + * waiting threads, + * EINVAL 'cond' is invalid + * ENOSPC a required resource has been exhausted, + * + * ------------------------------------------------------ + */ +{ + /* + * The TRUE unblockAll arg means unblock ALL waiters. + */ + return (ptw32_cond_unblock (cond, PTW32_TRUE)); + +} /* pthread_cond_broadcast */ diff --git a/libs/pthreads/src/pthread_cond_wait.c b/libs/pthreads/src/pthread_cond_wait.c new file mode 100644 index 0000000000..359219ae9b --- /dev/null +++ b/libs/pthreads/src/pthread_cond_wait.c @@ -0,0 +1,567 @@ +/* + * pthread_cond_wait.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * ------------------------------------------------------------- + * Algorithm: + * The algorithm used in this implementation is that developed by + * Alexander Terekhov in colaboration with Louis Thomas. The bulk + * of the discussion is recorded in the file README.CV, which contains + * several generations of both colaborators original algorithms. The final + * algorithm used here is the one referred to as + * + * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL + * + * presented below in pseudo-code as it appeared: + * + * + * given: + * semBlockLock - bin.semaphore + * semBlockQueue - semaphore + * mtxExternal - mutex or CS + * mtxUnblockLock - mutex or CS + * nWaitersGone - int + * nWaitersBlocked - int + * nWaitersToUnblock - int + * + * wait( timeout ) { + * + * [auto: register int result ] // error checking omitted + * [auto: register int nSignalsWasLeft ] + * [auto: register int nWaitersWasGone ] + * + * sem_wait( semBlockLock ); + * nWaitersBlocked++; + * sem_post( semBlockLock ); + * + * unlock( mtxExternal ); + * bTimedOut = sem_wait( semBlockQueue,timeout ); + * + * lock( mtxUnblockLock ); + * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { + * if ( bTimeout ) { // timeout (or canceled) + * if ( 0 != nWaitersBlocked ) { + * nWaitersBlocked--; + * } + * else { + * nWaitersGone++; // count spurious wakeups. + * } + * } + * if ( 0 == --nWaitersToUnblock ) { + * if ( 0 != nWaitersBlocked ) { + * sem_post( semBlockLock ); // open the gate. + * nSignalsWasLeft = 0; // do not open the gate + * // below again. + * } + * else if ( 0 != (nWaitersWasGone = nWaitersGone) ) { + * nWaitersGone = 0; + * } + * } + * } + * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or + * // spurious semaphore :-) + * sem_wait( semBlockLock ); + * nWaitersBlocked -= nWaitersGone; // something is going on here + * // - test of timeouts? :-) + * sem_post( semBlockLock ); + * nWaitersGone = 0; + * } + * unlock( mtxUnblockLock ); + * + * if ( 1 == nSignalsWasLeft ) { + * if ( 0 != nWaitersWasGone ) { + * // sem_adjust( semBlockQueue,-nWaitersWasGone ); + * while ( nWaitersWasGone-- ) { + * sem_wait( semBlockQueue ); // better now than spurious later + * } + * } sem_post( semBlockLock ); // open the gate + * } + * + * lock( mtxExternal ); + * + * return ( bTimedOut ) ? ETIMEOUT : 0; + * } + * + * signal(bAll) { + * + * [auto: register int result ] + * [auto: register int nSignalsToIssue] + * + * lock( mtxUnblockLock ); + * + * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! + * if ( 0 == nWaitersBlocked ) { // NO-OP + * return unlock( mtxUnblockLock ); + * } + * if (bAll) { + * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; + * nWaitersBlocked = 0; + * } + * else { + * nSignalsToIssue = 1; + * nWaitersToUnblock++; + * nWaitersBlocked--; + * } + * } + * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! + * sem_wait( semBlockLock ); // close the gate + * if ( 0 != nWaitersGone ) { + * nWaitersBlocked -= nWaitersGone; + * nWaitersGone = 0; + * } + * if (bAll) { + * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; + * nWaitersBlocked = 0; + * } + * else { + * nSignalsToIssue = nWaitersToUnblock = 1; + * nWaitersBlocked--; + * } + * } + * else { // NO-OP + * return unlock( mtxUnblockLock ); + * } + * + * unlock( mtxUnblockLock ); + * sem_post( semBlockQueue,nSignalsToIssue ); + * return result; + * } + * ------------------------------------------------------------- + * + * Algorithm 9 / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL + * + * presented below in pseudo-code; basically 8a... + * ...BUT W/O "spurious wakes" prevention: + * + * + * given: + * semBlockLock - bin.semaphore + * semBlockQueue - semaphore + * mtxExternal - mutex or CS + * mtxUnblockLock - mutex or CS + * nWaitersGone - int + * nWaitersBlocked - int + * nWaitersToUnblock - int + * + * wait( timeout ) { + * + * [auto: register int result ] // error checking omitted + * [auto: register int nSignalsWasLeft ] + * + * sem_wait( semBlockLock ); + * ++nWaitersBlocked; + * sem_post( semBlockLock ); + * + * unlock( mtxExternal ); + * bTimedOut = sem_wait( semBlockQueue,timeout ); + * + * lock( mtxUnblockLock ); + * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) { + * --nWaitersToUnblock; + * } + * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or + * // spurious semaphore :-) + * sem_wait( semBlockLock ); + * nWaitersBlocked -= nWaitersGone; // something is going on here + * // - test of timeouts? :-) + * sem_post( semBlockLock ); + * nWaitersGone = 0; + * } + * unlock( mtxUnblockLock ); + * + * if ( 1 == nSignalsWasLeft ) { + * sem_post( semBlockLock ); // open the gate + * } + * + * lock( mtxExternal ); + * + * return ( bTimedOut ) ? ETIMEOUT : 0; + * } + * + * signal(bAll) { + * + * [auto: register int result ] + * [auto: register int nSignalsToIssue] + * + * lock( mtxUnblockLock ); + * + * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!! + * if ( 0 == nWaitersBlocked ) { // NO-OP + * return unlock( mtxUnblockLock ); + * } + * if (bAll) { + * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked; + * nWaitersBlocked = 0; + * } + * else { + * nSignalsToIssue = 1; + * ++nWaitersToUnblock; + * --nWaitersBlocked; + * } + * } + * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION! + * sem_wait( semBlockLock ); // close the gate + * if ( 0 != nWaitersGone ) { + * nWaitersBlocked -= nWaitersGone; + * nWaitersGone = 0; + * } + * if (bAll) { + * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked; + * nWaitersBlocked = 0; + * } + * else { + * nSignalsToIssue = nWaitersToUnblock = 1; + * --nWaitersBlocked; + * } + * } + * else { // NO-OP + * return unlock( mtxUnblockLock ); + * } + * + * unlock( mtxUnblockLock ); + * sem_post( semBlockQueue,nSignalsToIssue ); + * return result; + * } + * ------------------------------------------------------------- + * + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Arguments for cond_wait_cleanup, since we can only pass a + * single void * to it. + */ +typedef struct +{ + pthread_mutex_t *mutexPtr; + pthread_cond_t cv; + int *resultPtr; +} ptw32_cond_wait_cleanup_args_t; + +static void PTW32_CDECL +ptw32_cond_wait_cleanup (void *args) +{ + ptw32_cond_wait_cleanup_args_t *cleanup_args = + (ptw32_cond_wait_cleanup_args_t *) args; + pthread_cond_t cv = cleanup_args->cv; + int *resultPtr = cleanup_args->resultPtr; + int nSignalsWasLeft; + int result; + + /* + * Whether we got here as a result of signal/broadcast or because of + * timeout on wait or thread cancellation we indicate that we are no + * longer waiting. The waiter is responsible for adjusting waiters + * (to)unblock(ed) counts (protected by unblock lock). + */ + if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0) + { + *resultPtr = result; + return; + } + + if (0 != (nSignalsWasLeft = cv->nWaitersToUnblock)) + { + --(cv->nWaitersToUnblock); + } + else if (INT_MAX / 2 == ++(cv->nWaitersGone)) + { + /* Use the non-cancellable version of sem_wait() */ + if (ptw32_semwait (&(cv->semBlockLock)) != 0) + { + *resultPtr = errno; + /* + * This is a fatal error for this CV, + * so we deliberately don't unlock + * cv->mtxUnblockLock before returning. + */ + return; + } + cv->nWaitersBlocked -= cv->nWaitersGone; + if (sem_post (&(cv->semBlockLock)) != 0) + { + *resultPtr = errno; + /* + * This is a fatal error for this CV, + * so we deliberately don't unlock + * cv->mtxUnblockLock before returning. + */ + return; + } + cv->nWaitersGone = 0; + } + + if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) != 0) + { + *resultPtr = result; + return; + } + + if (1 == nSignalsWasLeft) + { + if (sem_post (&(cv->semBlockLock)) != 0) + { + *resultPtr = errno; + return; + } + } + + /* + * XSH: Upon successful return, the mutex has been locked and is owned + * by the calling thread. + */ + if ((result = pthread_mutex_lock (cleanup_args->mutexPtr)) != 0) + { + *resultPtr = result; + } +} /* ptw32_cond_wait_cleanup */ + +static INLINE int +ptw32_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, const struct timespec *abstime) +{ + int result = 0; + pthread_cond_t cv; + ptw32_cond_wait_cleanup_args_t cleanup_args; + + if (cond == NULL || *cond == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static condition variable. We check + * again inside the guarded section of ptw32_cond_check_need_init() + * to avoid race conditions. + */ + if (*cond == PTHREAD_COND_INITIALIZER) + { + result = ptw32_cond_check_need_init (cond); + } + + if (result != 0 && result != EBUSY) + { + return result; + } + + cv = *cond; + + /* Thread can be cancelled in sem_wait() but this is OK */ + if (sem_wait (&(cv->semBlockLock)) != 0) + { + return errno; + } + + ++(cv->nWaitersBlocked); + + if (sem_post (&(cv->semBlockLock)) != 0) + { + return errno; + } + + /* + * Setup this waiter cleanup handler + */ + cleanup_args.mutexPtr = mutex; + cleanup_args.cv = cv; + cleanup_args.resultPtr = &result; + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth(0) +#endif + pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args); + + /* + * Now we can release 'mutex' and... + */ + if ((result = pthread_mutex_unlock (mutex)) == 0) + { + + /* + * ...wait to be awakened by + * pthread_cond_signal, or + * pthread_cond_broadcast, or + * timeout, or + * thread cancellation + * + * Note: + * + * sem_timedwait is a cancellation point, + * hence providing the mechanism for making + * pthread_cond_wait a cancellation point. + * We use the cleanup mechanism to ensure we + * re-lock the mutex and adjust (to)unblock(ed) waiters + * counts if we are cancelled, timed out or signalled. + */ + if (sem_timedwait (&(cv->semBlockQueue), abstime) != 0) + { + result = errno; + } + } + + /* + * Always cleanup + */ + pthread_cleanup_pop (1); +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth() +#endif + + /* + * "result" can be modified by the cleanup handler. + */ + return result; + +} /* ptw32_cond_timedwait */ + + +int +pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a condition variable until + * awakened by a signal or broadcast. + * + * Caller MUST be holding the mutex lock; the + * lock is released and the caller is blocked waiting + * on 'cond'. When 'cond' is signaled, the mutex + * is re-acquired before returning to the caller. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * mutex + * pointer to an instance of pthread_mutex_t + * + * + * DESCRIPTION + * This function waits on a condition variable until + * awakened by a signal or broadcast. + * + * NOTES: + * + * 1) The function must be called with 'mutex' LOCKED + * by the calling thread, or undefined behaviour + * will result. + * + * 2) This routine atomically releases 'mutex' and causes + * the calling thread to block on the condition variable. + * The blocked thread may be awakened by + * pthread_cond_signal or + * pthread_cond_broadcast. + * + * Upon successful completion, the 'mutex' has been locked and + * is owned by the calling thread. + * + * + * RESULTS + * 0 caught condition; mutex released, + * EINVAL 'cond' or 'mutex' is invalid, + * EINVAL different mutexes for concurrent waits, + * EINVAL mutex is not held by the calling thread, + * + * ------------------------------------------------------ + */ +{ + /* + * The NULL abstime arg means INFINITE waiting. + */ + return (ptw32_cond_timedwait (cond, mutex, NULL)); + +} /* pthread_cond_wait */ + + +int +pthread_cond_timedwait (pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec *abstime) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a condition variable either until + * awakened by a signal or broadcast; or until the time + * specified by abstime passes. + * + * PARAMETERS + * cond + * pointer to an instance of pthread_cond_t + * + * mutex + * pointer to an instance of pthread_mutex_t + * + * abstime + * pointer to an instance of (const struct timespec) + * + * + * DESCRIPTION + * This function waits on a condition variable either until + * awakened by a signal or broadcast; or until the time + * specified by abstime passes. + * + * NOTES: + * 1) The function must be called with 'mutex' LOCKED + * by the calling thread, or undefined behaviour + * will result. + * + * 2) This routine atomically releases 'mutex' and causes + * the calling thread to block on the condition variable. + * The blocked thread may be awakened by + * pthread_cond_signal or + * pthread_cond_broadcast. + * + * + * RESULTS + * 0 caught condition; mutex released, + * EINVAL 'cond', 'mutex', or abstime is invalid, + * EINVAL different mutexes for concurrent waits, + * EINVAL mutex is not held by the calling thread, + * ETIMEDOUT abstime ellapsed before cond was signaled. + * + * ------------------------------------------------------ + */ +{ + if (abstime == NULL) + { + return EINVAL; + } + + return (ptw32_cond_timedwait (cond, mutex, abstime)); + +} /* pthread_cond_timedwait */ diff --git a/libs/pthreads/src/pthread_condattr_destroy.c b/libs/pthreads/src/pthread_condattr_destroy.c new file mode 100644 index 0000000000..58a14828fd --- /dev/null +++ b/libs/pthreads/src/pthread_condattr_destroy.c @@ -0,0 +1,86 @@ +/* + * condvar_attr_destroy.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_condattr_destroy (pthread_condattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a condition variable attributes object. + * The object can no longer be used. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_condattr_t + * + * + * DESCRIPTION + * Destroys a condition variable attributes object. + * The object can no longer be used. + * + * NOTES: + * 1) Does not affect condition variables created + * using 'attr' + * + * RESULTS + * 0 successfully released attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (attr == NULL || *attr == NULL) + { + result = EINVAL; + } + else + { + (void) free (*attr); + + *attr = NULL; + result = 0; + } + + return result; + +} /* pthread_condattr_destroy */ diff --git a/libs/pthreads/src/pthread_condattr_getpshared.c b/libs/pthreads/src/pthread_condattr_getpshared.c new file mode 100644 index 0000000000..a0ac6d8829 --- /dev/null +++ b/libs/pthreads/src/pthread_condattr_getpshared.c @@ -0,0 +1,97 @@ +/* + * pthread_condattr_getpshared.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_condattr_getpshared (const pthread_condattr_t * attr, int *pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Determine whether condition variables created with 'attr' + * can be shared between processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_condattr_t + * + * pshared + * will be set to one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * + * DESCRIPTION + * Condition Variables created with 'attr' can be shared + * between processes if pthread_cond_t variable is allocated + * in memory shared by these processes. + * NOTES: + * 1) pshared condition variables MUST be allocated in + * shared memory. + * + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully retrieved attribute, + * EINVAL 'attr' or 'pshared' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && (pshared != NULL)) + { + *pshared = (*attr)->pshared; + result = 0; + } + else + { + result = EINVAL; + } + + return result; + +} /* pthread_condattr_getpshared */ diff --git a/libs/pthreads/src/pthread_condattr_init.c b/libs/pthreads/src/pthread_condattr_init.c new file mode 100644 index 0000000000..5987878e0c --- /dev/null +++ b/libs/pthreads/src/pthread_condattr_init.c @@ -0,0 +1,87 @@ +/* + * pthread_condattr_init.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_condattr_init (pthread_condattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a condition variable attributes object + * with default attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_condattr_t + * + * + * DESCRIPTION + * Initializes a condition variable attributes object + * with default attributes. + * + * NOTES: + * 1) Use to define condition variable types + * 2) It is up to the application to ensure + * that it doesn't re-init an attribute + * without destroying it first. Otherwise + * a memory leak is created. + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + pthread_condattr_t attr_result; + int result = 0; + + attr_result = (pthread_condattr_t) calloc (1, sizeof (*attr_result)); + + if (attr_result == NULL) + { + result = ENOMEM; + } + + *attr = attr_result; + + return result; + +} /* pthread_condattr_init */ diff --git a/libs/pthreads/src/pthread_condattr_setpshared.c b/libs/pthreads/src/pthread_condattr_setpshared.c new file mode 100644 index 0000000000..954fb38299 --- /dev/null +++ b/libs/pthreads/src/pthread_condattr_setpshared.c @@ -0,0 +1,117 @@ +/* + * pthread_condattr_setpshared.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_condattr_setpshared (pthread_condattr_t * attr, int pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Mutexes created with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * pshared + * must be one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * + * NOTES: + * 1) pshared mutexes MUST be allocated in shared + * memory. + * + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) + && ((pshared == PTHREAD_PROCESS_SHARED) + || (pshared == PTHREAD_PROCESS_PRIVATE))) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + +#if !defined( _POSIX_THREAD_PROCESS_SHARED ) + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; +#else + result = 0; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + else + { + result = 0; + } + + (*attr)->pshared = pshared; + } + else + { + result = EINVAL; + } + + return result; + +} /* pthread_condattr_setpshared */ diff --git a/libs/pthreads/src/pthread_delay_np.c b/libs/pthreads/src/pthread_delay_np.c new file mode 100644 index 0000000000..e6c96d8070 --- /dev/null +++ b/libs/pthreads/src/pthread_delay_np.c @@ -0,0 +1,172 @@ +/* + * pthreads_delay_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * pthread_delay_np + * + * DESCRIPTION + * + * This routine causes a thread to delay execution for a specific period of time. + * This period ends at the current time plus the specified interval. The routine + * will not return before the end of the period is reached, but may return an + * arbitrary amount of time after the period has gone by. This can be due to + * system load, thread priorities, and system timer granularity. + * + * Specifying an interval of zero (0) seconds and zero (0) nanoseconds is + * allowed and can be used to force the thread to give up the processor or to + * deliver a pending cancelation request. + * + * The timespec structure contains the following two fields: + * + * tv_sec is an integer number of seconds. + * tv_nsec is an integer number of nanoseconds. + * + * Return Values + * + * If an error condition occurs, this routine returns an integer value indicating + * the type of error. Possible return values are as follows: + * + * 0 + * Successful completion. + * [EINVAL] + * The value specified by interval is invalid. + * + * Example + * + * The following code segment would wait for 5 and 1/2 seconds + * + * struct timespec tsWait; + * int intRC; + * + * tsWait.tv_sec = 5; + * tsWait.tv_nsec = 500000000L; + * intRC = pthread_delay_np(&tsWait); + */ +int +pthread_delay_np (struct timespec *interval) +{ + DWORD wait_time; + DWORD secs_in_millisecs; + DWORD millisecs; + DWORD status; + pthread_t self; + ptw32_thread_t * sp; + + if (interval == NULL) + { + return EINVAL; + } + + if (interval->tv_sec == 0L && interval->tv_nsec == 0L) + { + pthread_testcancel (); + Sleep (0); + pthread_testcancel (); + return (0); + } + + /* convert secs to millisecs */ + secs_in_millisecs = (DWORD)interval->tv_sec * 1000L; + + /* convert nanosecs to millisecs (rounding up) */ + millisecs = (interval->tv_nsec + 999999L) / 1000000L; + +#if defined(__WATCOMC__) +#pragma disable_message (124) +#endif + + /* + * Most compilers will issue a warning 'comparison always 0' + * because the variable type is unsigned, but we need to keep this + * for some reason I can't recall now. + */ + if (0 > (wait_time = secs_in_millisecs + millisecs)) + { + return EINVAL; + } + +#if defined(__WATCOMC__) +#pragma enable_message (124) +#endif + + if (NULL == (self = pthread_self ()).p) + { + return ENOMEM; + } + + sp = (ptw32_thread_t *) self.p; + + if (sp->cancelState == PTHREAD_CANCEL_ENABLE) + { + /* + * Async cancelation won't catch us until wait_time is up. + * Deferred cancelation will cancel us immediately. + */ + if (WAIT_OBJECT_0 == + (status = WaitForSingleObject (sp->cancelEvent, wait_time))) + { + ptw32_mcs_local_node_t stateLock; + /* + * Canceling! + */ + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); + if (sp->state < PThreadStateCanceling) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + ptw32_mcs_lock_release (&stateLock); + + ptw32_throw (PTW32_EPS_CANCEL); + } + + ptw32_mcs_lock_release (&stateLock); + return ESRCH; + } + else if (status != WAIT_TIMEOUT) + { + return EINVAL; + } + } + else + { + Sleep (wait_time); + } + + return (0); +} diff --git a/libs/pthreads/src/pthread_detach.c b/libs/pthreads/src/pthread_detach.c new file mode 100644 index 0000000000..9ff6587f3c --- /dev/null +++ b/libs/pthreads/src/pthread_detach.c @@ -0,0 +1,136 @@ +/* + * pthread_detach.c + * + * Description: + * This translation unit implements functions related to thread + * synchronisation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Not needed yet, but defining it should indicate clashes with build target + * environment that should be fixed. + */ +#if !defined(WINCE) +# include +#endif + + +int +pthread_detach (pthread_t thread) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function detaches the given thread. + * + * PARAMETERS + * thread + * an instance of a pthread_t + * + * + * DESCRIPTION + * This function detaches the given thread. You may use it to + * detach the main thread or to detach a joinable thread. + * NOTE: detached threads cannot be joined; + * storage is freed immediately on termination. + * + * RESULTS + * 0 successfully detached the thread, + * EINVAL thread is not a joinable thread, + * ENOSPC a required resource has been exhausted, + * ESRCH no thread could be found for 'thread', + * + * ------------------------------------------------------ + */ +{ + int result; + BOOL destroyIt = PTW32_FALSE; + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node); + + if (NULL == tp + || thread.x != tp->ptHandle.x) + { + result = ESRCH; + } + else if (PTHREAD_CREATE_DETACHED == tp->detachState) + { + result = EINVAL; + } + else + { + ptw32_mcs_local_node_t stateLock; + /* + * Joinable ptw32_thread_t structs are not scavenged until + * a join or detach is done. The thread may have exited already, + * but all of the state and locks etc are still there. + */ + result = 0; + + ptw32_mcs_lock_acquire (&tp->stateLock, &stateLock); + if (tp->state != PThreadStateLast) + { + tp->detachState = PTHREAD_CREATE_DETACHED; + } + else if (tp->detachState != PTHREAD_CREATE_DETACHED) + { + /* + * Thread is joinable and has exited or is exiting. + */ + destroyIt = PTW32_TRUE; + } + ptw32_mcs_lock_release (&stateLock); + } + + ptw32_mcs_lock_release(&node); + + if (result == 0) + { + /* Thread is joinable */ + + if (destroyIt) + { + /* The thread has exited or is exiting but has not been joined or + * detached. Need to wait in case it's still exiting. + */ + (void) WaitForSingleObject(tp->threadH, INFINITE); + ptw32_threadDestroy (thread); + } + } + + return (result); + +} /* pthread_detach */ diff --git a/libs/pthreads/src/pthread_equal.c b/libs/pthreads/src/pthread_equal.c new file mode 100644 index 0000000000..5ddd82acba --- /dev/null +++ b/libs/pthreads/src/pthread_equal.c @@ -0,0 +1,76 @@ +/* + * pthread_equal.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_equal (pthread_t t1, pthread_t t2) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function returns nonzero if t1 and t2 are equal, else + * returns zero + * + * PARAMETERS + * t1, + * t2 + * thread IDs + * + * + * DESCRIPTION + * This function returns nonzero if t1 and t2 are equal, else + * returns zero. + * + * RESULTS + * non-zero if t1 and t2 refer to the same thread, + * 0 t1 and t2 do not refer to the same thread + * + * ------------------------------------------------------ + */ +{ + int result; + + /* + * We also accept NULL == NULL - treating NULL as a thread + * for this special case, because there is no error that we can return. + */ + result = ( t1.p == t2.p && t1.x == t2.x ); + + return (result); + +} /* pthread_equal */ diff --git a/libs/pthreads/src/pthread_exit.c b/libs/pthreads/src/pthread_exit.c new file mode 100644 index 0000000000..37b3c09902 --- /dev/null +++ b/libs/pthreads/src/pthread_exit.c @@ -0,0 +1,106 @@ +/* + * pthread_exit.c + * + * Description: + * This translation unit implements routines associated with exiting from + * a thread. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#if !defined(_UWIN) +/*# include */ +#endif + +void +pthread_exit (void *value_ptr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function terminates the calling thread, returning + * the value 'value_ptr' to any joining thread. + * + * PARAMETERS + * value_ptr + * a generic data value (i.e. not the address of a value) + * + * + * DESCRIPTION + * This function terminates the calling thread, returning + * the value 'value_ptr' to any joining thread. + * NOTE: thread should be joinable. + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + ptw32_thread_t * sp; + + /* + * Don't use pthread_self() to avoid creating an implicit POSIX thread handle + * unnecessarily. + */ + sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + +#if defined(_UWIN) + if (--pthread_count <= 0) + exit ((int) value_ptr); +#endif + + if (NULL == sp) + { + /* + * A POSIX thread handle was never created. I.e. this is a + * Win32 thread that has never called a pthreads-win32 routine that + * required a POSIX handle. + * + * Implicit POSIX handles are cleaned up in ptw32_throw() now. + */ + +#if ! (defined (__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__) + _endthreadex ((unsigned) (size_t) value_ptr); +#else + _endthread (); +#endif + + /* Never reached */ + } + + sp->exitStatus = value_ptr; + + ptw32_throw (PTW32_EPS_EXIT); + + /* Never reached. */ + +} diff --git a/libs/pthreads/src/pthread_getconcurrency.c b/libs/pthreads/src/pthread_getconcurrency.c new file mode 100644 index 0000000000..cf9e9c85c2 --- /dev/null +++ b/libs/pthreads/src/pthread_getconcurrency.c @@ -0,0 +1,45 @@ +/* + * pthread_getconcurrency.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_getconcurrency (void) +{ + return ptw32_concurrency; +} diff --git a/libs/pthreads/src/pthread_getschedparam.c b/libs/pthreads/src/pthread_getschedparam.c new file mode 100644 index 0000000000..0afcfb74a9 --- /dev/null +++ b/libs/pthreads/src/pthread_getschedparam.c @@ -0,0 +1,75 @@ +/* + * sched_getschedparam.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_getschedparam (pthread_t thread, int *policy, + struct sched_param *param) +{ + int result; + + /* Validate the thread id. */ + result = pthread_kill (thread, 0); + if (0 != result) + { + return result; + } + + /* + * Validate the policy and param args. + * Check that a policy constant wasn't passed rather than &policy. + */ + if (policy <= (int *) SCHED_MAX || param == NULL) + { + return EINVAL; + } + + /* Fill out the policy. */ + *policy = SCHED_OTHER; + + /* + * This function must return the priority value set by + * the most recent pthread_setschedparam() or pthread_create() + * for the target thread. It must not return the actual thread + * priority as altered by any system priority adjustments etc. + */ + param->sched_priority = ((ptw32_thread_t *)thread.p)->sched_priority; + + return 0; +} diff --git a/libs/pthreads/src/pthread_getspecific.c b/libs/pthreads/src/pthread_getspecific.c new file mode 100644 index 0000000000..5ee1641dc1 --- /dev/null +++ b/libs/pthreads/src/pthread_getspecific.c @@ -0,0 +1,87 @@ +/* + * pthread_getspecific.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void * +pthread_getspecific (pthread_key_t key) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function returns the current value of key in the + * calling thread. If no value has been set for 'key' in + * the thread, NULL is returned. + * + * PARAMETERS + * key + * an instance of pthread_key_t + * + * + * DESCRIPTION + * This function returns the current value of key in the + * calling thread. If no value has been set for 'key' in + * the thread, NULL is returned. + * + * RESULTS + * key value or NULL on failure + * + * ------------------------------------------------------ + */ +{ + void * ptr; + + if (key == NULL) + { + ptr = NULL; + } + else + { + int lasterror = GetLastError (); +#if defined(RETAIN_WSALASTERROR) + int lastWSAerror = WSAGetLastError (); +#endif + ptr = TlsGetValue (key->key); + + SetLastError (lasterror); +#if defined(RETAIN_WSALASTERROR) + WSASetLastError (lastWSAerror); +#endif + } + + return ptr; +} diff --git a/libs/pthreads/src/pthread_getunique_np.c b/libs/pthreads/src/pthread_getunique_np.c new file mode 100644 index 0000000000..4496c68bf5 --- /dev/null +++ b/libs/pthreads/src/pthread_getunique_np.c @@ -0,0 +1,47 @@ +/* + * pthread_getunique_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * + */ +unsigned __int64 +pthread_getunique_np (pthread_t thread) +{ + return ((ptw32_thread_t*)thread.p)->seqNumber; +} diff --git a/libs/pthreads/src/pthread_getw32threadhandle_np.c b/libs/pthreads/src/pthread_getw32threadhandle_np.c new file mode 100644 index 0000000000..309a8f281f --- /dev/null +++ b/libs/pthreads/src/pthread_getw32threadhandle_np.c @@ -0,0 +1,65 @@ +/* + * pthread_getw32threadhandle_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * pthread_getw32threadhandle_np() + * + * Returns the win32 thread handle that the POSIX + * thread "thread" is running as. + * + * Applications can use the win32 handle to set + * win32 specific attributes of the thread. + */ +HANDLE +pthread_getw32threadhandle_np (pthread_t thread) +{ + return ((ptw32_thread_t *)thread.p)->threadH; +} + +/* + * pthread_getw32threadid_np() + * + * Returns the win32 thread id that the POSIX + * thread "thread" is running as. + */ +DWORD +pthread_getw32threadid_np (pthread_t thread) +{ + return ((ptw32_thread_t *)thread.p)->thread; +} diff --git a/libs/pthreads/src/pthread_join.c b/libs/pthreads/src/pthread_join.c new file mode 100644 index 0000000000..c2b7c1e757 --- /dev/null +++ b/libs/pthreads/src/pthread_join.c @@ -0,0 +1,157 @@ +/* + * pthread_join.c + * + * Description: + * This translation unit implements functions related to thread + * synchronisation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Not needed yet, but defining it should indicate clashes with build target + * environment that should be fixed. + */ +#if !defined(WINCE) +# include +#endif + + +int +pthread_join (pthread_t thread, void **value_ptr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits for 'thread' to terminate and + * returns the thread's exit value if 'value_ptr' is not + * NULL. This also detaches the thread on successful + * completion. + * + * PARAMETERS + * thread + * an instance of pthread_t + * + * value_ptr + * pointer to an instance of pointer to void + * + * + * DESCRIPTION + * This function waits for 'thread' to terminate and + * returns the thread's exit value if 'value_ptr' is not + * NULL. This also detaches the thread on successful + * completion. + * NOTE: detached threads cannot be joined or canceled + * + * RESULTS + * 0 'thread' has completed + * EINVAL thread is not a joinable thread, + * ESRCH no thread could be found with ID 'thread', + * ENOENT thread couldn't find it's own valid handle, + * EDEADLK attempt to join thread with self + * + * ------------------------------------------------------ + */ +{ + int result; + pthread_t self; + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node); + + if (NULL == tp + || thread.x != tp->ptHandle.x) + { + result = ESRCH; + } + else if (PTHREAD_CREATE_DETACHED == tp->detachState) + { + result = EINVAL; + } + else + { + result = 0; + } + + ptw32_mcs_lock_release(&node); + + if (result == 0) + { + /* + * The target thread is joinable and can't be reused before we join it. + */ + self = pthread_self(); + + if (NULL == self.p) + { + result = ENOENT; + } + else if (pthread_equal (self, thread)) + { + result = EDEADLK; + } + else + { + /* + * Pthread_join is a cancelation point. + * If we are canceled then our target thread must not be + * detached (destroyed). This is guarranteed because + * pthreadCancelableWait will not return if we + * are canceled. + */ + result = pthreadCancelableWait (tp->threadH); + + if (0 == result) + { + if (value_ptr != NULL) + { + *value_ptr = tp->exitStatus; + } + + /* + * The result of making multiple simultaneous calls to + * pthread_join() or pthread_detach() specifying the same + * target is undefined. + */ + result = pthread_detach (thread); + } + else + { + result = ESRCH; + } + } + } + + return (result); + +} /* pthread_join */ diff --git a/libs/pthreads/src/pthread_key_create.c b/libs/pthreads/src/pthread_key_create.c new file mode 100644 index 0000000000..65c6f95081 --- /dev/null +++ b/libs/pthreads/src/pthread_key_create.c @@ -0,0 +1,108 @@ +/* + * pthread_key_create.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +/* TLS_OUT_OF_INDEXES not defined on WinCE */ +#if !defined(TLS_OUT_OF_INDEXES) +#define TLS_OUT_OF_INDEXES 0xffffffff +#endif + +int +pthread_key_create (pthread_key_t * key, void (PTW32_CDECL *destructor) (void *)) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function creates a thread-specific data key visible + * to all threads. All existing and new threads have a value + * NULL for key until set using pthread_setspecific. When any + * thread with a non-NULL value for key terminates, 'destructor' + * is called with key's current value for that thread. + * + * PARAMETERS + * key + * pointer to an instance of pthread_key_t + * + * + * DESCRIPTION + * This function creates a thread-specific data key visible + * to all threads. All existing and new threads have a value + * NULL for key until set using pthread_setspecific. When any + * thread with a non-NULL value for key terminates, 'destructor' + * is called with key's current value for that thread. + * + * RESULTS + * 0 successfully created semaphore, + * EAGAIN insufficient resources or PTHREAD_KEYS_MAX + * exceeded, + * ENOMEM insufficient memory to create the key, + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_key_t newkey; + + if ((newkey = (pthread_key_t) calloc (1, sizeof (*newkey))) == NULL) + { + result = ENOMEM; + } + else if ((newkey->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES) + { + result = EAGAIN; + + free (newkey); + newkey = NULL; + } + else if (destructor != NULL) + { + /* + * Have to manage associations between thread and key; + * Therefore, need a lock that allows competing threads + * to gain exclusive access to the key->threads list. + * + * The mutex will only be created when it is first locked. + */ + newkey->keyLock = 0; + newkey->destructor = destructor; + } + + *key = newkey; + + return (result); +} diff --git a/libs/pthreads/src/pthread_key_delete.c b/libs/pthreads/src/pthread_key_delete.c new file mode 100644 index 0000000000..09d70c63f5 --- /dev/null +++ b/libs/pthreads/src/pthread_key_delete.c @@ -0,0 +1,125 @@ +/* + * pthread_key_delete.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_key_delete (pthread_key_t key) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function deletes a thread-specific data key. This + * does not change the value of the thread specific data key + * for any thread and does not run the key's destructor + * in any thread so it should be used with caution. + * + * PARAMETERS + * key + * pointer to an instance of pthread_key_t + * + * + * DESCRIPTION + * This function deletes a thread-specific data key. This + * does not change the value of the thread specific data key + * for any thread and does not run the key's destructor + * in any thread so it should be used with caution. + * + * RESULTS + * 0 successfully deleted the key, + * EINVAL key is invalid, + * + * ------------------------------------------------------ + */ +{ + ptw32_mcs_local_node_t keyLock; + int result = 0; + + if (key != NULL) + { + if (key->threads != NULL && key->destructor != NULL) + { + ThreadKeyAssoc *assoc; + ptw32_mcs_lock_acquire (&(key->keyLock), &keyLock); + /* + * Run through all Thread<-->Key associations + * for this key. + * + * While we hold at least one of the locks guarding + * the assoc, we know that the assoc pointed to by + * key->threads is valid. + */ + while ((assoc = (ThreadKeyAssoc *) key->threads) != NULL) + { + ptw32_mcs_local_node_t threadLock; + ptw32_thread_t * thread = assoc->thread; + + if (assoc == NULL) + { + /* Finished */ + break; + } + + ptw32_mcs_lock_acquire (&(thread->threadLock), &threadLock); + /* + * Since we are starting at the head of the key's threads + * chain, this will also point key->threads at the next assoc. + * While we hold key->keyLock, no other thread can insert + * a new assoc via pthread_setspecific. + */ + ptw32_tkAssocDestroy (assoc); + ptw32_mcs_lock_release (&threadLock); + ptw32_mcs_lock_release (&keyLock); + } + } + + TlsFree (key->key); + if (key->destructor != NULL) + { + /* A thread could be holding the keyLock */ + ptw32_mcs_lock_acquire (&(key->keyLock), &keyLock); + ptw32_mcs_lock_release (&keyLock); + } + +#if defined( _DEBUG ) + memset ((char *) key, 0, sizeof (*key)); +#endif + free (key); + } + + return (result); +} diff --git a/libs/pthreads/src/pthread_kill.c b/libs/pthreads/src/pthread_kill.c new file mode 100644 index 0000000000..5473b43cd4 --- /dev/null +++ b/libs/pthreads/src/pthread_kill.c @@ -0,0 +1,105 @@ +/* + * pthread_kill.c + * + * Description: + * This translation unit implements the pthread_kill routine. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Not needed yet, but defining it should indicate clashes with build target + * environment that should be fixed. + */ +#if !defined(WINCE) +# include +#endif + +int +pthread_kill (pthread_t thread, int sig) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function requests that a signal be delivered to the + * specified thread. If sig is zero, error checking is + * performed but no signal is actually sent such that this + * function can be used to check for a valid thread ID. + * + * PARAMETERS + * thread reference to an instances of pthread_t + * sig signal. Currently only a value of 0 is supported. + * + * + * DESCRIPTION + * This function requests that a signal be delivered to the + * specified thread. If sig is zero, error checking is + * performed but no signal is actually sent such that this + * function can be used to check for a valid thread ID. + * + * RESULTS + * ESRCH the thread is not a valid thread ID, + * EINVAL the value of the signal is invalid + * or unsupported. + * 0 the signal was successfully sent. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + ptw32_thread_t * tp; + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node); + + tp = (ptw32_thread_t *) thread.p; + + if (NULL == tp + || thread.x != tp->ptHandle.x + || NULL == tp->threadH) + { + result = ESRCH; + } + + ptw32_mcs_lock_release(&node); + + if (0 == result && 0 != sig) + { + /* + * Currently does not support any signals. + */ + result = EINVAL; + } + + return result; + +} /* pthread_kill */ diff --git a/libs/pthreads/src/pthread_mutex_consistent.c b/libs/pthreads/src/pthread_mutex_consistent.c new file mode 100644 index 0000000000..b7805e7b19 --- /dev/null +++ b/libs/pthreads/src/pthread_mutex_consistent.c @@ -0,0 +1,190 @@ +/* + * pthread_mutex_consistent.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * From the Sun Multi-threaded Programming Guide + * + * robustness defines the behavior when the owner of the mutex terminates without unlocking the + * mutex, usually because its process terminated abnormally. The value of robustness that is + * defined in pthread.h is PTHREAD_MUTEX_ROBUST or PTHREAD_MUTEX_STALLED. The + * default value is PTHREAD_MUTEX_STALLED . + * ■ PTHREAD_MUTEX_STALLED + * When the owner of the mutex terminates without unlocking the mutex, all subsequent calls + * to pthread_mutex_lock() are blocked from progress in an unspecified manner. + * ■ PTHREAD_MUTEX_ROBUST + * When the owner of the mutex terminates without unlocking the mutex, the mutex is + * unlocked. The next owner of this mutex acquires the mutex with an error return of + * EOWNERDEAD. + * Note – Your application must always check the return code from pthread_mutex_lock() for + * a mutex initialized with the PTHREAD_MUTEX_ROBUST attribute. + * ■ The new owner of this mutex should make the state protected by the mutex consistent. + * This state might have been left inconsistent when the previous owner terminated. + * ■ If the new owner is able to make the state consistent, call + * pthread_mutex_consistent() for the mutex before unlocking the mutex. This + * marks the mutex as consistent and subsequent calls to pthread_mutex_lock() and + * pthread_mutex_unlock() will behave in the normal manner. + * ■ If the new owner is not able to make the state consistent, do not call + * pthread_mutex_consistent() for the mutex, but unlock the mutex. + * All waiters are woken up and all subsequent calls to pthread_mutex_lock() fail to + * acquire the mutex. The return code is ENOTRECOVERABLE. The mutex can be made + * consistent by calling pthread_mutex_destroy() to uninitialize the mutex, and calling + * pthread_mutex_int() to reinitialize the mutex.However, the state that was protected + * by the mutex remains inconsistent and some form of application recovery is required. + * ■ If the thread that acquires the lock with EOWNERDEAD terminates without unlocking the + * mutex, the next owner acquires the lock with an EOWNERDEAD return code. + */ +#if !defined(_UWIN) +/*# include */ +#endif +#include "pthread.h" +#include "implement.h" + +INLINE +int +ptw32_robust_mutex_inherit(pthread_mutex_t * mutex) +{ + int result; + pthread_mutex_t mx = *mutex; + ptw32_robust_node_t* robust = mx->robustNode; + + switch ((LONG)PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR)&robust->stateInconsistent, + (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_INCONSISTENT, + (PTW32_INTERLOCKED_LONG)-1 /* The terminating thread sets this */)) + { + case -1L: + result = EOWNERDEAD; + break; + case (LONG)PTW32_ROBUST_NOTRECOVERABLE: + result = ENOTRECOVERABLE; + break; + default: + result = 0; + break; + } + + return result; +} + +/* + * The next two internal support functions depend on only being + * called by the thread that owns the robust mutex. This enables + * us to avoid additional locks. + * Any mutex currently in the thread's robust mutex list is held + * by the thread, again eliminating the need for locks. + * The forward/backward links allow the thread to unlock mutexes + * in any order, not necessarily the reverse locking order. + * This is all possible because it is an error if a thread that + * does not own the [robust] mutex attempts to unlock it. + */ + +INLINE +void +ptw32_robust_mutex_add(pthread_mutex_t* mutex, pthread_t self) +{ + ptw32_robust_node_t** list; + pthread_mutex_t mx = *mutex; + ptw32_thread_t* tp = (ptw32_thread_t*)self.p; + ptw32_robust_node_t* robust = mx->robustNode; + + list = &tp->robustMxList; + mx->ownerThread = self; + if (NULL == *list) + { + robust->prev = NULL; + robust->next = NULL; + *list = robust; + } + else + { + robust->prev = NULL; + robust->next = *list; + (*list)->prev = robust; + *list = robust; + } +} + +INLINE +void +ptw32_robust_mutex_remove(pthread_mutex_t* mutex, ptw32_thread_t* otp) +{ + ptw32_robust_node_t** list; + pthread_mutex_t mx = *mutex; + ptw32_robust_node_t* robust = mx->robustNode; + + list = &(((ptw32_thread_t*)mx->ownerThread.p)->robustMxList); + mx->ownerThread.p = otp; + if (robust->next != NULL) + { + robust->next->prev = robust->prev; + } + if (robust->prev != NULL) + { + robust->prev->next = robust->next; + } + if (*list == robust) + { + *list = robust->next; + } +} + + +int +pthread_mutex_consistent (pthread_mutex_t* mutex) +{ + pthread_mutex_t mx = *mutex; + int result = 0; + + /* + * Let the system deal with invalid pointers. + */ + if (mx == NULL) + { + return EINVAL; + } + + if (mx->kind >= 0 + || (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_INCONSISTENT != PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR)&mx->robustNode->stateInconsistent, + (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_CONSISTENT, + (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_INCONSISTENT)) + { + result = EINVAL; + } + + return (result); +} + diff --git a/libs/pthreads/src/pthread_mutex_destroy.c b/libs/pthreads/src/pthread_mutex_destroy.c new file mode 100644 index 0000000000..7b8c9cd65b --- /dev/null +++ b/libs/pthreads/src/pthread_mutex_destroy.c @@ -0,0 +1,148 @@ +/* + * pthread_mutex_destroy.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutex_destroy (pthread_mutex_t * mutex) +{ + int result = 0; + pthread_mutex_t mx; + + /* + * Let the system deal with invalid pointers. + */ + + /* + * Check to see if we have something to delete. + */ + if (*mutex < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + mx = *mutex; + + result = pthread_mutex_trylock (&mx); + + /* + * If trylock succeeded and the mutex is not recursively locked it + * can be destroyed. + */ + if (0 == result || ENOTRECOVERABLE == result) + { + if (mx->kind != PTHREAD_MUTEX_RECURSIVE || 1 == mx->recursive_count) + { + /* + * FIXME!!! + * The mutex isn't held by another thread but we could still + * be too late invalidating the mutex below since another thread + * may already have entered mutex_lock and the check for a valid + * *mutex != NULL. + */ + *mutex = NULL; + + result = (0 == result)?pthread_mutex_unlock(&mx):0; + + if (0 == result) + { + if (mx->robustNode != NULL) + { + free(mx->robustNode); + } + if (!CloseHandle (mx->event)) + { + *mutex = mx; + result = EINVAL; + } + else + { + free (mx); + } + } + else + { + /* + * Restore the mutex before we return the error. + */ + *mutex = mx; + } + } + else /* mx->recursive_count > 1 */ + { + /* + * The mutex must be recursive and already locked by us (this thread). + */ + mx->recursive_count--; /* Undo effect of pthread_mutex_trylock() above */ + result = EBUSY; + } + } + } + else + { + ptw32_mcs_local_node_t node; + + /* + * See notes in ptw32_mutex_check_need_init() above also. + */ + + ptw32_mcs_lock_acquire(&ptw32_mutex_test_init_lock, &node); + + /* + * Check again. + */ + if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised mutex that has not yet been used (initialised). + * If we get to here, another thread + * waiting to initialise this mutex will get an EINVAL. + */ + *mutex = NULL; + } + else + { + /* + * The mutex has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + ptw32_mcs_lock_release(&node); + } + + return (result); +} diff --git a/libs/pthreads/src/pthread_mutex_init.c b/libs/pthreads/src/pthread_mutex_init.c new file mode 100644 index 0000000000..daf805e5bc --- /dev/null +++ b/libs/pthreads/src/pthread_mutex_init.c @@ -0,0 +1,130 @@ +/* + * pthread_mutex_init.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t * attr) +{ + int result = 0; + pthread_mutex_t mx; + + if (mutex == NULL) + { + return EINVAL; + } + + if (attr != NULL && *attr != NULL) + { + if ((*attr)->pshared == PTHREAD_PROCESS_SHARED) + { + /* + * Creating mutex that can be shared between + * processes. + */ +#if _POSIX_THREAD_PROCESS_SHARED >= 0 + + /* + * Not implemented yet. + */ + +#error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet. + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + } + } + + mx = (pthread_mutex_t) calloc (1, sizeof (*mx)); + + if (mx == NULL) + { + result = ENOMEM; + } + else + { + mx->lock_idx = 0; + mx->recursive_count = 0; + mx->robustNode = NULL; + if (attr == NULL || *attr == NULL) + { + mx->kind = PTHREAD_MUTEX_DEFAULT; + } + else + { + mx->kind = (*attr)->kind; + if ((*attr)->robustness == PTHREAD_MUTEX_ROBUST) + { + /* + * Use the negative range to represent robust types. + * Replaces a memory fetch with a register negate and incr + * in pthread_mutex_lock etc. + * + * Map 0,1,..,n to -1,-2,..,(-n)-1 + */ + mx->kind = -mx->kind - 1; + + mx->robustNode = (ptw32_robust_node_t*) malloc(sizeof(ptw32_robust_node_t)); + mx->robustNode->stateInconsistent = PTW32_ROBUST_CONSISTENT; + mx->robustNode->mx = mx; + mx->robustNode->next = NULL; + mx->robustNode->prev = NULL; + } + } + + mx->ownerThread.p = NULL; + + mx->event = CreateEvent (NULL, PTW32_FALSE, /* manual reset = No */ + PTW32_FALSE, /* initial state = not signaled */ + NULL); /* event name */ + + if (0 == mx->event) + { + result = ENOSPC; + free (mx); + mx = NULL; + } + } + + *mutex = mx; + + return (result); +} diff --git a/libs/pthreads/src/pthread_mutex_lock.c b/libs/pthreads/src/pthread_mutex_lock.c new file mode 100644 index 0000000000..eee9abe8c7 --- /dev/null +++ b/libs/pthreads/src/pthread_mutex_lock.c @@ -0,0 +1,269 @@ +/* + * pthread_mutex_lock.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined(_UWIN) +/*# include */ +#endif +#include "pthread.h" +#include "implement.h" + +int +pthread_mutex_lock (pthread_mutex_t * mutex) +{ + int kind; + pthread_mutex_t mx; + int result = 0; + + /* + * Let the system deal with invalid pointers. + */ + if (*mutex == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static mutex. We check + * again inside the guarded section of ptw32_mutex_check_need_init() + * to avoid race conditions. + */ + if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + if ((result = ptw32_mutex_check_need_init (mutex)) != 0) + { + return (result); + } + } + + mx = *mutex; + kind = mx->kind; + + if (kind >= 0) + { + /* Non-robust */ + if (PTHREAD_MUTEX_NORMAL == kind) + { + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1) != 0) + { + while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } + } + } + } + else + { + pthread_t self = pthread_self(); + + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) + { + mx->recursive_count = 1; + mx->ownerThread = self; + } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (kind == PTHREAD_MUTEX_RECURSIVE) + { + mx->recursive_count++; + } + else + { + result = EDEADLK; + } + } + else + { + while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } + } + + if (0 == result) + { + mx->recursive_count = 1; + mx->ownerThread = self; + } + } + } + } + } + else + { + /* + * Robust types + * All types record the current owner thread. + * The mutex is added to a per thread list when ownership is acquired. + */ + ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent; + + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + result = ENOTRECOVERABLE; + } + else + { + pthread_t self = pthread_self(); + + kind = -kind - 1; /* Convert to non-robust range */ + + if (PTHREAD_MUTEX_NORMAL == kind) + { + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1) != 0) + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex)) + && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + break; + } + } + } + if (0 == result || EOWNERDEAD == result) + { + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); + } + } + else + { + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) + { + mx->recursive_count = 1; + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); + } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (PTHREAD_MUTEX_RECURSIVE == kind) + { + mx->recursive_count++; + } + else + { + result = EDEADLK; + } + } + else + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex)) + && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (WAIT_OBJECT_0 != WaitForSingleObject (mx->event, INFINITE)) + { + result = EINVAL; + break; + } + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + break; + } + } + + if (0 == result || EOWNERDEAD == result) + { + mx->recursive_count = 1; + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); + } + } + } + } + } + } + + return (result); +} + diff --git a/libs/pthreads/src/pthread_mutex_timedlock.c b/libs/pthreads/src/pthread_mutex_timedlock.c new file mode 100644 index 0000000000..1745316795 --- /dev/null +++ b/libs/pthreads/src/pthread_mutex_timedlock.c @@ -0,0 +1,324 @@ +/* + * pthread_mutex_timedlock.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +static INLINE int +ptw32_timed_eventwait (HANDLE event, const struct timespec *abstime) + /* + * ------------------------------------------------------ + * DESCRIPTION + * This function waits on an event until signaled or until + * abstime passes. + * If abstime has passed when this routine is called then + * it returns a result to indicate this. + * + * If 'abstime' is a NULL pointer then this function will + * block until it can successfully decrease the value or + * until interrupted by a signal. + * + * This routine is not a cancelation point. + * + * RESULTS + * 0 successfully signaled, + * ETIMEDOUT abstime passed + * EINVAL 'event' is not a valid event, + * + * ------------------------------------------------------ + */ +{ + + DWORD milliseconds; + DWORD status; + + if (event == NULL) + { + return EINVAL; + } + else + { + if (abstime == NULL) + { + milliseconds = INFINITE; + } + else + { + /* + * Calculate timeout as milliseconds from current system time. + */ + milliseconds = ptw32_relmillisecs (abstime); + } + + status = WaitForSingleObject (event, milliseconds); + + if (status == WAIT_OBJECT_0) + { + return 0; + } + else if (status == WAIT_TIMEOUT) + { + return ETIMEDOUT; + } + else + { + return EINVAL; + } + } + + return 0; + +} /* ptw32_timed_semwait */ + + +int +pthread_mutex_timedlock (pthread_mutex_t * mutex, + const struct timespec *abstime) +{ + pthread_mutex_t mx; + int kind; + int result = 0; + + /* + * Let the system deal with invalid pointers. + */ + + /* + * We do a quick check to see if we need to do more work + * to initialise a static mutex. We check + * again inside the guarded section of ptw32_mutex_check_need_init() + * to avoid race conditions. + */ + if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + if ((result = ptw32_mutex_check_need_init (mutex)) != 0) + { + return (result); + } + } + + mx = *mutex; + kind = mx->kind; + + if (kind >= 0) + { + if (mx->kind == PTHREAD_MUTEX_NORMAL) + { + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1) != 0) + { + while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + } + } + } + else + { + pthread_t self = pthread_self(); + + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0) == 0) + { + mx->recursive_count = 1; + mx->ownerThread = self; + } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (mx->kind == PTHREAD_MUTEX_RECURSIVE) + { + mx->recursive_count++; + } + else + { + return EDEADLK; + } + } + else + { + while ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + } + + mx->recursive_count = 1; + mx->ownerThread = self; + } + } + } + } + else + { + /* + * Robust types + * All types record the current owner thread. + * The mutex is added to a per thread list when ownership is acquired. + */ + ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent; + + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + result = ENOTRECOVERABLE; + } + else + { + pthread_t self = pthread_self(); + + kind = -kind - 1; /* Convert to non-robust range */ + + if (PTHREAD_MUTEX_NORMAL == kind) + { + if ((PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1) != 0) + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex)) + && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + break; + } + } + + if (0 == result || EOWNERDEAD == result) + { + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); + } + } + } + else + { + pthread_t self = pthread_self(); + + if (0 == (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0)) + { + mx->recursive_count = 1; + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); + } + else + { + if (pthread_equal (mx->ownerThread, self)) + { + if (PTHREAD_MUTEX_RECURSIVE == kind) + { + mx->recursive_count++; + } + else + { + return EDEADLK; + } + } + else + { + while (0 == (result = ptw32_robust_mutex_inherit(mutex)) + && (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) -1) != 0) + { + if (0 != (result = ptw32_timed_eventwait (mx->event, abstime))) + { + return result; + } + } + + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + /* Unblock the next thread */ + SetEvent(mx->event); + result = ENOTRECOVERABLE; + } + else if (0 == result || EOWNERDEAD == result) + { + mx->recursive_count = 1; + /* + * Add mutex to the per-thread robust mutex currently-held list. + * If the thread terminates, all mutexes in this list will be unlocked. + */ + ptw32_robust_mutex_add(mutex, self); + } + } + } + } + } + } + + return result; +} diff --git a/libs/pthreads/src/pthread_mutex_trylock.c b/libs/pthreads/src/pthread_mutex_trylock.c new file mode 100644 index 0000000000..d6b68724db --- /dev/null +++ b/libs/pthreads/src/pthread_mutex_trylock.c @@ -0,0 +1,154 @@ +/* + * pthread_mutex_trylock.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutex_trylock (pthread_mutex_t * mutex) +{ + pthread_mutex_t mx; + int kind; + int result = 0; + + /* + * Let the system deal with invalid pointers. + */ + + /* + * We do a quick check to see if we need to do more work + * to initialise a static mutex. We check + * again inside the guarded section of ptw32_mutex_check_need_init() + * to avoid race conditions. + */ + if (*mutex >= PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + if ((result = ptw32_mutex_check_need_init (mutex)) != 0) + { + return (result); + } + } + + mx = *mutex; + kind = mx->kind; + + if (kind >= 0) + { + /* Non-robust */ + if (0 == (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG ( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0)) + { + if (kind != PTHREAD_MUTEX_NORMAL) + { + mx->recursive_count = 1; + mx->ownerThread = pthread_self (); + } + } + else + { + if (kind == PTHREAD_MUTEX_RECURSIVE && + pthread_equal (mx->ownerThread, pthread_self ())) + { + mx->recursive_count++; + } + else + { + result = EBUSY; + } + } + } + else + { + /* + * Robust types + * All types record the current owner thread. + * The mutex is added to a per thread list when ownership is acquired. + */ + pthread_t self; + ptw32_robust_state_t* statePtr = &mx->robustNode->stateInconsistent; + + if ((PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE == + PTW32_INTERLOCKED_EXCHANGE_ADD_LONG( + (PTW32_INTERLOCKED_LONGPTR)statePtr, + (PTW32_INTERLOCKED_LONG)0)) + { + return ENOTRECOVERABLE; + } + + self = pthread_self(); + kind = -kind - 1; /* Convert to non-robust range */ + + if (0 == (PTW32_INTERLOCKED_LONG) PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG ( + (PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 1, + (PTW32_INTERLOCKED_LONG) 0)) + { + if (kind != PTHREAD_MUTEX_NORMAL) + { + mx->recursive_count = 1; + } + ptw32_robust_mutex_add(mutex, self); + } + else + { + if (PTHREAD_MUTEX_RECURSIVE == kind && + pthread_equal (mx->ownerThread, pthread_self ())) + { + mx->recursive_count++; + } + else + { + if (EOWNERDEAD == (result = ptw32_robust_mutex_inherit(mutex))) + { + mx->recursive_count = 1; + ptw32_robust_mutex_add(mutex, self); + } + else + { + if (0 == result) + { + result = EBUSY; + } + } + } + } + } + + return (result); +} diff --git a/libs/pthreads/src/pthread_mutex_unlock.c b/libs/pthreads/src/pthread_mutex_unlock.c new file mode 100644 index 0000000000..3d65d1a957 --- /dev/null +++ b/libs/pthreads/src/pthread_mutex_unlock.c @@ -0,0 +1,175 @@ +/* + * pthread_mutex_unlock.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutex_unlock (pthread_mutex_t * mutex) +{ + int result = 0; + int kind; + pthread_mutex_t mx; + + /* + * Let the system deal with invalid pointers. + */ + + mx = *mutex; + + /* + * If the thread calling us holds the mutex then there is no + * race condition. If another thread holds the + * lock then we shouldn't be in here. + */ + if (mx < PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + kind = mx->kind; + + if (kind >= 0) + { + if (kind == PTHREAD_MUTEX_NORMAL) + { + LONG idx; + + idx = (LONG) PTW32_INTERLOCKED_EXCHANGE_LONG ((PTW32_INTERLOCKED_LONGPTR)&mx->lock_idx, + (PTW32_INTERLOCKED_LONG)0); + if (idx != 0) + { + if (idx < 0) + { + /* + * Someone may be waiting on that mutex. + */ + if (SetEvent (mx->event) == 0) + { + result = EINVAL; + } + } + } + } + else + { + if (pthread_equal (mx->ownerThread, pthread_self())) + { + if (kind != PTHREAD_MUTEX_RECURSIVE + || 0 == --mx->recursive_count) + { + mx->ownerThread.p = NULL; + + if ((LONG) PTW32_INTERLOCKED_EXCHANGE_LONG ((PTW32_INTERLOCKED_LONGPTR)&mx->lock_idx, + (PTW32_INTERLOCKED_LONG)0) < 0L) + { + /* Someone may be waiting on that mutex */ + if (SetEvent (mx->event) == 0) + { + result = EINVAL; + } + } + } + } + else + { + result = EPERM; + } + } + } + else + { + /* Robust types */ + pthread_t self = pthread_self(); + kind = -kind - 1; /* Convert to non-robust range */ + + /* + * The thread must own the lock regardless of type if the mutex + * is robust. + */ + if (pthread_equal (mx->ownerThread, self)) + { + PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG((PTW32_INTERLOCKED_LONGPTR) &mx->robustNode->stateInconsistent, + (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_NOTRECOVERABLE, + (PTW32_INTERLOCKED_LONG)PTW32_ROBUST_INCONSISTENT); + if (PTHREAD_MUTEX_NORMAL == kind) + { + ptw32_robust_mutex_remove(mutex, NULL); + + if ((LONG) PTW32_INTERLOCKED_EXCHANGE_LONG((PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 0) < 0) + { + /* + * Someone may be waiting on that mutex. + */ + if (SetEvent (mx->event) == 0) + { + result = EINVAL; + } + } + } + else + { + if (kind != PTHREAD_MUTEX_RECURSIVE + || 0 == --mx->recursive_count) + { + ptw32_robust_mutex_remove(mutex, NULL); + + if ((LONG) PTW32_INTERLOCKED_EXCHANGE_LONG((PTW32_INTERLOCKED_LONGPTR) &mx->lock_idx, + (PTW32_INTERLOCKED_LONG) 0) < 0) + { + /* + * Someone may be waiting on that mutex. + */ + if (SetEvent (mx->event) == 0) + { + result = EINVAL; + } + } + } + } + } + else + { + result = EPERM; + } + } + } + else if (mx != PTHREAD_MUTEX_INITIALIZER) + { + result = EINVAL; + } + + return (result); +} diff --git a/libs/pthreads/src/pthread_mutexattr_destroy.c b/libs/pthreads/src/pthread_mutexattr_destroy.c new file mode 100644 index 0000000000..9d424bfa28 --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_destroy.c @@ -0,0 +1,83 @@ +/* + * pthread_mutexattr_destroy.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_destroy (pthread_mutexattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a mutex attributes object. The object can + * no longer be used. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * + * DESCRIPTION + * Destroys a mutex attributes object. The object can + * no longer be used. + * + * NOTES: + * 1) Does not affect mutexes created using 'attr' + * + * RESULTS + * 0 successfully released attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (attr == NULL || *attr == NULL) + { + result = EINVAL; + } + else + { + pthread_mutexattr_t ma = *attr; + + *attr = NULL; + free (ma); + } + + return (result); +} /* pthread_mutexattr_destroy */ diff --git a/libs/pthreads/src/pthread_mutexattr_getkind_np.c b/libs/pthreads/src/pthread_mutexattr_getkind_np.c new file mode 100644 index 0000000000..2d82ec6bc7 --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_getkind_np.c @@ -0,0 +1,44 @@ +/* + * pthread_mutexattr_getkind_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +pthread_mutexattr_getkind_np (pthread_mutexattr_t * attr, int *kind) +{ + return pthread_mutexattr_gettype (attr, kind); +} diff --git a/libs/pthreads/src/pthread_mutexattr_getpshared.c b/libs/pthreads/src/pthread_mutexattr_getpshared.c new file mode 100644 index 0000000000..42f9589c51 --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_getpshared.c @@ -0,0 +1,95 @@ +/* + * pthread_mutexattr_getpshared.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_getpshared (const pthread_mutexattr_t * attr, int *pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Determine whether mutexes created with 'attr' can be + * shared between processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * pshared + * will be set to one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * NOTES: + * 1) pshared mutexes MUST be allocated in shared + * memory. + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully retrieved attribute, + * EINVAL 'attr' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && (pshared != NULL)) + { + *pshared = (*attr)->pshared; + result = 0; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_mutexattr_getpshared */ diff --git a/libs/pthreads/src/pthread_mutexattr_getrobust.c b/libs/pthreads/src/pthread_mutexattr_getrobust.c new file mode 100644 index 0000000000..be004837bc --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_getrobust.c @@ -0,0 +1,113 @@ +/* + * pthread_mutexattr_getrobust.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_getrobust (const pthread_mutexattr_t * attr, int * robust) + /* + * ------------------------------------------------------ + * + * DOCPUBLIC + * The pthread_mutexattr_setrobust() and + * pthread_mutexattr_getrobust() functions respectively set and + * get the mutex robust attribute. This attribute is set in the + * robust parameter to these functions. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * robust + * must be one of: + * + * PTHREAD_MUTEX_STALLED + * + * PTHREAD_MUTEX_ROBUST + * + * DESCRIPTION + * The pthread_mutexattr_setrobust() and + * pthread_mutexattr_getrobust() functions respectively set and + * get the mutex robust attribute. This attribute is set in the + * robust parameter to these functions. The default value of the + * robust attribute is PTHREAD_MUTEX_STALLED. + * + * The robustness of mutex is contained in the robustness attribute + * of the mutex attributes. Valid mutex robustness values are: + * + * PTHREAD_MUTEX_STALLED + * No special actions are taken if the owner of the mutex is + * terminated while holding the mutex lock. This can lead to + * deadlocks if no other thread can unlock the mutex. + * This is the default value. + * + * PTHREAD_MUTEX_ROBUST + * If the process containing the owning thread of a robust mutex + * terminates while holding the mutex lock, the next thread that + * acquires the mutex shall be notified about the termination by + * the return value [EOWNERDEAD] from the locking function. If the + * owning thread of a robust mutex terminates while holding the mutex + * lock, the next thread that acquires the mutex may be notified + * about the termination by the return value [EOWNERDEAD]. The + * notified thread can then attempt to mark the state protected by + * the mutex as consistent again by a call to + * pthread_mutex_consistent(). After a subsequent successful call to + * pthread_mutex_unlock(), the mutex lock shall be released and can + * be used normally by other threads. If the mutex is unlocked without + * a call to pthread_mutex_consistent(), it shall be in a permanently + * unusable state and all attempts to lock the mutex shall fail with + * the error [ENOTRECOVERABLE]. The only permissible operation on such + * a mutex is pthread_mutex_destroy(). + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or 'robust' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result = EINVAL; + + if ((attr != NULL && *attr != NULL && robust != NULL)) + { + *robust = (*attr)->robustness; + result = 0; + } + + return (result); +} /* pthread_mutexattr_getrobust */ diff --git a/libs/pthreads/src/pthread_mutexattr_gettype.c b/libs/pthreads/src/pthread_mutexattr_gettype.c new file mode 100644 index 0000000000..c63fcfa03a --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_gettype.c @@ -0,0 +1,56 @@ +/* + * pthread_mutexattr_gettype.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind) +{ + int result = 0; + + if (attr != NULL && *attr != NULL && kind != NULL) + { + *kind = (*attr)->kind; + } + else + { + result = EINVAL; + } + + return (result); +} diff --git a/libs/pthreads/src/pthread_mutexattr_init.c b/libs/pthreads/src/pthread_mutexattr_init.c new file mode 100644 index 0000000000..d2797ff248 --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_init.c @@ -0,0 +1,86 @@ +/* + * pthread_mutexattr_init.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_init (pthread_mutexattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a mutex attributes object with default + * attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * + * DESCRIPTION + * Initializes a mutex attributes object with default + * attributes. + * + * NOTES: + * 1) Used to define mutex types + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_mutexattr_t ma; + + ma = (pthread_mutexattr_t) calloc (1, sizeof (*ma)); + + if (ma == NULL) + { + result = ENOMEM; + } + else + { + ma->pshared = PTHREAD_PROCESS_PRIVATE; + ma->kind = PTHREAD_MUTEX_DEFAULT; + } + + *attr = ma; + + return (result); +} /* pthread_mutexattr_init */ diff --git a/libs/pthreads/src/pthread_mutexattr_setkind_np.c b/libs/pthreads/src/pthread_mutexattr_setkind_np.c new file mode 100644 index 0000000000..faa936658f --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_setkind_np.c @@ -0,0 +1,44 @@ +/* + * pthread_mutexattr_setkind_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +pthread_mutexattr_setkind_np (pthread_mutexattr_t * attr, int kind) +{ + return pthread_mutexattr_settype (attr, kind); +} diff --git a/libs/pthreads/src/pthread_mutexattr_setpshared.c b/libs/pthreads/src/pthread_mutexattr_setpshared.c new file mode 100644 index 0000000000..cfa6f71994 --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_setpshared.c @@ -0,0 +1,119 @@ +/* + * pthread_mutexattr_setpshared.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, int pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Mutexes created with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * pshared + * must be one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * DESCRIPTION + * Mutexes creatd with 'attr' can be shared between + * processes if pthread_mutex_t variable is allocated + * in memory shared by these processes. + * + * NOTES: + * 1) pshared mutexes MUST be allocated in shared + * memory. + * + * 2) The following macro is defined if shared mutexes + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && + ((pshared == PTHREAD_PROCESS_SHARED) || + (pshared == PTHREAD_PROCESS_PRIVATE))) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + +#if !defined( _POSIX_THREAD_PROCESS_SHARED ) + + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; + +#else + + result = 0; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + else + { + result = 0; + } + + (*attr)->pshared = pshared; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_mutexattr_setpshared */ diff --git a/libs/pthreads/src/pthread_mutexattr_setrobust.c b/libs/pthreads/src/pthread_mutexattr_setrobust.c new file mode 100644 index 0000000000..b1acef7572 --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_setrobust.c @@ -0,0 +1,119 @@ +/* + * pthread_mutexattr_setrobust.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_setrobust (pthread_mutexattr_t * attr, int robust) + /* + * ------------------------------------------------------ + * + * DOCPUBLIC + * The pthread_mutexattr_setrobust() and + * pthread_mutexattr_getrobust() functions respectively set and + * get the mutex robust attribute. This attribute is set in the + * robust parameter to these functions. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * robust + * must be one of: + * + * PTHREAD_MUTEX_STALLED + * + * PTHREAD_MUTEX_ROBUST + * + * DESCRIPTION + * The pthread_mutexattr_setrobust() and + * pthread_mutexattr_getrobust() functions respectively set and + * get the mutex robust attribute. This attribute is set in the + * robust parameter to these functions. The default value of the + * robust attribute is PTHREAD_MUTEX_STALLED. + * + * The robustness of mutex is contained in the robustness attribute + * of the mutex attributes. Valid mutex robustness values are: + * + * PTHREAD_MUTEX_STALLED + * No special actions are taken if the owner of the mutex is + * terminated while holding the mutex lock. This can lead to + * deadlocks if no other thread can unlock the mutex. + * This is the default value. + * + * PTHREAD_MUTEX_ROBUST + * If the process containing the owning thread of a robust mutex + * terminates while holding the mutex lock, the next thread that + * acquires the mutex shall be notified about the termination by + * the return value [EOWNERDEAD] from the locking function. If the + * owning thread of a robust mutex terminates while holding the mutex + * lock, the next thread that acquires the mutex may be notified + * about the termination by the return value [EOWNERDEAD]. The + * notified thread can then attempt to mark the state protected by + * the mutex as consistent again by a call to + * pthread_mutex_consistent(). After a subsequent successful call to + * pthread_mutex_unlock(), the mutex lock shall be released and can + * be used normally by other threads. If the mutex is unlocked without + * a call to pthread_mutex_consistent(), it shall be in a permanently + * unusable state and all attempts to lock the mutex shall fail with + * the error [ENOTRECOVERABLE]. The only permissible operation on such + * a mutex is pthread_mutex_destroy(). + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or 'robust' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result = EINVAL; + + if ((attr != NULL && *attr != NULL)) + { + switch (robust) + { + case PTHREAD_MUTEX_STALLED: + case PTHREAD_MUTEX_ROBUST: + (*attr)->robustness = robust; + result = 0; + break; + } + } + + return (result); +} /* pthread_mutexattr_setrobust */ diff --git a/libs/pthreads/src/pthread_mutexattr_settype.c b/libs/pthreads/src/pthread_mutexattr_settype.c new file mode 100644 index 0000000000..8365daf65d --- /dev/null +++ b/libs/pthreads/src/pthread_mutexattr_settype.c @@ -0,0 +1,143 @@ +/* + * pthread_mutexattr_settype.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind) + /* + * ------------------------------------------------------ + * + * DOCPUBLIC + * The pthread_mutexattr_settype() and + * pthread_mutexattr_gettype() functions respectively set and + * get the mutex type attribute. This attribute is set in the + * type parameter to these functions. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_mutexattr_t + * + * type + * must be one of: + * + * PTHREAD_MUTEX_DEFAULT + * + * PTHREAD_MUTEX_NORMAL + * + * PTHREAD_MUTEX_ERRORCHECK + * + * PTHREAD_MUTEX_RECURSIVE + * + * DESCRIPTION + * The pthread_mutexattr_settype() and + * pthread_mutexattr_gettype() functions respectively set and + * get the mutex type attribute. This attribute is set in the + * type parameter to these functions. The default value of the + * type attribute is PTHREAD_MUTEX_DEFAULT. + * + * The type of mutex is contained in the type attribute of the + * mutex attributes. Valid mutex types include: + * + * PTHREAD_MUTEX_NORMAL + * This type of mutex does not detect deadlock. A + * thread attempting to relock this mutex without + * first unlocking it will deadlock. Attempting to + * unlock a mutex locked by a different thread + * results in undefined behavior. Attempting to + * unlock an unlocked mutex results in undefined + * behavior. + * + * PTHREAD_MUTEX_ERRORCHECK + * This type of mutex provides error checking. A + * thread attempting to relock this mutex without + * first unlocking it will return with an error. A + * thread attempting to unlock a mutex which another + * thread has locked will return with an error. A + * thread attempting to unlock an unlocked mutex will + * return with an error. + * + * PTHREAD_MUTEX_DEFAULT + * Same as PTHREAD_MUTEX_NORMAL. + * + * PTHREAD_MUTEX_RECURSIVE + * A thread attempting to relock this mutex without + * first unlocking it will succeed in locking the + * mutex. The relocking deadlock which can occur with + * mutexes of type PTHREAD_MUTEX_NORMAL cannot occur + * with this type of mutex. Multiple locks of this + * mutex require the same number of unlocks to + * release the mutex before another thread can + * acquire the mutex. A thread attempting to unlock a + * mutex which another thread has locked will return + * with an error. A thread attempting to unlock an + * unlocked mutex will return with an error. This + * type of mutex is only supported for mutexes whose + * process shared attribute is + * PTHREAD_PROCESS_PRIVATE. + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or 'type' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if ((attr != NULL && *attr != NULL)) + { + switch (kind) + { + case PTHREAD_MUTEX_FAST_NP: + case PTHREAD_MUTEX_RECURSIVE_NP: + case PTHREAD_MUTEX_ERRORCHECK_NP: + (*attr)->kind = kind; + break; + default: + result = EINVAL; + break; + } + } + else + { + result = EINVAL; + } + + return (result); +} /* pthread_mutexattr_settype */ diff --git a/libs/pthreads/src/pthread_num_processors_np.c b/libs/pthreads/src/pthread_num_processors_np.c new file mode 100644 index 0000000000..3067d117d3 --- /dev/null +++ b/libs/pthreads/src/pthread_num_processors_np.c @@ -0,0 +1,56 @@ +/* + * pthread_num_processors_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * pthread_num_processors_np() + * + * Get the number of CPUs available to the process. + */ +int +pthread_num_processors_np (void) +{ + int count; + + if (ptw32_getprocessors (&count) != 0) + { + count = 1; + } + + return (count); +} diff --git a/libs/pthreads/src/pthread_once.c b/libs/pthreads/src/pthread_once.c new file mode 100644 index 0000000000..3bfeb9f0bf --- /dev/null +++ b/libs/pthreads/src/pthread_once.c @@ -0,0 +1,79 @@ +/* + * pthread_once.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +pthread_once (pthread_once_t * once_control, void (PTW32_CDECL *init_routine) (void)) +{ + if (once_control == NULL || init_routine == NULL) + { + return EINVAL; + } + + if ((PTW32_INTERLOCKED_LONG)PTW32_FALSE == + (PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_EXCHANGE_ADD_LONG((PTW32_INTERLOCKED_LONGPTR)&once_control->done, + (PTW32_INTERLOCKED_LONG)0)) /* MBR fence */ + { + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&once_control->lock, &node); + + if (!once_control->done) + { + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth(0) +#endif + + pthread_cleanup_push(ptw32_mcs_lock_release, &node); + (*init_routine)(); + pthread_cleanup_pop(0); + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth() +#endif + + once_control->done = PTW32_TRUE; + } + + ptw32_mcs_lock_release(&node); + } + + return 0; + +} /* pthread_once */ diff --git a/libs/pthreads/src/pthread_rwlock_destroy.c b/libs/pthreads/src/pthread_rwlock_destroy.c new file mode 100644 index 0000000000..245a892410 --- /dev/null +++ b/libs/pthreads/src/pthread_rwlock_destroy.c @@ -0,0 +1,143 @@ +/* + * pthread_rwlock_destroy.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_destroy (pthread_rwlock_t * rwlock) +{ + pthread_rwlock_t rwl; + int result = 0, result1 = 0, result2 = 0; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + if (*rwlock != PTHREAD_RWLOCK_INITIALIZER) + { + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if ((result = + pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + /* + * Check whether any threads own/wait for the lock (wait for ex.access); + * report "BUSY" if so. + */ + if (rwl->nExclusiveAccessCount > 0 + || rwl->nSharedAccessCount > rwl->nCompletedSharedAccessCount) + { + result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); + result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + result2 = EBUSY; + } + else + { + rwl->nMagic = 0; + + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + pthread_mutex_unlock (&rwl->mtxExclusiveAccess); + return result; + } + + if ((result = + pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + *rwlock = NULL; /* Invalidate rwlock before anything else */ + result = pthread_cond_destroy (&(rwl->cndSharedAccessCompleted)); + result1 = pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted)); + result2 = pthread_mutex_destroy (&(rwl->mtxExclusiveAccess)); + (void) free (rwl); + } + } + else + { + ptw32_mcs_local_node_t node; + /* + * See notes in ptw32_rwlock_check_need_init() above also. + */ + ptw32_mcs_lock_acquire(&ptw32_rwlock_test_init_lock, &node); + + /* + * Check again. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised rwlock that has not yet been used (initialised). + * If we get to here, another thread + * waiting to initialise this rwlock will get an EINVAL. + */ + *rwlock = NULL; + } + else + { + /* + * The rwlock has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + + ptw32_mcs_lock_release(&node); + } + + return ((result != 0) ? result : ((result1 != 0) ? result1 : result2)); +} diff --git a/libs/pthreads/src/pthread_rwlock_init.c b/libs/pthreads/src/pthread_rwlock_init.c new file mode 100644 index 0000000000..597c1ff266 --- /dev/null +++ b/libs/pthreads/src/pthread_rwlock_init.c @@ -0,0 +1,109 @@ +/* + * pthread_rwlock_init.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_init (pthread_rwlock_t * rwlock, + const pthread_rwlockattr_t * attr) +{ + int result; + pthread_rwlock_t rwl = 0; + + if (rwlock == NULL) + { + return EINVAL; + } + + if (attr != NULL && *attr != NULL) + { + result = EINVAL; /* Not supported */ + goto DONE; + } + + rwl = (pthread_rwlock_t) calloc (1, sizeof (*rwl)); + + if (rwl == NULL) + { + result = ENOMEM; + goto DONE; + } + + rwl->nSharedAccessCount = 0; + rwl->nExclusiveAccessCount = 0; + rwl->nCompletedSharedAccessCount = 0; + + result = pthread_mutex_init (&rwl->mtxExclusiveAccess, NULL); + if (result != 0) + { + goto FAIL0; + } + + result = pthread_mutex_init (&rwl->mtxSharedAccessCompleted, NULL); + if (result != 0) + { + goto FAIL1; + } + + result = pthread_cond_init (&rwl->cndSharedAccessCompleted, NULL); + if (result != 0) + { + goto FAIL2; + } + + rwl->nMagic = PTW32_RWLOCK_MAGIC; + + result = 0; + goto DONE; + +FAIL2: + (void) pthread_mutex_destroy (&(rwl->mtxSharedAccessCompleted)); + +FAIL1: + (void) pthread_mutex_destroy (&(rwl->mtxExclusiveAccess)); + +FAIL0: + (void) free (rwl); + rwl = NULL; + +DONE: + *rwlock = rwl; + + return result; +} diff --git a/libs/pthreads/src/pthread_rwlock_rdlock.c b/libs/pthreads/src/pthread_rwlock_rdlock.c new file mode 100644 index 0000000000..91e180835e --- /dev/null +++ b/libs/pthreads/src/pthread_rwlock_rdlock.c @@ -0,0 +1,102 @@ +/* + * pthread_rwlock_rdlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_rdlock (pthread_rwlock_t * rwlock) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if (++rwl->nSharedAccessCount == INT_MAX) + { + if ((result = + pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + } + + return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))); +} diff --git a/libs/pthreads/src/pthread_rwlock_timedrdlock.c b/libs/pthreads/src/pthread_rwlock_timedrdlock.c new file mode 100644 index 0000000000..7133778bf1 --- /dev/null +++ b/libs/pthreads/src/pthread_rwlock_timedrdlock.c @@ -0,0 +1,109 @@ +/* + * pthread_rwlock_timedrdlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_timedrdlock (pthread_rwlock_t * rwlock, + const struct timespec *abstime) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = + pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0) + { + return result; + } + + if (++rwl->nSharedAccessCount == INT_MAX) + { + if ((result = + pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted), + abstime)) != 0) + { + if (result == ETIMEDOUT) + { + ++rwl->nCompletedSharedAccessCount; + } + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + } + + return (pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))); +} diff --git a/libs/pthreads/src/pthread_rwlock_timedwrlock.c b/libs/pthreads/src/pthread_rwlock_timedwrlock.c new file mode 100644 index 0000000000..8c111bbb1b --- /dev/null +++ b/libs/pthreads/src/pthread_rwlock_timedwrlock.c @@ -0,0 +1,139 @@ +/* + * pthread_rwlock_timedwrlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_timedwrlock (pthread_rwlock_t * rwlock, + const struct timespec *abstime) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = + pthread_mutex_timedlock (&(rwl->mtxExclusiveAccess), abstime)) != 0) + { + return result; + } + + if ((result = + pthread_mutex_timedlock (&(rwl->mtxSharedAccessCompleted), + abstime)) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + if (rwl->nExclusiveAccessCount == 0) + { + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } + + if (rwl->nSharedAccessCount > 0) + { + rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; + + /* + * This routine may be a cancelation point + * according to POSIX 1003.1j section 18.1.2. + */ +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth(0) +#endif + pthread_cleanup_push (ptw32_rwlock_cancelwrwait, (void *) rwl); + + do + { + result = + pthread_cond_timedwait (&(rwl->cndSharedAccessCompleted), + &(rwl->mtxSharedAccessCompleted), + abstime); + } + while (result == 0 && rwl->nCompletedSharedAccessCount < 0); + + pthread_cleanup_pop ((result != 0) ? 1 : 0); +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth() +#endif + + if (result == 0) + { + rwl->nSharedAccessCount = 0; + } + } + } + + if (result == 0) + { + rwl->nExclusiveAccessCount++; + } + + return result; +} diff --git a/libs/pthreads/src/pthread_rwlock_tryrdlock.c b/libs/pthreads/src/pthread_rwlock_tryrdlock.c new file mode 100644 index 0000000000..0fc5458579 --- /dev/null +++ b/libs/pthreads/src/pthread_rwlock_tryrdlock.c @@ -0,0 +1,102 @@ +/* + * pthread_rwlock_tryrdlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_tryrdlock (pthread_rwlock_t * rwlock) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if (++rwl->nSharedAccessCount == INT_MAX) + { + if ((result = + pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + } + + return (pthread_mutex_unlock (&rwl->mtxExclusiveAccess)); +} diff --git a/libs/pthreads/src/pthread_rwlock_trywrlock.c b/libs/pthreads/src/pthread_rwlock_trywrlock.c new file mode 100644 index 0000000000..9997c5d7fb --- /dev/null +++ b/libs/pthreads/src/pthread_rwlock_trywrlock.c @@ -0,0 +1,122 @@ +/* + * pthread_rwlock_trywrlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_trywrlock (pthread_rwlock_t * rwlock) +{ + int result, result1; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_trylock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if ((result = + pthread_mutex_trylock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return ((result1 != 0) ? result1 : result); + } + + if (rwl->nExclusiveAccessCount == 0) + { + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } + + if (rwl->nSharedAccessCount > 0) + { + if ((result = + pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + if ((result = + pthread_mutex_unlock (&(rwl->mtxExclusiveAccess))) == 0) + { + result = EBUSY; + } + } + else + { + rwl->nExclusiveAccessCount = 1; + } + } + else + { + result = EBUSY; + } + + return result; +} diff --git a/libs/pthreads/src/pthread_rwlock_unlock.c b/libs/pthreads/src/pthread_rwlock_unlock.c new file mode 100644 index 0000000000..d48d18705b --- /dev/null +++ b/libs/pthreads/src/pthread_rwlock_unlock.c @@ -0,0 +1,93 @@ +/* + * pthread_rwlock_unlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_unlock (pthread_rwlock_t * rwlock) +{ + int result, result1; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return (EINVAL); + } + + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + /* + * Assume any race condition here is harmless. + */ + return 0; + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if (rwl->nExclusiveAccessCount == 0) + { + if ((result = + pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + return result; + } + + if (++rwl->nCompletedSharedAccessCount == 0) + { + result = pthread_cond_signal (&(rwl->cndSharedAccessCompleted)); + } + + result1 = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); + } + else + { + rwl->nExclusiveAccessCount--; + + result = pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); + result1 = pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + + } + + return ((result != 0) ? result : result1); +} diff --git a/libs/pthreads/src/pthread_rwlock_wrlock.c b/libs/pthreads/src/pthread_rwlock_wrlock.c new file mode 100644 index 0000000000..e8b4fbb303 --- /dev/null +++ b/libs/pthreads/src/pthread_rwlock_wrlock.c @@ -0,0 +1,133 @@ +/* + * pthread_rwlock_wrlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlock_wrlock (pthread_rwlock_t * rwlock) +{ + int result; + pthread_rwlock_t rwl; + + if (rwlock == NULL || *rwlock == NULL) + { + return EINVAL; + } + + /* + * We do a quick check to see if we need to do more work + * to initialise a static rwlock. We check + * again inside the guarded section of ptw32_rwlock_check_need_init() + * to avoid race conditions. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = ptw32_rwlock_check_need_init (rwlock); + + if (result != 0 && result != EBUSY) + { + return result; + } + } + + rwl = *rwlock; + + if (rwl->nMagic != PTW32_RWLOCK_MAGIC) + { + return EINVAL; + } + + if ((result = pthread_mutex_lock (&(rwl->mtxExclusiveAccess))) != 0) + { + return result; + } + + if ((result = pthread_mutex_lock (&(rwl->mtxSharedAccessCompleted))) != 0) + { + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); + return result; + } + + if (rwl->nExclusiveAccessCount == 0) + { + if (rwl->nCompletedSharedAccessCount > 0) + { + rwl->nSharedAccessCount -= rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + } + + if (rwl->nSharedAccessCount > 0) + { + rwl->nCompletedSharedAccessCount = -rwl->nSharedAccessCount; + + /* + * This routine may be a cancelation point + * according to POSIX 1003.1j section 18.1.2. + */ +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth(0) +#endif + pthread_cleanup_push (ptw32_rwlock_cancelwrwait, (void *) rwl); + + do + { + result = pthread_cond_wait (&(rwl->cndSharedAccessCompleted), + &(rwl->mtxSharedAccessCompleted)); + } + while (result == 0 && rwl->nCompletedSharedAccessCount < 0); + + pthread_cleanup_pop ((result != 0) ? 1 : 0); +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth() +#endif + + if (result == 0) + { + rwl->nSharedAccessCount = 0; + } + } + } + + if (result == 0) + { + rwl->nExclusiveAccessCount++; + } + + return result; +} diff --git a/libs/pthreads/src/pthread_rwlockattr_destroy.c b/libs/pthreads/src/pthread_rwlockattr_destroy.c new file mode 100644 index 0000000000..868e727d30 --- /dev/null +++ b/libs/pthreads/src/pthread_rwlockattr_destroy.c @@ -0,0 +1,84 @@ +/* + * pthread_rwlockattr_destroy.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Destroys a rwlock attributes object. The object can + * no longer be used. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_rwlockattr_t + * + * + * DESCRIPTION + * Destroys a rwlock attributes object. The object can + * no longer be used. + * + * NOTES: + * 1) Does not affect rwlockss created using 'attr' + * + * RESULTS + * 0 successfully released attr, + * EINVAL 'attr' is invalid. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + + if (attr == NULL || *attr == NULL) + { + result = EINVAL; + } + else + { + pthread_rwlockattr_t rwa = *attr; + + *attr = NULL; + free (rwa); + } + + return (result); +} /* pthread_rwlockattr_destroy */ diff --git a/libs/pthreads/src/pthread_rwlockattr_getpshared.c b/libs/pthreads/src/pthread_rwlockattr_getpshared.c new file mode 100644 index 0000000000..eeace207f2 --- /dev/null +++ b/libs/pthreads/src/pthread_rwlockattr_getpshared.c @@ -0,0 +1,97 @@ +/* + * pthread_rwlockattr_getpshared.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, + int *pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Determine whether rwlocks created with 'attr' can be + * shared between processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_rwlockattr_t + * + * pshared + * will be set to one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * + * DESCRIPTION + * Rwlocks creatd with 'attr' can be shared between + * processes if pthread_rwlock_t variable is allocated + * in memory shared by these processes. + * NOTES: + * 1) pshared rwlocks MUST be allocated in shared + * memory. + * 2) The following macro is defined if shared rwlocks + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully retrieved attribute, + * EINVAL 'attr' is invalid, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && (pshared != NULL)) + { + *pshared = (*attr)->pshared; + result = 0; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_rwlockattr_getpshared */ diff --git a/libs/pthreads/src/pthread_rwlockattr_init.c b/libs/pthreads/src/pthread_rwlockattr_init.c new file mode 100644 index 0000000000..a2d2b945f4 --- /dev/null +++ b/libs/pthreads/src/pthread_rwlockattr_init.c @@ -0,0 +1,83 @@ +/* + * pthread_rwlockattr_init.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlockattr_init (pthread_rwlockattr_t * attr) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Initializes a rwlock attributes object with default + * attributes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_rwlockattr_t + * + * + * DESCRIPTION + * Initializes a rwlock attributes object with default + * attributes. + * + * RESULTS + * 0 successfully initialized attr, + * ENOMEM insufficient memory for attr. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_rwlockattr_t rwa; + + rwa = (pthread_rwlockattr_t) calloc (1, sizeof (*rwa)); + + if (rwa == NULL) + { + result = ENOMEM; + } + else + { + rwa->pshared = PTHREAD_PROCESS_PRIVATE; + } + + *attr = rwa; + + return (result); +} /* pthread_rwlockattr_init */ diff --git a/libs/pthreads/src/pthread_rwlockattr_setpshared.c b/libs/pthreads/src/pthread_rwlockattr_setpshared.c new file mode 100644 index 0000000000..a83dd70a4b --- /dev/null +++ b/libs/pthreads/src/pthread_rwlockattr_setpshared.c @@ -0,0 +1,120 @@ +/* + * pthread_rwlockattr_setpshared.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include + +#include "pthread.h" +#include "implement.h" + +int +pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, int pshared) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Rwlocks created with 'attr' can be shared between + * processes if pthread_rwlock_t variable is allocated + * in memory shared by these processes. + * + * PARAMETERS + * attr + * pointer to an instance of pthread_rwlockattr_t + * + * pshared + * must be one of: + * + * PTHREAD_PROCESS_SHARED + * May be shared if in shared memory + * + * PTHREAD_PROCESS_PRIVATE + * Cannot be shared. + * + * DESCRIPTION + * Rwlocks creatd with 'attr' can be shared between + * processes if pthread_rwlock_t variable is allocated + * in memory shared by these processes. + * + * NOTES: + * 1) pshared rwlocks MUST be allocated in shared + * memory. + * + * 2) The following macro is defined if shared rwlocks + * are supported: + * _POSIX_THREAD_PROCESS_SHARED + * + * RESULTS + * 0 successfully set attribute, + * EINVAL 'attr' or pshared is invalid, + * ENOSYS PTHREAD_PROCESS_SHARED not supported, + * + * ------------------------------------------------------ + */ +{ + int result; + + if ((attr != NULL && *attr != NULL) && + ((pshared == PTHREAD_PROCESS_SHARED) || + (pshared == PTHREAD_PROCESS_PRIVATE))) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + +#if !defined( _POSIX_THREAD_PROCESS_SHARED ) + + result = ENOSYS; + pshared = PTHREAD_PROCESS_PRIVATE; + +#else + + result = 0; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + else + { + result = 0; + } + + (*attr)->pshared = pshared; + } + else + { + result = EINVAL; + } + + return (result); + +} /* pthread_rwlockattr_setpshared */ diff --git a/libs/pthreads/src/pthread_self.c b/libs/pthreads/src/pthread_self.c new file mode 100644 index 0000000000..9a1765f82e --- /dev/null +++ b/libs/pthreads/src/pthread_self.c @@ -0,0 +1,141 @@ +/* + * pthread_self.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +pthread_t +pthread_self (void) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function returns a reference to the current running + * thread. + * + * PARAMETERS + * N/A + * + * + * DESCRIPTION + * This function returns a reference to the current running + * thread. + * + * RESULTS + * pthread_t reference to the current thread + * + * ------------------------------------------------------ + */ +{ + pthread_t self; + pthread_t nil = {NULL, 0}; + ptw32_thread_t * sp; + +#if defined(_UWIN) + if (!ptw32_selfThreadKey) + return nil; +#endif + + sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + + if (sp != NULL) + { + self = sp->ptHandle; + } + else + { + /* + * Need to create an implicit 'self' for the currently + * executing thread. + */ + self = ptw32_new (); + sp = (ptw32_thread_t *) self.p; + + if (sp != NULL) + { + /* + * This is a non-POSIX thread which has chosen to call + * a POSIX threads function for some reason. We assume that + * it isn't joinable, but we do assume that it's + * (deferred) cancelable. + */ + sp->implicit = 1; + sp->detachState = PTHREAD_CREATE_DETACHED; + sp->thread = GetCurrentThreadId (); + +#if defined(NEED_DUPLICATEHANDLE) + /* + * DuplicateHandle does not exist on WinCE. + * + * NOTE: + * GetCurrentThread only returns a pseudo-handle + * which is only valid in the current thread context. + * Therefore, you should not pass the handle to + * other threads for whatever purpose. + */ + sp->threadH = GetCurrentThread (); +#else + if (!DuplicateHandle (GetCurrentProcess (), + GetCurrentThread (), + GetCurrentProcess (), + &sp->threadH, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + /* + * Should not do this, but we have no alternative if + * we can't get a Win32 thread handle. + * Thread structs are never freed. + */ + ptw32_threadReusePush (self); + /* + * As this is a win32 thread calling us and we have failed, + * return a value that makes sense to win32. + */ + return nil; + } +#endif + + /* + * No need to explicitly serialise access to sched_priority + * because the new handle is not yet public. + */ + sp->sched_priority = GetThreadPriority (sp->threadH); + pthread_setspecific (ptw32_selfThreadKey, (void *) sp); + } + } + + return (self); + +} /* pthread_self */ diff --git a/libs/pthreads/src/pthread_setcancelstate.c b/libs/pthreads/src/pthread_setcancelstate.c new file mode 100644 index 0000000000..bbcd624af8 --- /dev/null +++ b/libs/pthreads/src/pthread_setcancelstate.c @@ -0,0 +1,125 @@ +/* + * pthread_setcancelstate.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_setcancelstate (int state, int *oldstate) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function atomically sets the calling thread's + * cancelability state to 'state' and returns the previous + * cancelability state at the location referenced by + * 'oldstate' + * + * PARAMETERS + * state, + * oldstate + * PTHREAD_CANCEL_ENABLE + * cancellation is enabled, + * + * PTHREAD_CANCEL_DISABLE + * cancellation is disabled + * + * + * DESCRIPTION + * This function atomically sets the calling thread's + * cancelability state to 'state' and returns the previous + * cancelability state at the location referenced by + * 'oldstate'. + * + * NOTES: + * 1) Use to disable cancellation around 'atomic' code that + * includes cancellation points + * + * COMPATIBILITY ADDITIONS + * If 'oldstate' is NULL then the previous state is not returned + * but the function still succeeds. (Solaris) + * + * RESULTS + * 0 successfully set cancelability type, + * EINVAL 'state' is invalid + * + * ------------------------------------------------------ + */ +{ + ptw32_mcs_local_node_t stateLock; + int result = 0; + pthread_t self = pthread_self (); + ptw32_thread_t * sp = (ptw32_thread_t *) self.p; + + if (sp == NULL + || (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE)) + { + return EINVAL; + } + + /* + * Lock for async-cancel safety. + */ + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); + + if (oldstate != NULL) + { + *oldstate = sp->cancelState; + } + + sp->cancelState = state; + + /* + * Check if there is a pending asynchronous cancel + */ + if (state == PTHREAD_CANCEL_ENABLE + && sp->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS + && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + ResetEvent (sp->cancelEvent); + ptw32_mcs_lock_release (&stateLock); + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ + } + + ptw32_mcs_lock_release (&stateLock); + + return (result); + +} /* pthread_setcancelstate */ diff --git a/libs/pthreads/src/pthread_setcanceltype.c b/libs/pthreads/src/pthread_setcanceltype.c new file mode 100644 index 0000000000..72b0af5bbc --- /dev/null +++ b/libs/pthreads/src/pthread_setcanceltype.c @@ -0,0 +1,126 @@ +/* + * pthread_setcanceltype.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_setcanceltype (int type, int *oldtype) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function atomically sets the calling thread's + * cancelability type to 'type' and returns the previous + * cancelability type at the location referenced by + * 'oldtype' + * + * PARAMETERS + * type, + * oldtype + * PTHREAD_CANCEL_DEFERRED + * only deferred cancelation is allowed, + * + * PTHREAD_CANCEL_ASYNCHRONOUS + * Asynchronous cancellation is allowed + * + * + * DESCRIPTION + * This function atomically sets the calling thread's + * cancelability type to 'type' and returns the previous + * cancelability type at the location referenced by + * 'oldtype' + * + * NOTES: + * 1) Use with caution; most code is not safe for use + * with asynchronous cancelability. + * + * COMPATIBILITY ADDITIONS + * If 'oldtype' is NULL then the previous type is not returned + * but the function still succeeds. (Solaris) + * + * RESULTS + * 0 successfully set cancelability type, + * EINVAL 'type' is invalid + * + * ------------------------------------------------------ + */ +{ + ptw32_mcs_local_node_t stateLock; + int result = 0; + pthread_t self = pthread_self (); + ptw32_thread_t * sp = (ptw32_thread_t *) self.p; + + if (sp == NULL + || (type != PTHREAD_CANCEL_DEFERRED + && type != PTHREAD_CANCEL_ASYNCHRONOUS)) + { + return EINVAL; + } + + /* + * Lock for async-cancel safety. + */ + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); + + if (oldtype != NULL) + { + *oldtype = sp->cancelType; + } + + sp->cancelType = type; + + /* + * Check if there is a pending asynchronous cancel + */ + if (sp->cancelState == PTHREAD_CANCEL_ENABLE + && type == PTHREAD_CANCEL_ASYNCHRONOUS + && WaitForSingleObject (sp->cancelEvent, 0) == WAIT_OBJECT_0) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + ResetEvent (sp->cancelEvent); + ptw32_mcs_lock_release (&stateLock); + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ + } + + ptw32_mcs_lock_release (&stateLock); + + return (result); + +} /* pthread_setcanceltype */ diff --git a/libs/pthreads/src/pthread_setconcurrency.c b/libs/pthreads/src/pthread_setconcurrency.c new file mode 100644 index 0000000000..f62346f8e5 --- /dev/null +++ b/libs/pthreads/src/pthread_setconcurrency.c @@ -0,0 +1,53 @@ +/* + * pthread_setconcurrency.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_setconcurrency (int level) +{ + if (level < 0) + { + return EINVAL; + } + else + { + ptw32_concurrency = level; + return 0; + } +} diff --git a/libs/pthreads/src/pthread_setschedparam.c b/libs/pthreads/src/pthread_setschedparam.c new file mode 100644 index 0000000000..b762753cdd --- /dev/null +++ b/libs/pthreads/src/pthread_setschedparam.c @@ -0,0 +1,123 @@ +/* + * sched_setschedparam.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +pthread_setschedparam (pthread_t thread, int policy, + const struct sched_param *param) +{ + int result; + + /* Validate the thread id. */ + result = pthread_kill (thread, 0); + if (0 != result) + { + return result; + } + + /* Validate the scheduling policy. */ + if (policy < SCHED_MIN || policy > SCHED_MAX) + { + return EINVAL; + } + + /* Ensure the policy is SCHED_OTHER. */ + if (policy != SCHED_OTHER) + { + return ENOTSUP; + } + + return (ptw32_setthreadpriority (thread, policy, param->sched_priority)); +} + + +int +ptw32_setthreadpriority (pthread_t thread, int policy, int priority) +{ + int prio; + ptw32_mcs_local_node_t threadLock; + int result = 0; + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + + prio = priority; + + /* Validate priority level. */ + if (prio < sched_get_priority_min (policy) || + prio > sched_get_priority_max (policy)) + { + return EINVAL; + } + +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) +/* WinCE */ +#else +/* Everything else */ + + if (THREAD_PRIORITY_IDLE < prio && THREAD_PRIORITY_LOWEST > prio) + { + prio = THREAD_PRIORITY_LOWEST; + } + else if (THREAD_PRIORITY_TIME_CRITICAL > prio + && THREAD_PRIORITY_HIGHEST < prio) + { + prio = THREAD_PRIORITY_HIGHEST; + } + +#endif + + ptw32_mcs_lock_acquire (&tp->threadLock, &threadLock); + + /* If this fails, the current priority is unchanged. */ + if (0 == SetThreadPriority (tp->threadH, prio)) + { + result = EINVAL; + } + else + { + /* + * Must record the thread's sched_priority as given, + * not as finally adjusted. + */ + tp->sched_priority = priority; + } + + ptw32_mcs_lock_release (&threadLock); + + return result; +} diff --git a/libs/pthreads/src/pthread_setspecific.c b/libs/pthreads/src/pthread_setspecific.c new file mode 100644 index 0000000000..0f29e704ab --- /dev/null +++ b/libs/pthreads/src/pthread_setspecific.c @@ -0,0 +1,167 @@ +/* + * pthread_setspecific.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_setspecific (pthread_key_t key, const void *value) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function sets the value of the thread specific + * key in the calling thread. + * + * PARAMETERS + * key + * an instance of pthread_key_t + * value + * the value to set key to + * + * + * DESCRIPTION + * This function sets the value of the thread specific + * key in the calling thread. + * + * RESULTS + * 0 successfully set value + * EAGAIN could not set value + * ENOENT SERIOUS!! + * + * ------------------------------------------------------ + */ +{ + pthread_t self; + int result = 0; + + if (key != ptw32_selfThreadKey) + { + /* + * Using pthread_self will implicitly create + * an instance of pthread_t for the current + * thread if one wasn't explicitly created + */ + self = pthread_self (); + if (self.p == NULL) + { + return ENOENT; + } + } + else + { + /* + * Resolve catch-22 of registering thread with selfThread + * key + */ + ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + + if (sp == NULL) + { + if (value == NULL) + { + return ENOENT; + } + self = *((pthread_t *) value); + } + else + { + self = sp->ptHandle; + } + } + + result = 0; + + if (key != NULL) + { + if (self.p != NULL && key->destructor != NULL && value != NULL) + { + ptw32_mcs_local_node_t keyLock; + ptw32_mcs_local_node_t threadLock; + ptw32_thread_t * sp = (ptw32_thread_t *) self.p; + /* + * Only require associations if we have to + * call user destroy routine. + * Don't need to locate an existing association + * when setting data to NULL for WIN32 since the + * data is stored with the operating system; not + * on the association; setting assoc to NULL short + * circuits the search. + */ + ThreadKeyAssoc *assoc; + + ptw32_mcs_lock_acquire(&(key->keyLock), &keyLock); + ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock); + + assoc = (ThreadKeyAssoc *) sp->keys; + /* + * Locate existing association + */ + while (assoc != NULL) + { + if (assoc->key == key) + { + /* + * Association already exists + */ + break; + } + assoc = assoc->nextKey; + } + + /* + * create an association if not found + */ + if (assoc == NULL) + { + result = ptw32_tkAssocCreate (sp, key); + } + + ptw32_mcs_lock_release(&threadLock); + ptw32_mcs_lock_release(&keyLock); + } + + if (result == 0) + { + if (!TlsSetValue (key->key, (LPVOID) value)) + { + result = EAGAIN; + } + } + } + + return (result); +} /* pthread_setspecific */ diff --git a/libs/pthreads/src/pthread_spin_destroy.c b/libs/pthreads/src/pthread_spin_destroy.c new file mode 100644 index 0000000000..786c4e34cd --- /dev/null +++ b/libs/pthreads/src/pthread_spin_destroy.c @@ -0,0 +1,111 @@ +/* + * pthread_spin_destroy.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_destroy (pthread_spinlock_t * lock) +{ + register pthread_spinlock_t s; + int result = 0; + + if (lock == NULL || *lock == NULL) + { + return EINVAL; + } + + if ((s = *lock) != PTHREAD_SPINLOCK_INITIALIZER) + { + if (s->interlock == PTW32_SPIN_USE_MUTEX) + { + result = pthread_mutex_destroy (&(s->u.mutex)); + } + else if ((PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED != + PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG ((PTW32_INTERLOCKED_LONGPTR) &s->interlock, + (PTW32_INTERLOCKED_LONG) PTW32_SPIN_INVALID, + (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED)) + { + result = EINVAL; + } + + if (0 == result) + { + /* + * We are relying on the application to ensure that all other threads + * have finished with the spinlock before destroying it. + */ + *lock = NULL; + (void) free (s); + } + } + else + { + /* + * See notes in ptw32_spinlock_check_need_init() above also. + */ + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire(&ptw32_spinlock_test_init_lock, &node); + + /* + * Check again. + */ + if (*lock == PTHREAD_SPINLOCK_INITIALIZER) + { + /* + * This is all we need to do to destroy a statically + * initialised spinlock that has not yet been used (initialised). + * If we get to here, another thread + * waiting to initialise this mutex will get an EINVAL. + */ + *lock = NULL; + } + else + { + /* + * The spinlock has been initialised while we were waiting + * so assume it's in use. + */ + result = EBUSY; + } + + ptw32_mcs_lock_release(&node); + } + + return (result); +} diff --git a/libs/pthreads/src/pthread_spin_init.c b/libs/pthreads/src/pthread_spin_init.c new file mode 100644 index 0000000000..553af7eac8 --- /dev/null +++ b/libs/pthreads/src/pthread_spin_init.c @@ -0,0 +1,123 @@ +/* + * pthread_spin_init.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_init (pthread_spinlock_t * lock, int pshared) +{ + pthread_spinlock_t s; + int cpus = 0; + int result = 0; + + if (lock == NULL) + { + return EINVAL; + } + + if (0 != ptw32_getprocessors (&cpus)) + { + cpus = 1; + } + + if (cpus > 1) + { + if (pshared == PTHREAD_PROCESS_SHARED) + { + /* + * Creating spinlock that can be shared between + * processes. + */ +#if _POSIX_THREAD_PROCESS_SHARED >= 0 + + /* + * Not implemented yet. + */ + +#error ERROR [__FILE__, line __LINE__]: Process shared spin locks are not supported yet. + +#else + + return ENOSYS; + +#endif /* _POSIX_THREAD_PROCESS_SHARED */ + + } + } + + s = (pthread_spinlock_t) calloc (1, sizeof (*s)); + + if (s == NULL) + { + return ENOMEM; + } + + if (cpus > 1) + { + s->u.cpus = cpus; + s->interlock = PTW32_SPIN_UNLOCKED; + } + else + { + pthread_mutexattr_t ma; + result = pthread_mutexattr_init (&ma); + + if (0 == result) + { + ma->pshared = pshared; + result = pthread_mutex_init (&(s->u.mutex), &ma); + if (0 == result) + { + s->interlock = PTW32_SPIN_USE_MUTEX; + } + } + (void) pthread_mutexattr_destroy (&ma); + } + + if (0 == result) + { + *lock = s; + } + else + { + (void) free (s); + *lock = NULL; + } + + return (result); +} diff --git a/libs/pthreads/src/pthread_spin_lock.c b/libs/pthreads/src/pthread_spin_lock.c new file mode 100644 index 0000000000..b560e14891 --- /dev/null +++ b/libs/pthreads/src/pthread_spin_lock.c @@ -0,0 +1,80 @@ +/* + * pthread_spin_lock.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_lock (pthread_spinlock_t * lock) +{ + register pthread_spinlock_t s; + + if (NULL == lock || NULL == *lock) + { + return (EINVAL); + } + + if (*lock == PTHREAD_SPINLOCK_INITIALIZER) + { + int result; + + if ((result = ptw32_spinlock_check_need_init (lock)) != 0) + { + return (result); + } + } + + s = *lock; + + while ((PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED == + PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG ((PTW32_INTERLOCKED_LONGPTR) &s->interlock, + (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED, + (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED)) + { + } + + if (s->interlock == PTW32_SPIN_LOCKED) + { + return 0; + } + else if (s->interlock == PTW32_SPIN_USE_MUTEX) + { + return pthread_mutex_lock (&(s->u.mutex)); + } + + return EINVAL; +} diff --git a/libs/pthreads/src/pthread_spin_trylock.c b/libs/pthreads/src/pthread_spin_trylock.c new file mode 100644 index 0000000000..a6c65aff6a --- /dev/null +++ b/libs/pthreads/src/pthread_spin_trylock.c @@ -0,0 +1,77 @@ +/* + * pthread_spin_trylock.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_trylock (pthread_spinlock_t * lock) +{ + register pthread_spinlock_t s; + + if (NULL == lock || NULL == *lock) + { + return (EINVAL); + } + + if (*lock == PTHREAD_SPINLOCK_INITIALIZER) + { + int result; + + if ((result = ptw32_spinlock_check_need_init (lock)) != 0) + { + return (result); + } + } + + s = *lock; + + switch ((long) + PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG ((PTW32_INTERLOCKED_LONGPTR) &s->interlock, + (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED, + (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED)) + { + case PTW32_SPIN_UNLOCKED: + return 0; + case PTW32_SPIN_LOCKED: + return EBUSY; + case PTW32_SPIN_USE_MUTEX: + return pthread_mutex_trylock (&(s->u.mutex)); + } + + return EINVAL; +} diff --git a/libs/pthreads/src/pthread_spin_unlock.c b/libs/pthreads/src/pthread_spin_unlock.c new file mode 100644 index 0000000000..3a6932aef3 --- /dev/null +++ b/libs/pthreads/src/pthread_spin_unlock.c @@ -0,0 +1,71 @@ +/* + * pthread_spin_unlock.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +pthread_spin_unlock (pthread_spinlock_t * lock) +{ + register pthread_spinlock_t s; + + if (NULL == lock || NULL == *lock) + { + return (EINVAL); + } + + s = *lock; + + if (s == PTHREAD_SPINLOCK_INITIALIZER) + { + return EPERM; + } + + switch ((long) + PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG ((PTW32_INTERLOCKED_LONGPTR) &s->interlock, + (PTW32_INTERLOCKED_LONG) PTW32_SPIN_UNLOCKED, + (PTW32_INTERLOCKED_LONG) PTW32_SPIN_LOCKED)) + { + case PTW32_SPIN_LOCKED: + case PTW32_SPIN_UNLOCKED: + return 0; + case PTW32_SPIN_USE_MUTEX: + return pthread_mutex_unlock (&(s->u.mutex)); + } + + return EINVAL; +} diff --git a/libs/pthreads/src/pthread_testcancel.c b/libs/pthreads/src/pthread_testcancel.c new file mode 100644 index 0000000000..6658650000 --- /dev/null +++ b/libs/pthreads/src/pthread_testcancel.c @@ -0,0 +1,103 @@ +/* + * pthread_testcancel.c + * + * Description: + * POSIX thread functions related to thread cancellation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void +pthread_testcancel (void) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function creates a deferred cancellation point + * in the calling thread. The call has no effect if the + * current cancelability state is + * PTHREAD_CANCEL_DISABLE + * + * PARAMETERS + * N/A + * + * + * DESCRIPTION + * This function creates a deferred cancellation point + * in the calling thread. The call has no effect if the + * current cancelability state is + * PTHREAD_CANCEL_DISABLE + * + * NOTES: + * 1) Cancellation is asynchronous. Use pthread_join + * to wait for termination of thread if necessary + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + ptw32_mcs_local_node_t stateLock; + pthread_t self = pthread_self (); + ptw32_thread_t * sp = (ptw32_thread_t *) self.p; + + if (sp == NULL) + { + return; + } + + /* + * Pthread_cancel() will have set sp->state to PThreadStateCancelPending + * and set an event, so no need to enter kernel space if + * sp->state != PThreadStateCancelPending - that only slows us down. + */ + if (sp->state != PThreadStateCancelPending) + { + return; + } + + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); + + if (sp->cancelState != PTHREAD_CANCEL_DISABLE) + { + ResetEvent(sp->cancelEvent); + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + ptw32_mcs_lock_release (&stateLock); + ptw32_throw (PTW32_EPS_CANCEL); + /* Never returns here */ + } + + ptw32_mcs_lock_release (&stateLock); +} /* pthread_testcancel */ diff --git a/libs/pthreads/src/pthread_timechange_handler_np.c b/libs/pthreads/src/pthread_timechange_handler_np.c new file mode 100644 index 0000000000..0f97e74f14 --- /dev/null +++ b/libs/pthreads/src/pthread_timechange_handler_np.c @@ -0,0 +1,108 @@ +/* + * pthread_timechange_handler_np.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Notes on handling system time adjustments (especially negative ones). + * --------------------------------------------------------------------- + * + * This solution was suggested by Alexander Terekhov, but any errors + * in the implementation are mine - [Ross Johnson] + * + * 1) The problem: threads doing a timedwait on a CV may expect to timeout + * at a specific absolute time according to a system timer. If the + * system clock is adjusted backwards then those threads sleep longer than + * expected. Also, pthreads-win32 converts absolute times to intervals in + * order to make use of the underlying Win32, and so waiting threads may + * awake before their proper abstimes. + * + * 2) We aren't able to distinquish between threads on timed or untimed waits, + * so we wake them all at the time of the adjustment so that they can + * re-evaluate their conditions and re-compute their timeouts. + * + * 3) We rely on correctly written applications for this to work. Specifically, + * they must be able to deal properly with spurious wakeups. That is, + * they must re-test their condition upon wakeup and wait again if + * the condition is not satisfied. + */ + +void * +pthread_timechange_handler_np (void *arg) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * Broadcasts all CVs to force re-evaluation and + * new timeouts if required. + * + * PARAMETERS + * NONE + * + * + * DESCRIPTION + * Broadcasts all CVs to force re-evaluation and + * new timeouts if required. + * + * This routine may be passed directly to pthread_create() + * as a new thread in order to run asynchronously. + * + * + * RESULTS + * 0 successfully broadcast all CVs + * EAGAIN Not all CVs were broadcast + * + * ------------------------------------------------------ + */ +{ + int result = 0; + pthread_cond_t cv; + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire(&ptw32_cond_list_lock, &node); + + cv = ptw32_cond_list_head; + + while (cv != NULL && 0 == result) + { + result = pthread_cond_broadcast (&cv); + cv = cv->next; + } + + ptw32_mcs_lock_release(&node); + + return (void *) (size_t) (result != 0 ? EAGAIN : 0); +} diff --git a/libs/pthreads/src/pthread_win32_attach_detach_np.c b/libs/pthreads/src/pthread_win32_attach_detach_np.c new file mode 100644 index 0000000000..bfad450653 --- /dev/null +++ b/libs/pthreads/src/pthread_win32_attach_detach_np.c @@ -0,0 +1,256 @@ +/* + * pthread_win32_attach_detach_np.c + * + * Description: + * This translation unit implements non-portable thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +/* + * Handle to quserex.dll + */ +static HINSTANCE ptw32_h_quserex; + +BOOL +pthread_win32_process_attach_np () +{ + TCHAR QuserExDLLPathBuf[1024]; + BOOL result = TRUE; + + result = ptw32_processInitialize (); + +#if defined(_UWIN) + pthread_count++; +#endif + +#if defined(__GNUC__) + ptw32_features = 0; +#else + /* + * This is obsolete now. + */ + ptw32_features = PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE; +#endif + + /* + * Load QUSEREX.DLL and try to get address of QueueUserAPCEx. + * Because QUSEREX.DLL requires a driver to be installed we will + * assume the DLL is in the system directory. + * + * This should take care of any security issues. + */ +#if defined(__GNUC__) || _MSC_VER < 1400 + if(GetSystemDirectory(QuserExDLLPathBuf, sizeof(QuserExDLLPathBuf))) + { + (void) strncat(QuserExDLLPathBuf, + "\\QUSEREX.DLL", + sizeof(QuserExDLLPathBuf) - strlen(QuserExDLLPathBuf) - 1); + ptw32_h_quserex = LoadLibrary(QuserExDLLPathBuf); + } +#else + /* strncat is secure - this is just to avoid a warning */ + if(GetSystemDirectory(QuserExDLLPathBuf, sizeof(QuserExDLLPathBuf)) && + 0 == strncat_s(QuserExDLLPathBuf, sizeof(QuserExDLLPathBuf), "\\QUSEREX.DLL", 12)) + { + ptw32_h_quserex = LoadLibrary(QuserExDLLPathBuf); + } +#endif + + if (ptw32_h_quserex != NULL) + { + ptw32_register_cancelation = (DWORD (*)(PAPCFUNC, HANDLE, DWORD)) +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress (ptw32_h_quserex, + (const TCHAR *) TEXT ("QueueUserAPCEx")); +#else + GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx"); +#endif + } + + if (NULL == ptw32_register_cancelation) + { + ptw32_register_cancelation = ptw32_RegisterCancelation; + + if (ptw32_h_quserex != NULL) + { + (void) FreeLibrary (ptw32_h_quserex); + } + ptw32_h_quserex = 0; + } + else + { + /* Initialise QueueUserAPCEx */ + BOOL (*queue_user_apc_ex_init) (VOID); + + queue_user_apc_ex_init = (BOOL (*)(VOID)) +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress (ptw32_h_quserex, + (const TCHAR *) TEXT ("QueueUserAPCEx_Init")); +#else + GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Init"); +#endif + + if (queue_user_apc_ex_init == NULL || !queue_user_apc_ex_init ()) + { + ptw32_register_cancelation = ptw32_RegisterCancelation; + + (void) FreeLibrary (ptw32_h_quserex); + ptw32_h_quserex = 0; + } + } + + if (ptw32_h_quserex) + { + ptw32_features |= PTW32_ALERTABLE_ASYNC_CANCEL; + } + + return result; +} + + +BOOL +pthread_win32_process_detach_np () +{ + if (ptw32_processInitialized) + { + ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + + if (sp != NULL) + { + /* + * Detached threads have their resources automatically + * cleaned up upon exit (others must be 'joined'). + */ + if (sp->detachState == PTHREAD_CREATE_DETACHED) + { + ptw32_threadDestroy (sp->ptHandle); + TlsSetValue (ptw32_selfThreadKey->key, NULL); + } + } + + /* + * The DLL is being unmapped from the process's address space + */ + ptw32_processTerminate (); + + if (ptw32_h_quserex) + { + /* Close QueueUserAPCEx */ + BOOL (*queue_user_apc_ex_fini) (VOID); + + queue_user_apc_ex_fini = (BOOL (*)(VOID)) +#if defined(NEED_UNICODE_CONSTS) + GetProcAddress (ptw32_h_quserex, + (const TCHAR *) TEXT ("QueueUserAPCEx_Fini")); +#else + GetProcAddress (ptw32_h_quserex, (LPCSTR) "QueueUserAPCEx_Fini"); +#endif + + if (queue_user_apc_ex_fini != NULL) + { + (void) queue_user_apc_ex_fini (); + } + (void) FreeLibrary (ptw32_h_quserex); + } + } + + return TRUE; +} + +BOOL +pthread_win32_thread_attach_np () +{ + return TRUE; +} + +BOOL +pthread_win32_thread_detach_np () +{ + if (ptw32_processInitialized) + { + /* + * Don't use pthread_self() - to avoid creating an implicit POSIX thread handle + * unnecessarily. + */ + ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + + if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle. + { + ptw32_mcs_local_node_t stateLock; + ptw32_callUserDestroyRoutines (sp->ptHandle); + + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); + sp->state = PThreadStateLast; + /* + * If the thread is joinable at this point then it MUST be joined + * or detached explicitly by the application. + */ + ptw32_mcs_lock_release (&stateLock); + + /* + * Robust Mutexes + */ + while (sp->robustMxList != NULL) + { + pthread_mutex_t mx = sp->robustMxList->mx; + ptw32_robust_mutex_remove(&mx, sp); + (void) PTW32_INTERLOCKED_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR)&mx->robustNode->stateInconsistent, + (PTW32_INTERLOCKED_LONG)-1); + /* + * If there are no waiters then the next thread to block will + * sleep, wakeup immediately and then go back to sleep. + * See pthread_mutex_lock.c. + */ + SetEvent(mx->event); + } + + + if (sp->detachState == PTHREAD_CREATE_DETACHED) + { + ptw32_threadDestroy (sp->ptHandle); + + TlsSetValue (ptw32_selfThreadKey->key, NULL); + } + } + } + + return TRUE; +} + +BOOL +pthread_win32_test_features_np (int feature_mask) +{ + return ((ptw32_features & feature_mask) == feature_mask); +} diff --git a/libs/pthreads/src/ptw32_MCS_lock.c b/libs/pthreads/src/ptw32_MCS_lock.c new file mode 100644 index 0000000000..659cda60de --- /dev/null +++ b/libs/pthreads/src/ptw32_MCS_lock.c @@ -0,0 +1,278 @@ +/* + * ptw32_MCS_lock.c + * + * Description: + * This translation unit implements queue-based locks. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * About MCS locks: + * + * MCS locks are queue-based locks, where the queue nodes are local to the + * thread. The 'lock' is nothing more than a global pointer that points to + * the last node in the queue, or is NULL if the queue is empty. + * + * Originally designed for use as spin locks requiring no kernel resources + * for synchronisation or blocking, the implementation below has adapted + * the MCS spin lock for use as a general mutex that will suspend threads + * when there is lock contention. + * + * Because the queue nodes are thread-local, most of the memory read/write + * operations required to add or remove nodes from the queue do not trigger + * cache-coherence updates. + * + * Like 'named' mutexes, MCS locks consume system resources transiently - + * they are able to acquire and free resources automatically - but MCS + * locks do not require any unique 'name' to identify the lock to all + * threads using it. + * + * Usage of MCS locks: + * + * - you need a global ptw32_mcs_lock_t instance initialised to 0 or NULL. + * - you need a local thread-scope ptw32_mcs_local_node_t instance, which + * may serve several different locks but you need at least one node for + * every lock held concurrently by a thread. + * + * E.g.: + * + * ptw32_mcs_lock_t lock1 = 0; + * ptw32_mcs_lock_t lock2 = 0; + * + * void *mythread(void *arg) + * { + * ptw32_mcs_local_node_t node; + * + * ptw32_mcs_acquire (&lock1, &node); + * ptw32_mcs_lock_release (&node); + * + * ptw32_mcs_lock_acquire (&lock2, &node); + * ptw32_mcs_lock_release (&node); + * { + * ptw32_mcs_local_node_t nodex; + * + * ptw32_mcs_lock_acquire (&lock1, &node); + * ptw32_mcs_lock_acquire (&lock2, &nodex); + * + * ptw32_mcs_lock_release (&nodex); + * ptw32_mcs_lock_release (&node); + * } + * return (void *)0; + * } + */ + +#include "pthread.h" +#include "sched.h" +#include "implement.h" + +/* + * ptw32_mcs_flag_set -- notify another thread about an event. + * + * Set event if an event handle has been stored in the flag, and + * set flag to -1 otherwise. Note that -1 cannot be a valid handle value. + */ +INLINE void +ptw32_mcs_flag_set (HANDLE * flag) +{ + HANDLE e = (HANDLE)(PTW32_INTERLOCKED_SIZE)PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE( + (PTW32_INTERLOCKED_SIZEPTR)flag, + (PTW32_INTERLOCKED_SIZE)-1, + (PTW32_INTERLOCKED_SIZE)0); + if ((HANDLE)0 != e) + { + /* another thread has already stored an event handle in the flag */ + SetEvent(e); + } +} + +/* + * ptw32_mcs_flag_set -- wait for notification from another. + * + * Store an event handle in the flag and wait on it if the flag has not been + * set, and proceed without creating an event otherwise. + */ +INLINE void +ptw32_mcs_flag_wait (HANDLE * flag) +{ + if ((PTW32_INTERLOCKED_LONG)0 == + PTW32_INTERLOCKED_EXCHANGE_ADD_SIZE((PTW32_INTERLOCKED_SIZEPTR)flag, + (PTW32_INTERLOCKED_SIZE)0)) /* MBR fence */ + { + /* the flag is not set. create event. */ + + HANDLE e = CreateEvent(NULL, PTW32_FALSE, PTW32_FALSE, NULL); + + if ((PTW32_INTERLOCKED_SIZE)0 == PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE( + (PTW32_INTERLOCKED_SIZEPTR)flag, + (PTW32_INTERLOCKED_SIZE)e, + (PTW32_INTERLOCKED_SIZE)0)) + { + /* stored handle in the flag. wait on it now. */ + WaitForSingleObject(e, INFINITE); + } + + CloseHandle(e); + } +} + +/* + * ptw32_mcs_lock_acquire -- acquire an MCS lock. + * + * See: + * J. M. Mellor-Crummey and M. L. Scott. + * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors. + * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991. + */ +#if defined(PTW32_BUILD_INLINED) +INLINE +#endif /* PTW32_BUILD_INLINED */ +void +ptw32_mcs_lock_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node) +{ + ptw32_mcs_local_node_t *pred; + + node->lock = lock; + node->nextFlag = 0; + node->readyFlag = 0; + node->next = 0; /* initially, no successor */ + + /* queue for the lock */ + pred = (ptw32_mcs_local_node_t *)PTW32_INTERLOCKED_EXCHANGE_PTR((PTW32_INTERLOCKED_PVOID_PTR)lock, + (PTW32_INTERLOCKED_PVOID)node); + + if (0 != pred) + { + /* the lock was not free. link behind predecessor. */ + pred->next = node; + ptw32_mcs_flag_set(&pred->nextFlag); + ptw32_mcs_flag_wait(&node->readyFlag); + } +} + +/* + * ptw32_mcs_lock_release -- release an MCS lock. + * + * See: + * J. M. Mellor-Crummey and M. L. Scott. + * Algorithms for Scalable Synchronization on Shared-Memory Multiprocessors. + * ACM Transactions on Computer Systems, 9(1):21-65, Feb. 1991. + */ +#if defined(PTW32_BUILD_INLINED) +INLINE +#endif /* PTW32_BUILD_INLINED */ +void +ptw32_mcs_lock_release (ptw32_mcs_local_node_t * node) +{ + ptw32_mcs_lock_t *lock = node->lock; + ptw32_mcs_local_node_t *next = + (ptw32_mcs_local_node_t *) + PTW32_INTERLOCKED_EXCHANGE_ADD_SIZE((PTW32_INTERLOCKED_SIZEPTR)&node->next, (PTW32_INTERLOCKED_SIZE)0); /* MBR fence */ + + if (0 == next) + { + /* no known successor */ + + if (node == (ptw32_mcs_local_node_t *) + PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR((PTW32_INTERLOCKED_PVOID_PTR)lock, + (PTW32_INTERLOCKED_PVOID)0, + (PTW32_INTERLOCKED_PVOID)node)) + { + /* no successor, lock is free now */ + return; + } + + /* A successor has started enqueueing behind us so wait for them to link to us */ + ptw32_mcs_flag_wait(&node->nextFlag); + next = (ptw32_mcs_local_node_t *) + PTW32_INTERLOCKED_EXCHANGE_ADD_SIZE((PTW32_INTERLOCKED_SIZEPTR)&node->next, (PTW32_INTERLOCKED_SIZE)0); /* MBR fence */ + } + + /* pass the lock */ + ptw32_mcs_flag_set(&next->readyFlag); +} + +/* + * ptw32_mcs_lock_try_acquire + */ +#if defined(PTW32_BUILD_INLINED) +INLINE +#endif /* PTW32_BUILD_INLINED */ +int +ptw32_mcs_lock_try_acquire (ptw32_mcs_lock_t * lock, ptw32_mcs_local_node_t * node) +{ + node->lock = lock; + node->nextFlag = 0; + node->readyFlag = 0; + node->next = 0; /* initially, no successor */ + + return ((PTW32_INTERLOCKED_PVOID)PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR((PTW32_INTERLOCKED_PVOID_PTR)lock, + (PTW32_INTERLOCKED_PVOID)node, + (PTW32_INTERLOCKED_PVOID)0) + == (PTW32_INTERLOCKED_PVOID)0) ? 0 : EBUSY; +} + +/* + * ptw32_mcs_node_transfer -- move an MCS lock local node, usually from thread + * space to, for example, global space so that another thread can release + * the lock on behalf of the current lock owner. + * + * Example: used in pthread_barrier_wait where we want the last thread out of + * the barrier to release the lock owned by the last thread to enter the barrier + * (the one that releases all threads but not necessarily the last to leave). + * + * Should only be called by the thread that has the lock. + */ +#if defined(PTW32_BUILD_INLINED) +INLINE +#endif /* PTW32_BUILD_INLINED */ +void +ptw32_mcs_node_transfer (ptw32_mcs_local_node_t * new_node, ptw32_mcs_local_node_t * old_node) +{ + new_node->lock = old_node->lock; + new_node->nextFlag = 0; /* Not needed - used only in initial Acquire */ + new_node->readyFlag = 0; /* Not needed - we were waiting on this */ + new_node->next = 0; + + if ((ptw32_mcs_local_node_t *)PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR((PTW32_INTERLOCKED_PVOID_PTR)new_node->lock, + (PTW32_INTERLOCKED_PVOID)new_node, + (PTW32_INTERLOCKED_PVOID)old_node) + != old_node) + { + /* + * A successor has queued after us, so wait for them to link to us + */ + while (old_node->next == 0) + { + sched_yield(); + } + new_node->next = old_node->next; + } +} diff --git a/libs/pthreads/src/ptw32_OLL_lock.c b/libs/pthreads/src/ptw32_OLL_lock.c new file mode 100644 index 0000000000..789d0ad8c6 --- /dev/null +++ b/libs/pthreads/src/ptw32_OLL_lock.c @@ -0,0 +1,734 @@ +/* + * ptw32_OLL_lock.c + * + * Description: + * This translation unit implements extended reader/writer queue-based locks. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * About the OLL lock (Scalable Reader-Writer Lock): + * + * OLL locks are queue-based locks similar to the MCS queue lock, where the queue + * nodes are local to the thread but where reader threads can enter the critical + * section immediately without going through a central guard lock if there are + * already readers holding the lock. + * + * Covered by United States Patent Application 20100241774 (Oracle) + */ + +#include "pthread.h" +#include "sched.h" +#include "implement.h" + +/* + * C-SNZI support + */ +typedef union ptw32_oll_counter_t_ ptw32_oll_counter_t; +typedef struct ptw32_oll_snziRoot_t_ ptw32_oll_snziRoot_t; +typedef struct ptw32_oll_snziNode_t_ ptw32_oll_snziNode_t; +typedef union ptw32_oll_snziNodeOrRoot_t_ ptw32_oll_snziNodeOrRoot_t; +typedef struct ptw32_oll_queryResult_t_ ptw32_oll_queryResult_t; +typedef struct ptw32_oll_ticket_t_ ptw32_oll_ticket_t; +typedef struct ptw32_oll_csnzi_t_ ptw32_oll_csnzi_t; + +enum +{ + ptw32_archWidth = sizeof(size_t)*8, + ptw32_oll_countWidth = ptw32_archWidth-2 +}; + +#define PTW32_OLL_MAXREADERS (((size_t)2<<(ptw32_oll_countWidth-1))-1) + +union ptw32_oll_counter_t_ +{ + size_t word : ptw32_archWidth; + struct + { + /* + * This needs to be a single word + * + * ------------------------------------ + * | STATE | ROOT | COUNT (readers) | + * ------------------------------------ + * 63 / 31 62 / 30 61 / 29 .. 0 + */ + size_t count : ptw32_oll_countWidth; + size_t root : 1; /* ROOT or NODE */ + size_t state : 1; /* OPEN or CLOSED (root only) */ + } internal; +}; + +struct ptw32_oll_snziRoot_t_ +{ + /* + * "counter" must be at same offset in both + * ptw32_oll_snziNode_t and ptw32_oll_snziRoot_t + */ + ptw32_oll_counter_t counter; +}; + +enum +{ + ptw32_oll_snziRoot_open = 0, + ptw32_oll_snziRoot_closed = 1 +}; + +enum +{ + ptw32_oll_snzi_root = 0, + ptw32_oll_snzi_node = 1 +}; + +/* + * Some common SNZI root whole-word states that can be used to set or compare + * root words with a single operation. + */ +ptw32_oll_snziRoot_t ptw32_oll_snziRoot_openAndZero = {.counter.internal.count = 0, + .counter.internal.root = ptw32_oll_snzi_root, + .counter.internal.state = ptw32_oll_snziRoot_open}; +ptw32_oll_snziRoot_t ptw32_oll_snziRoot_closedAndZero = {.counter.internal.count = 0, + .counter.internal.root = ptw32_oll_snzi_root, + .counter.internal.state = ptw32_oll_snziRoot_closed}; + +struct ptw32_oll_queryResult_t_ +{ + BOOL nonZero; + BOOL open; +}; + +union ptw32_oll_snziNodeOrRoot_t_ +{ + ptw32_oll_snziRoot_t* rootPtr; + ptw32_oll_snziNode_t* nodePtr; +}; + +struct ptw32_oll_snziNode_t_ +{ + /* "counter" must be at same offset in both + * ptw32_oll_snziNode_t and ptw32_oll_snziRoot_t + */ + ptw32_oll_counter_t counter; + ptw32_oll_snziNodeOrRoot_t parentPtr; +}; + +struct ptw32_oll_ticket_t_ +{ + ptw32_oll_snziNodeOrRoot_t snziNodeOrRoot; +}; + +ptw32_oll_ticket_t ptw32_oll_ticket_null = {NULL}; + +struct ptw32_oll_csnzi_t_ +{ + ptw32_oll_snziRoot_t proxyRoot; + ptw32_oll_snziNode_t leafs[]; +}; + +/* + * FOLL lock support + */ + +typedef struct ptw32_foll_node_t_ ptw32_foll_node_t; +typedef struct ptw32_foll_local_t_ ptw32_foll_local_t; +typedef struct ptw32_foll_rwlock_t_ ptw32_foll_rwlock_t; + +enum +{ + ptw32_srwl_reader, + ptw32_srwl_writer +}; + +enum +{ + ptw32_srwl_free, + ptw32_srwl_in_use +}; + +struct ptw32_foll_node_t_ +{ + ptw32_foll_node_t* qNextPtr; + ptw32_oll_csnzi_t* csnziPtr; + ptw32_foll_node_t* nextPtr; + int kind; + int allocState; + BOOL spin; +}; + +struct ptw32_foll_local_t_ +{ + ptw32_foll_node_t* rNodePtr; // Default read node. Immutable + ptw32_foll_node_t* wNodePtr; // Write node. Immutable. + ptw32_foll_node_t* departFromPtr; // List node we last arrived at. + ptw32_oll_ticket_t ticket; // C-SNZI ticket +}; + +struct ptw32_foll_rwlock_t_ +{ + ptw32_foll_node_t* tailPtr; + ptw32_foll_node_t* rNodesPtr; // Head of reader node +}; + +/* + * ShouldArriveAtTree() returns true if: + * the compare_exchange in Arrive() fails too often under read access; or + * ?? + * Note that this is measured across all access to + * this lock, not just this attempt, so that highly + * read-contended locks will use C-SNZI. Lightly + * read-contended locks can reduce memory usage and some + * processing by using the root directly. + */ +BOOL +ptw32_oll_ShouldArriveAtTree() +{ + return PTW32_FALSE; +} + +size_t +ptw32_oll_GetLeafForThread() +{ + return 0; +} + +/* + * Only readers call ptw32_oll_Arrive() + * + * Checks whether the C-SNZI state is OPEN, and if so, + * increments the surplus of the C-SNZI by either directly + * arriving at the root node, or calling TreeArrive on one + * of the leaf nodes. Returns a ticket pointing to the node + * that was arrived at. If the state is CLOSED, makes no + * change and returns a ticket that contains no pointer. + */ +ptw32_oll_ticket_t +ptw32_oll_Arrive(ptw32_oll_csnzi_t* csnzi) +{ + for (;;) + { + ptw32_oll_ticket_t ticket; + ptw32_oll_snziRoot_t oldProxy = csnzi->proxyRoot; + if (oldProxy.counter.internal.state != ptw32_oll_snziRoot_open) + { + ticket.snziNodeOrRoot.rootPtr = (ptw32_oll_snziRoot_t*)NULL; + return ticket; + } + if (!ptw32_oll_ShouldArriveAtTree()) + { + ptw32_oll_snziRoot_t newProxy = oldProxy; + newProxy.counter.internal.count++; + if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE( + (PTW32_INTERLOCKED_SIZEPTR)&csnzi->proxyRoot.counter, + (PTW32_INTERLOCKED_SIZE)newProxy.counter.word, + (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word) + == (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word) + { + /* Exchange successful */ + ticket.snziNodeOrRoot.rootPtr = &csnzi->proxyRoot; + return ticket; + } + } + else + { + ptw32_oll_snziNode_t* leafPtr = &csnzi->leafs[ptw32_oll_GetLeafForThread()]; + ticket.snziNodeOrRoot.nodePtr = (ptw32_oll_TreeArrive(leafPtr) ? leafPtr : (ptw32_oll_snziNode_t*)NULL); + return ticket; + } + } +} + +/* + * Decrements the C-SNZI surplus. Returns false iff the + * resulting state is CLOSED and the surplus is zero. + * Ticket must have been returned by an arrival. Must have + * received this ticket from Arrive more times than Depart + * has been called with the ticket. (Thus, the surplus + * must be greater than zero.) + */ +BOOL +ptw32_oll_Depart(ptw32_oll_ticket_t ticket) +{ + return ptw32_oll_TreeDepart(ticket.snziNodeOrRoot); +} + +/* + * Increments the C-SNZI surplus and returns true if the + * C-SNZI is open or has a surplus. Calls TreeArrive + * recursively on the node’s parent if needed. + * Otherwise, returns false without making any changes. + */ +BOOL +ptw32_oll_TreeArrive(ptw32_oll_snziNodeOrRoot_t snziNodeOrRoot) +{ + if (snziNodeOrRoot.nodePtr->counter.internal.root != ptw32_oll_snzi_root) + { + /* Non-root node */ + ptw32_oll_counter_t newCounter, oldCounter; + BOOL arrivedAtParent = PTW32_FALSE; + do + { + oldCounter = snziNodeOrRoot.nodePtr->counter; + if (0 == oldCounter.internal.count && !arrivedAtParent) + { + if (ptw32_oll_TreeArrive(snziNodeOrRoot.nodePtr->parentPtr)) + arrivedAtParent = PTW32_TRUE; + else + return PTW32_FALSE; + } + newCounter = oldCounter; + newCounter.internal.count++; + } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE( + (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.nodePtr->counter, + (PTW32_INTERLOCKED_SIZE)newCounter.word, + (PTW32_INTERLOCKED_SIZE)oldCounter.word) + != (PTW32_INTERLOCKED_SIZE)oldCounter.word); + if (newCounter.internal.count != 0 && arrivedAtParent) + ptw32_oll_TreeDepart(snziNodeOrRoot.nodePtr->parentPtr); + return PTW32_TRUE; + } + else + { + /* Root node */ + ptw32_oll_snziRoot_t newRoot, oldRoot; + do + { + oldRoot = *(ptw32_oll_snziRoot_t*)snziNodeOrRoot.rootPtr; + if (oldRoot.counter.word == ptw32_oll_snziRoot_closedAndZero.counter.word) + return PTW32_FALSE; + newRoot = oldRoot; + newRoot.counter.internal.count++; + } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE( + (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.rootPtr->counter, + (PTW32_INTERLOCKED_SIZE)newRoot.counter.word, + (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word) + != (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word); + return PTW32_TRUE; + } +} + +/* + * Decrements the C-SNZI surplus, calling TreeDepart + * recursively on the node’s parent if needed. Returns + * false iff the resulting state of the C-SNZI is CLOSED + * and the surplus is zero. Otherwise, returns true. + */ +BOOL +ptw32_oll_TreeDepart(ptw32_oll_snziNodeOrRoot_t snziNodeOrRoot) +{ + if (snziNodeOrRoot.nodePtr->counter.internal.root != ptw32_oll_snzi_root) + { + /* Non-root node */ + ptw32_oll_counter_t newCounter, oldCounter; + do + { + newCounter = oldCounter = snziNodeOrRoot.nodePtr->counter; + newCounter.internal.count--; + } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE( + (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.nodePtr->counter, + (PTW32_INTERLOCKED_SIZE)newCounter.word, + (PTW32_INTERLOCKED_SIZE)oldCounter.word) + != (PTW32_INTERLOCKED_SIZE)oldCounter.word); + return (0 == newCounter.internal.count) + ? ptw32_oll_TreeDepart(snziNodeOrRoot.nodePtr->parentPtr) + : PTW32_TRUE; + } + else + { + /* Root node */ + ptw32_oll_snziRoot_t newRoot, oldRoot; + do + { + newRoot = oldRoot = *(ptw32_oll_snziRoot_t*)snziNodeOrRoot.rootPtr; + newRoot.counter.internal.count--; + } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE( + (PTW32_INTERLOCKED_SIZEPTR)&snziNodeOrRoot.rootPtr->counter, + (PTW32_INTERLOCKED_SIZE)newRoot.counter.word, + (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word) + != (PTW32_INTERLOCKED_SIZE)oldRoot.counter.word); + return (newRoot.counter.word != ptw32_oll_snziRoot_closedAndZero.counter.word); + } +} + +/* + * Opens a C-SNZI object. Requires C-SNZI state to be + * CLOSED and the surplus to be zero. + */ +void +ptw32_oll_Open(ptw32_oll_csnzi_t* csnziPtr) +{ + csnziPtr->proxyRoot = ptw32_oll_snziRoot_openAndZero; +} + +/* + * Opens a C-SNZI object while atomically performing count + * arrivals. Requires C-SNZI state to be CLOSED and + * the surplus to be zero. + */ +void +ptw32_oll_OpenWithArrivals(ptw32_oll_csnzi_t* csnziPtr, size_t count, BOOL close) +{ + csnziPtr->proxyRoot.counter.internal.count = count; + csnziPtr->proxyRoot.counter.internal.state = (close ? ptw32_oll_snziRoot_closed : ptw32_oll_snziRoot_open); +} + +/* + * Closes a C-SNZI object. Returns true iff the C-SNZI + * state changed from OPEN to CLOSED and the surplus is + * zero. + */ +BOOL +ptw32_oll_Close(ptw32_oll_csnzi_t* csnziPtr) +{ + ptw32_oll_snziRoot_t newProxy, oldProxy; + do + { + oldProxy = csnziPtr->proxyRoot; + if (oldProxy.counter.internal.state != ptw32_oll_snziRoot_open) + { + return PTW32_FALSE; + } + newProxy = oldProxy; + newProxy.counter.internal.state = ptw32_oll_snziRoot_closed; + } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE( + (PTW32_INTERLOCKED_SIZEPTR)&csnziPtr->proxyRoot.counter, + (PTW32_INTERLOCKED_SIZE)newProxy.counter.word, + (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word) + != (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word); + return (newProxy.counter.word == ptw32_oll_snziRoot_closedAndZero.counter.word); +} + +/* + * Closes a C-SNZI if its surplus is zero. Otherwise, does + * nothing. Returns true iff C-SNZI state changed from + * OPEN to CLOSED. + */ +BOOL +ptw32_oll_CloseIfEmpty(ptw32_oll_csnzi_t* csnziPtr) +{ + ptw32_oll_snziRoot_t newProxy, oldProxy; + do + { + oldProxy = csnziPtr->proxyRoot; + if (oldProxy.counter.word != ptw32_oll_snziRoot_openAndZero.counter.word) + { + return PTW32_FALSE; + } + newProxy = ptw32_oll_snziRoot_closedAndZero; + } while (PTW32_INTERLOCKED_COMPARE_EXCHANGE_SIZE( + (PTW32_INTERLOCKED_SIZEPTR)&csnziPtr->proxyRoot.counter, + (PTW32_INTERLOCKED_SIZE)newProxy.counter.word, + (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word) + != (PTW32_INTERLOCKED_SIZE)oldProxy.counter.word); + return PTW32_TRUE; +} + +/* + * Returns whether the C-SNZI has a nonzero surplus and + * whether the C-SNZI is open. + * "nonZero" doesn't appear to be used anywhere in the algorithms. + */ +ptw32_oll_queryResult_t +ptw32_oll_Query(ptw32_oll_csnzi_t* csnziPtr) +{ + ptw32_oll_queryResult_t query; + ptw32_oll_snziRoot_t proxy = csnziPtr->proxyRoot; + + query.nonZero = (proxy.counter.internal.count > 0); + query.open = (proxy.counter.internal.state == ptw32_oll_snziRoot_open); + return query; +} + +/* + * Returns whether the Arrive operation that returned + * the ticket succeeded. + */ +BOOL +ptw32_oll_Arrived(ptw32_oll_ticket_t t) +{ + return (t.snziNodeOrRoot.nodePtr != NULL); +} + +/* + * Constructs and returns a ticket that can be used to + * depart from the root node. + */ +ptw32_oll_ticket_t +ptw32_oll_DirectTicket(ptw32_oll_csnzi_t* csnziPtr) +{ + ptw32_oll_ticket_t ticket; + ticket.snziNodeOrRoot.rootPtr = &csnziPtr->proxyRoot; + return ticket; +} + +/* Scalable RW Locks */ + +typedef struct ptw32_srwl_rwlock_t_ ptw32_srwl_rwlock_t; +typedef struct ptw32_srwl_node_t_ ptw32_srwl_node_t; +typedef struct ptw32_srwl_local_t_ ptw32_srwl_local_t; + +enum +{ + ptw32_srwl_reader = 0, + ptw32_srwl_writer = 1 +}; + +enum +{ + ptw32_srwl_free = 0, + ptw32_srwl_in_use = 1 +}; + +struct ptw32_srwl_rwlock_t_ +{ + ptw32_srwl_node_t* tailPtr; + ptw32_srwl_node_t* readerNodePtr; +}; + +struct ptw32_srwl_node_t_ +{ + ptw32_srwl_node_t* qNextPtr; + ptw32_oll_csnzi_t* csnziPtr; + ptw32_srwl_node_t* nextReaderPtr; + int kind; /* ptw32_srwl_reader, ptw32_srwl_writer */ + int allocState; /* ptw32_srwl_free, ptw32_srwl_in_use */ + BOOL spin; +}; + +/* + * When a ptw32_srwl_local_t is instantiated the "kind" of each of + * rNode and wNode must be set as appropriate. This is the only + * time "kind" is set. + */ +struct ptw32_srwl_local_t_ +{ + ptw32_srwl_node_t* rNodePtr; + ptw32_srwl_node_t* wNodePtr; + ptw32_srwl_node_t* departFromPtr; + ptw32_oll_ticket_t ticket; +}; + +/* Allocates a new reader node. */ +ptw32_srwl_node_t* +ptw32_srwl_AllocReaderNode(ptw32_srwl_local_t* local) +{ + ptw32_srwl_node_t* currNodePtr = local->rNodePtr; + for (;;) + { + if (currNodePtr->allocState == ptw32_srwl_free) + { + if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_LONG( + (PTW32_INTERLOCKED_LONGPTR)&currNodePtr->allocState, + (PTW32_INTERLOCKED_LONG)ptw32_srwl_in_use, + (PTW32_INTERLOCKED_LONG)ptw32_srwl_free) + == (PTW32_INTERLOCKED_LONG)ptw32_srwl_in_use) + { + return currNodePtr; + } + } + currNodePtr = currNodePtr->next; + } +} + +/* + * Frees a reader node. Requires that its allocState + * is ptw32_srwl_in_use. + */ +void +ptw32_srwl_FreeReaderNode(ptw32_srwl_node_t* nodePtr) +{ + nodePtr->allocState := ptw32_srwl_free; +} + +void +ptw32_srwl_WriterLock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr) +{ + oldTailPtr = (ptw32_srwl_rwlock_t*)PTW32_INTERLOCKED_EXCHANGE_PTR( + (PTW32_INTERLOCKED_PVOID_PTR)&lockPtr->tailPtr, + (PTW32_INTERLOCKED_PVOID)localPtr->wNodePtr); + if (oldTailPtr != NULL) + { + localPtr->wNodePtr->spin := PTW32_TRUE; + oldTailPtr->qNextPtr = localPtr->wNodePtr; + if (oldTailPtr->kind == ptw32_srwl_writer) + { + while (localPtr->wNodePtr->spin); + } + else + { + /* Wait until node is properly recycled */ + while (ptw32_oll_Query(oldTailPtr->csnzi).open); + /* + * Close C-SNZI of previous reader node. + * If there are no readers to signal us, spin on + * previous node and free it before entering + * critical section. + */ + if (ptw32_oll_Close(oldTailPtr->csnzi)) + { + while (oldTailPtr->spin); + ptw32_srwl_FreeReaderNode(oldTailPtr); + } + else + { + while (localPtr->wNodePtr->spin); + } + } + } +} + +void +ptw32_srwl_WriterUnlock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr) +{ + if (localPtr->wNodePtr->qNextPtr == NULL) + { + if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR( + (PTW32_INTERLOCKED_PVOIDPTR)&lockPtr->tailPtr, + (PTW32_INTERLOCKED_PVOID)NULL, + (PTW32_INTERLOCKED_PVOID)localPtr->wNodePtr) + == (PTW32_INTERLOCKED_PVOID)NULL) + { + return; + } + else + { + while (localPtr->wNodePtr->qNextPtr == NULL); + } + } + /* Clean up */ + localPtr->wNodePtr->qNextPtr->spin = PTW32_FALSE; + localPtr->wNodePtr->qNextPtr = NULL; +} + +void +ptw32_srwl_ReaderLock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr) +{ + ptw32_srwl_node_t* rNodePtr = NULL; + for (;;) + { + ptw32_srwl_node_t* tailPtr = lockPtr->tailPtr; + /* If no nodes are in the queue */ + if (tailPtr == NULL) + { + if (rNodePtr == NULL) + { + rNodePtr = ptw32_srwl_AllocReaderNode(localPtr); + } + rNodePtr->spin = PTW32_FALSE; + if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR( + (PTW32_INTERLOCKED_PVOIDPTR)&lockPtr->tailPtr, + (PTW32_INTERLOCKED_PVOID)rNodePtr, + (PTW32_INTERLOCKED_PVOID)NULL) + == (PTW32_INTERLOCKED_PVOID)rNodePtr) + { + ptw32_oll_Open(rNodePtr->csnzi); + localPtr->ticket = ptw32_oll_Arrive(rNodePtr->csnzi); + if (ptw32_oll_Arrived(localPtr->ticket)) + { + localPtr->departFromPtr = rNodePtr; + return; + } + /* Avoid reusing inserted node */ + rNodePtr = NULL; + } + } + /* Otherwise, there is a node in the queue */ + else + { + /* Is last node a writer node? */ + if (tailPtr->kind == ptw32_srwl_writer) + { + if (rNodePtr == NULL) + { + rNodePtr = ptw32_srwl_AllocReaderNode(localPtr); + } + rNodePtr->spin = PTW32_TRUE; + if (PTW32_INTERLOCKED_COMPARE_EXCHANGE_PTR( + (PTW32_INTERLOCKED_PVOIDPTR)&lockPtr->tailPtr, + (PTW32_INTERLOCKED_PVOID)rNodePtr, + (PTW32_INTERLOCKED_PVOID)tailPtr) + == (PTW32_INTERLOCKED_PVOID)rNodePtr) + { + tailPtr->qNextPtr = rNodePtr; + localPtr->ticket = ptw32_oll_Arrive(rNodePtr->csnzi); + if (ptw32_oll_Arrived(localPtr->ticket)) + { + localPtr->departFromPtr = rNodePtr; + while (rNodePtr->spin); + return; + } + /* Avoid reusing inserted node */ + rNodePtr = NULL; + } + } + /* + * Otherwise, last node is a reader node. + * (tailPtr->kind == ptw32_srwl_reader) + */ + else + { + localPtr->ticket = ptw32_oll_Arrive(tailPtr->csnzi); + if (ptw32_oll_Arrived(localPtr->ticket)) + { + if (rNodePtr != NULL) + { + ptw32_srwl_FreeReaderNode(rNodePtr); + } + localPtr->departFromPtr = tailPtr; + while (tailPtr->spin); + return; + } + } + } + } +} + +void +ptw32_srwl_ReaderUnlock(ptw32_srwl_rwlock_t* lockPtr, ptw32_srwl_local_t* localPtr) +{ + if (ptw32_oll_Depart(localPtr->departFromPtr->csnzi, localPtr->ticket)) + { + return; + } + /* Clean up */ + localPtr->departFromPtr->qNextPtr->spin = PTW32_FALSE; + localPtr->departFromPtr->qNextPtr = NULL; + ptw32_srwl_FreeReaderNode(localPtr->departFromPtr); +} + + +#include + +int main() +{ + printf("%lx\n", PTW32_OLL_MAXREADERS); + return 0; +} + diff --git a/libs/pthreads/src/ptw32_callUserDestroyRoutines.c b/libs/pthreads/src/ptw32_callUserDestroyRoutines.c new file mode 100644 index 0000000000..f290f7ba54 --- /dev/null +++ b/libs/pthreads/src/ptw32_callUserDestroyRoutines.c @@ -0,0 +1,232 @@ +/* + * ptw32_callUserDestroyRoutines.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#if defined(__CLEANUP_CXX) +# if defined(_MSC_VER) +# include +# elif defined(__WATCOMC__) +# include +# include +# else +# if defined(__GNUC__) && __GNUC__ < 3 +# include +# else +# include + using + std::terminate; +# endif +# endif +#endif + +void +ptw32_callUserDestroyRoutines (pthread_t thread) + /* + * ------------------------------------------------------------------- + * DOCPRIVATE + * + * This the routine runs through all thread keys and calls + * the destroy routines on the user's data for the current thread. + * It simulates the behaviour of POSIX Threads. + * + * PARAMETERS + * thread + * an instance of pthread_t + * + * RETURNS + * N/A + * ------------------------------------------------------------------- + */ +{ + ThreadKeyAssoc * assoc; + + if (thread.p != NULL) + { + ptw32_mcs_local_node_t threadLock; + ptw32_mcs_local_node_t keyLock; + int assocsRemaining; + int iterations = 0; + ptw32_thread_t * sp = (ptw32_thread_t *) thread.p; + + /* + * Run through all Thread<-->Key associations + * for the current thread. + * + * Do this process at most PTHREAD_DESTRUCTOR_ITERATIONS times. + */ + do + { + assocsRemaining = 0; + iterations++; + + ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock); + /* + * The pointer to the next assoc is stored in the thread struct so that + * the assoc destructor in pthread_key_delete can adjust it + * if it deletes this assoc. This can happen if we fail to acquire + * both locks below, and are forced to release all of our locks, + * leaving open the opportunity for pthread_key_delete to get in + * before us. + */ + sp->nextAssoc = sp->keys; + ptw32_mcs_lock_release(&threadLock); + + for (;;) + { + void * value; + pthread_key_t k; + void (*destructor) (void *); + + /* + * First we need to serialise with pthread_key_delete by locking + * both assoc guards, but in the reverse order to our convention, + * so we must be careful to avoid deadlock. + */ + ptw32_mcs_lock_acquire(&(sp->threadLock), &threadLock); + + if ((assoc = (ThreadKeyAssoc *)sp->nextAssoc) == NULL) + { + /* Finished */ + ptw32_mcs_lock_release(&threadLock); + break; + } + else + { + /* + * assoc->key must be valid because assoc can't change or be + * removed from our chain while we hold at least one lock. If + * the assoc was on our key chain then the key has not been + * deleted yet. + * + * Now try to acquire the second lock without deadlocking. + * If we fail, we need to relinquish the first lock and the + * processor and then try to acquire them all again. + */ + if (ptw32_mcs_lock_try_acquire(&(assoc->key->keyLock), &keyLock) == EBUSY) + { + ptw32_mcs_lock_release(&threadLock); + Sleep(0); + /* + * Go around again. + * If pthread_key_delete has removed this assoc in the meantime, + * sp->nextAssoc will point to a new assoc. + */ + continue; + } + } + + /* We now hold both locks */ + + sp->nextAssoc = assoc->nextKey; + + /* + * Key still active; pthread_key_delete + * will block on these same mutexes before + * it can release actual key; therefore, + * key is valid and we can call the destroy + * routine; + */ + k = assoc->key; + destructor = k->destructor; + value = TlsGetValue(k->key); + TlsSetValue (k->key, NULL); + + // Every assoc->key exists and has a destructor + if (value != NULL && iterations <= PTHREAD_DESTRUCTOR_ITERATIONS) + { + /* + * Unlock both locks before the destructor runs. + * POSIX says pthread_key_delete can be run from destructors, + * and that probably includes with this key as target. + * pthread_setspecific can also be run from destructors and + * also needs to be able to access the assocs. + */ + ptw32_mcs_lock_release(&threadLock); + ptw32_mcs_lock_release(&keyLock); + + assocsRemaining++; + +#if defined(__cplusplus) + + try + { + /* + * Run the caller's cleanup routine. + */ + destructor (value); + } + catch (...) + { + /* + * A system unexpected exception has occurred + * running the user's destructor. + * We get control back within this block in case + * the application has set up it's own terminate + * handler. Since we are leaving the thread we + * should not get any internal pthreads + * exceptions. + */ + terminate (); + } + +#else /* __cplusplus */ + + /* + * Run the caller's cleanup routine. + */ + destructor (value); + +#endif /* __cplusplus */ + + } + else + { + /* + * Remove association from both the key and thread chains + * and reclaim it's memory resources. + */ + ptw32_tkAssocDestroy (assoc); + ptw32_mcs_lock_release(&threadLock); + ptw32_mcs_lock_release(&keyLock); + } + } + } + while (assocsRemaining); + } +} /* ptw32_callUserDestroyRoutines */ diff --git a/libs/pthreads/src/ptw32_calloc.c b/libs/pthreads/src/ptw32_calloc.c new file mode 100644 index 0000000000..e7b9e64fe6 --- /dev/null +++ b/libs/pthreads/src/ptw32_calloc.c @@ -0,0 +1,56 @@ +/* + * ptw32_calloc.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#if defined(NEED_CALLOC) +void * +ptw32_calloc (size_t n, size_t s) +{ + unsigned int m = n * s; + void *p; + + p = malloc (m); + if (p == NULL) + return NULL; + + memset (p, 0, m); + + return p; +} +#endif diff --git a/libs/pthreads/src/ptw32_cond_check_need_init.c b/libs/pthreads/src/ptw32_cond_check_need_init.c new file mode 100644 index 0000000000..ec3e8bbd69 --- /dev/null +++ b/libs/pthreads/src/ptw32_cond_check_need_init.c @@ -0,0 +1,78 @@ +/* + * ptw32_cond_check_need_init.c + * + * Description: + * This translation unit implements condition variables and their primitives. + * + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +INLINE int +ptw32_cond_check_need_init (pthread_cond_t * cond) +{ + int result = 0; + ptw32_mcs_local_node_t node; + + /* + * The following guarded test is specifically for statically + * initialised condition variables (via PTHREAD_OBJECT_INITIALIZER). + */ + ptw32_mcs_lock_acquire(&ptw32_cond_test_init_lock, &node); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section. + * If a static cv has been destroyed, the application can + * re-initialise it only by calling pthread_cond_init() + * explicitly. + */ + if (*cond == PTHREAD_COND_INITIALIZER) + { + result = pthread_cond_init (cond, NULL); + } + else if (*cond == NULL) + { + /* + * The cv has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + result = EINVAL; + } + + ptw32_mcs_lock_release(&node); + + return result; +} diff --git a/libs/pthreads/src/ptw32_getprocessors.c b/libs/pthreads/src/ptw32_getprocessors.c new file mode 100644 index 0000000000..e60c3143f9 --- /dev/null +++ b/libs/pthreads/src/ptw32_getprocessors.c @@ -0,0 +1,91 @@ +/* + * ptw32_getprocessors.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +/* + * ptw32_getprocessors() + * + * Get the number of CPUs available to the process. + * + * If the available number of CPUs is 1 then pthread_spin_lock() + * will block rather than spin if the lock is already owned. + * + * pthread_spin_init() calls this routine when initialising + * a spinlock. If the number of available processors changes + * (after a call to SetProcessAffinityMask()) then only + * newly initialised spinlocks will notice. + */ +int +ptw32_getprocessors (int *count) +{ + DWORD_PTR vProcessCPUs; + DWORD_PTR vSystemCPUs; + int result = 0; + +#if defined(NEED_PROCESS_AFFINITY_MASK) + + *count = 1; + +#else + + if (GetProcessAffinityMask (GetCurrentProcess (), + &vProcessCPUs, &vSystemCPUs)) + { + DWORD_PTR bit; + int CPUs = 0; + + for (bit = 1; bit != 0; bit <<= 1) + { + if (vProcessCPUs & bit) + { + CPUs++; + } + } + *count = CPUs; + } + else + { + result = EAGAIN; + } + +#endif + + return (result); +} diff --git a/libs/pthreads/src/ptw32_is_attr.c b/libs/pthreads/src/ptw32_is_attr.c new file mode 100644 index 0000000000..36395f81f0 --- /dev/null +++ b/libs/pthreads/src/ptw32_is_attr.c @@ -0,0 +1,47 @@ +/* + * ptw32_is_attr.c + * + * Description: + * This translation unit implements operations on thread attribute objects. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +int +ptw32_is_attr (const pthread_attr_t * attr) +{ + /* Return 0 if the attr object is valid, non-zero otherwise. */ + + return (attr == NULL || + *attr == NULL || (*attr)->valid != PTW32_ATTR_VALID); +} diff --git a/libs/pthreads/src/ptw32_mutex_check_need_init.c b/libs/pthreads/src/ptw32_mutex_check_need_init.c new file mode 100644 index 0000000000..897db3c68e --- /dev/null +++ b/libs/pthreads/src/ptw32_mutex_check_need_init.c @@ -0,0 +1,92 @@ +/* + * ptw32_mutex_check_need_init.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +static struct pthread_mutexattr_t_ ptw32_recursive_mutexattr_s = + {PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_RECURSIVE}; +static struct pthread_mutexattr_t_ ptw32_errorcheck_mutexattr_s = + {PTHREAD_PROCESS_PRIVATE, PTHREAD_MUTEX_ERRORCHECK}; +static pthread_mutexattr_t ptw32_recursive_mutexattr = &ptw32_recursive_mutexattr_s; +static pthread_mutexattr_t ptw32_errorcheck_mutexattr = &ptw32_errorcheck_mutexattr_s; + + +INLINE int +ptw32_mutex_check_need_init (pthread_mutex_t * mutex) +{ + register int result = 0; + register pthread_mutex_t mtx; + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire(&ptw32_mutex_test_init_lock, &node); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section + * and only initialise if the mutex is valid (not been destroyed). + * If a static mutex has been destroyed, the application can + * re-initialise it only by calling pthread_mutex_init() + * explicitly. + */ + mtx = *mutex; + + if (mtx == PTHREAD_MUTEX_INITIALIZER) + { + result = pthread_mutex_init (mutex, NULL); + } + else if (mtx == PTHREAD_RECURSIVE_MUTEX_INITIALIZER) + { + result = pthread_mutex_init (mutex, &ptw32_recursive_mutexattr); + } + else if (mtx == PTHREAD_ERRORCHECK_MUTEX_INITIALIZER) + { + result = pthread_mutex_init (mutex, &ptw32_errorcheck_mutexattr); + } + else if (mtx == NULL) + { + /* + * The mutex has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + result = EINVAL; + } + + ptw32_mcs_lock_release(&node); + + return (result); +} diff --git a/libs/pthreads/src/ptw32_new.c b/libs/pthreads/src/ptw32_new.c new file mode 100644 index 0000000000..ac836ead3a --- /dev/null +++ b/libs/pthreads/src/ptw32_new.c @@ -0,0 +1,94 @@ +/* + * ptw32_new.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +pthread_t +ptw32_new (void) +{ + pthread_t t; + pthread_t nil = {NULL, 0}; + ptw32_thread_t * tp; + + /* + * If there's a reusable pthread_t then use it. + */ + t = ptw32_threadReusePop (); + + if (NULL != t.p) + { + tp = (ptw32_thread_t *) t.p; + } + else + { + /* No reuse threads available */ + tp = (ptw32_thread_t *) calloc (1, sizeof(ptw32_thread_t)); + + if (tp == NULL) + { + return nil; + } + + /* ptHandle.p needs to point to it's parent ptw32_thread_t. */ + t.p = tp->ptHandle.p = tp; + t.x = tp->ptHandle.x = 0; + } + + /* Set default state. */ + tp->seqNumber = ++ptw32_threadSeqNumber; + tp->sched_priority = THREAD_PRIORITY_NORMAL; + tp->detachState = PTHREAD_CREATE_JOINABLE; + tp->cancelState = PTHREAD_CANCEL_ENABLE; + tp->cancelType = PTHREAD_CANCEL_DEFERRED; + tp->stateLock = 0; + tp->threadLock = 0; + tp->robustMxListLock = 0; + tp->robustMxList = NULL; + tp->cancelEvent = CreateEvent (0, (int) PTW32_TRUE, /* manualReset */ + (int) PTW32_FALSE, /* setSignaled */ + NULL); + + if (tp->cancelEvent == NULL) + { + ptw32_threadReusePush (tp->ptHandle); + return nil; + } + + return t; + +} diff --git a/libs/pthreads/src/ptw32_processInitialize.c b/libs/pthreads/src/ptw32_processInitialize.c new file mode 100644 index 0000000000..8da3e41fa1 --- /dev/null +++ b/libs/pthreads/src/ptw32_processInitialize.c @@ -0,0 +1,92 @@ +/* + * ptw32_processInitialize.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +ptw32_processInitialize (void) + /* + * ------------------------------------------------------ + * DOCPRIVATE + * This function performs process wide initialization for + * the pthread library. + * + * PARAMETERS + * N/A + * + * DESCRIPTION + * This function performs process wide initialization for + * the pthread library. + * If successful, this routine sets the global variable + * ptw32_processInitialized to TRUE. + * + * RESULTS + * TRUE if successful, + * FALSE otherwise + * + * ------------------------------------------------------ + */ +{ + if (ptw32_processInitialized) + { + /* + * Ignore if already initialized. this is useful for + * programs that uses a non-dll pthread + * library. Such programs must call ptw32_processInitialize() explicitly, + * since this initialization routine is automatically called only when + * the dll is loaded. + */ + return PTW32_TRUE; + } + + ptw32_processInitialized = PTW32_TRUE; + + /* + * Initialize Keys + */ + if ((pthread_key_create (&ptw32_selfThreadKey, NULL) != 0) || + (pthread_key_create (&ptw32_cleanupKey, NULL) != 0)) + { + + ptw32_processTerminate (); + } + + return (ptw32_processInitialized); + +} /* processInitialize */ diff --git a/libs/pthreads/src/ptw32_processTerminate.c b/libs/pthreads/src/ptw32_processTerminate.c new file mode 100644 index 0000000000..83f0f23cab --- /dev/null +++ b/libs/pthreads/src/ptw32_processTerminate.c @@ -0,0 +1,105 @@ +/* + * ptw32_processTerminate.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void +ptw32_processTerminate (void) + /* + * ------------------------------------------------------ + * DOCPRIVATE + * This function performs process wide termination for + * the pthread library. + * + * PARAMETERS + * N/A + * + * DESCRIPTION + * This function performs process wide termination for + * the pthread library. + * This routine sets the global variable + * ptw32_processInitialized to FALSE + * + * RESULTS + * N/A + * + * ------------------------------------------------------ + */ +{ + if (ptw32_processInitialized) + { + ptw32_thread_t * tp, * tpNext; + ptw32_mcs_local_node_t node; + + if (ptw32_selfThreadKey != NULL) + { + /* + * Release ptw32_selfThreadKey + */ + pthread_key_delete (ptw32_selfThreadKey); + + ptw32_selfThreadKey = NULL; + } + + if (ptw32_cleanupKey != NULL) + { + /* + * Release ptw32_cleanupKey + */ + pthread_key_delete (ptw32_cleanupKey); + + ptw32_cleanupKey = NULL; + } + + ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node); + + tp = ptw32_threadReuseTop; + while (tp != PTW32_THREAD_REUSE_EMPTY) + { + tpNext = tp->prevReuse; + free (tp); + tp = tpNext; + } + + ptw32_mcs_lock_release(&node); + + ptw32_processInitialized = PTW32_FALSE; + } + +} /* processTerminate */ diff --git a/libs/pthreads/src/ptw32_relmillisecs.c b/libs/pthreads/src/ptw32_relmillisecs.c new file mode 100644 index 0000000000..894d5c9d46 --- /dev/null +++ b/libs/pthreads/src/ptw32_relmillisecs.c @@ -0,0 +1,132 @@ +/* + * ptw32_relmillisecs.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#if !defined(NEED_FTIME) +#include +#endif + + +#if defined(PTW32_BUILD_INLINED) +INLINE +#endif /* PTW32_BUILD_INLINED */ +DWORD +ptw32_relmillisecs (const struct timespec * abstime) +{ + const int64_t NANOSEC_PER_MILLISEC = 1000000; + const int64_t MILLISEC_PER_SEC = 1000; + DWORD milliseconds; + int64_t tmpAbsMilliseconds; + int64_t tmpCurrMilliseconds; +#if defined(NEED_FTIME) + struct timespec currSysTime; + FILETIME ft; + SYSTEMTIME st; +#else /* ! NEED_FTIME */ +#if ( defined(_MSC_VER) && _MSC_VER >= 1300 ) || \ + ( (defined(__MINGW64__) || defined(__MINGW32__)) && __MSVCRT_VERSION__ >= 0x0601 ) + struct __timeb64 currSysTime; +#else + struct _timeb currSysTime; +#endif +#endif /* NEED_FTIME */ + + + /* + * Calculate timeout as milliseconds from current system time. + */ + + /* + * subtract current system time from abstime in a way that checks + * that abstime is never in the past, or is never equivalent to the + * defined INFINITE value (0xFFFFFFFF). + * + * Assume all integers are unsigned, i.e. cannot test if less than 0. + */ + tmpAbsMilliseconds = (int64_t)abstime->tv_sec * MILLISEC_PER_SEC; + tmpAbsMilliseconds += ((int64_t)abstime->tv_nsec + (NANOSEC_PER_MILLISEC/2)) / NANOSEC_PER_MILLISEC; + + /* get current system time */ + +#if defined(NEED_FTIME) + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + /* + * GetSystemTimeAsFileTime(&ft); would be faster, + * but it does not exist on WinCE + */ + + ptw32_filetime_to_timespec(&ft, &currSysTime); + + tmpCurrMilliseconds = (int64_t)currSysTime.tv_sec * MILLISEC_PER_SEC; + tmpCurrMilliseconds += ((int64_t)currSysTime.tv_nsec + (NANOSEC_PER_MILLISEC/2)) + / NANOSEC_PER_MILLISEC; + +#else /* ! NEED_FTIME */ + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + _ftime64_s(&currSysTime); +#elif ( defined(_MSC_VER) && _MSC_VER >= 1300 ) || \ + ( (defined(__MINGW64__) || defined(__MINGW32__)) && __MSVCRT_VERSION__ >= 0x0601 ) + _ftime64(&currSysTime); +#else + _ftime(&currSysTime); +#endif + + tmpCurrMilliseconds = (int64_t) currSysTime.time * MILLISEC_PER_SEC; + tmpCurrMilliseconds += (int64_t) currSysTime.millitm; + +#endif /* NEED_FTIME */ + + if (tmpAbsMilliseconds > tmpCurrMilliseconds) + { + milliseconds = (DWORD) (tmpAbsMilliseconds - tmpCurrMilliseconds); + if (milliseconds == INFINITE) + { + /* Timeouts must be finite */ + milliseconds--; + } + } + else + { + /* The abstime given is in the past */ + milliseconds = 0; + } + + return milliseconds; +} diff --git a/libs/pthreads/src/ptw32_reuse.c b/libs/pthreads/src/ptw32_reuse.c new file mode 100644 index 0000000000..7325857ba2 --- /dev/null +++ b/libs/pthreads/src/ptw32_reuse.c @@ -0,0 +1,151 @@ +/* + * ptw32_threadReuse.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +/* + * How it works: + * A pthread_t is a struct (2x32 bit scalar types on IA-32, 2x64 bit on IA-64) + * which is normally passed/returned by value to/from pthreads routines. + * Applications are therefore storing a copy of the struct as it is at that + * time. + * + * The original pthread_t struct plus all copies of it contain the address of + * the thread state struct ptw32_thread_t_ (p), plus a reuse counter (x). Each + * ptw32_thread_t contains the original copy of it's pthread_t. + * Once malloced, a ptw32_thread_t_ struct is not freed until the process exits. + * + * The thread reuse stack is a simple LILO stack managed through a singly + * linked list element in the ptw32_thread_t. + * + * Each time a thread is destroyed, the ptw32_thread_t address is pushed onto the + * reuse stack after it's ptHandle's reuse counter has been incremented. + * + * The following can now be said from this: + * - two pthread_t's are identical if their ptw32_thread_t reference pointers + * are equal and their reuse counters are equal. That is, + * + * equal = (a.p == b.p && a.x == b.x) + * + * - a pthread_t copy refers to a destroyed thread if the reuse counter in + * the copy is not equal to the reuse counter in the original. + * + * threadDestroyed = (copy.x != ((ptw32_thread_t *)copy.p)->ptHandle.x) + * + */ + +/* + * Pop a clean pthread_t struct off the reuse stack. + */ +pthread_t +ptw32_threadReusePop (void) +{ + pthread_t t = {NULL, 0}; + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node); + + if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseTop) + { + ptw32_thread_t * tp; + + tp = ptw32_threadReuseTop; + + ptw32_threadReuseTop = tp->prevReuse; + + if (PTW32_THREAD_REUSE_EMPTY == ptw32_threadReuseTop) + { + ptw32_threadReuseBottom = PTW32_THREAD_REUSE_EMPTY; + } + + tp->prevReuse = NULL; + + t = tp->ptHandle; + } + + ptw32_mcs_lock_release(&node); + + return t; + +} + +/* + * Push a clean pthread_t struct onto the reuse stack. + * Must be re-initialised when reused. + * All object elements (mutexes, events etc) must have been either + * detroyed before this, or never initialised. + */ +void +ptw32_threadReusePush (pthread_t thread) +{ + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + pthread_t t; + ptw32_mcs_local_node_t node; + + ptw32_mcs_lock_acquire(&ptw32_thread_reuse_lock, &node); + + t = tp->ptHandle; + memset(tp, 0, sizeof(ptw32_thread_t)); + + /* Must restore the original POSIX handle that we just wiped. */ + tp->ptHandle = t; + + /* Bump the reuse counter now */ +#if defined(PTW32_THREAD_ID_REUSE_INCREMENT) + tp->ptHandle.x += PTW32_THREAD_ID_REUSE_INCREMENT; +#else + tp->ptHandle.x++; +#endif + + tp->state = PThreadStateReuse; + + tp->prevReuse = PTW32_THREAD_REUSE_EMPTY; + + if (PTW32_THREAD_REUSE_EMPTY != ptw32_threadReuseBottom) + { + ptw32_threadReuseBottom->prevReuse = tp; + } + else + { + ptw32_threadReuseTop = tp; + } + + ptw32_threadReuseBottom = tp; + + ptw32_mcs_lock_release(&node); +} diff --git a/libs/pthreads/src/ptw32_rwlock_cancelwrwait.c b/libs/pthreads/src/ptw32_rwlock_cancelwrwait.c new file mode 100644 index 0000000000..a057bd1d72 --- /dev/null +++ b/libs/pthreads/src/ptw32_rwlock_cancelwrwait.c @@ -0,0 +1,50 @@ +/* + * ptw32_rwlock_cancelwrwait.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +void +ptw32_rwlock_cancelwrwait (void *arg) +{ + pthread_rwlock_t rwl = (pthread_rwlock_t) arg; + + rwl->nSharedAccessCount = -rwl->nCompletedSharedAccessCount; + rwl->nCompletedSharedAccessCount = 0; + + (void) pthread_mutex_unlock (&(rwl->mtxSharedAccessCompleted)); + (void) pthread_mutex_unlock (&(rwl->mtxExclusiveAccess)); +} diff --git a/libs/pthreads/src/ptw32_rwlock_check_need_init.c b/libs/pthreads/src/ptw32_rwlock_check_need_init.c new file mode 100644 index 0000000000..858ee271ce --- /dev/null +++ b/libs/pthreads/src/ptw32_rwlock_check_need_init.c @@ -0,0 +1,77 @@ +/* + * pthread_rwlock_check_need_init.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +INLINE int +ptw32_rwlock_check_need_init (pthread_rwlock_t * rwlock) +{ + int result = 0; + ptw32_mcs_local_node_t node; + + /* + * The following guarded test is specifically for statically + * initialised rwlocks (via PTHREAD_RWLOCK_INITIALIZER). + */ + ptw32_mcs_lock_acquire(&ptw32_rwlock_test_init_lock, &node); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section + * and only initialise if the rwlock is valid (not been destroyed). + * If a static rwlock has been destroyed, the application can + * re-initialise it only by calling pthread_rwlock_init() + * explicitly. + */ + if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) + { + result = pthread_rwlock_init (rwlock, NULL); + } + else if (*rwlock == NULL) + { + /* + * The rwlock has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + result = EINVAL; + } + + ptw32_mcs_lock_release(&node); + + return result; +} diff --git a/libs/pthreads/src/ptw32_semwait.c b/libs/pthreads/src/ptw32_semwait.c new file mode 100644 index 0000000000..c3c4fd0e5e --- /dev/null +++ b/libs/pthreads/src/ptw32_semwait.c @@ -0,0 +1,135 @@ +/* + * ptw32_semwait.c + * + * Description: + * This translation unit implements mutual exclusion (mutex) primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined(_UWIN) +/*# include */ +#endif +#include "pthread.h" +#include "implement.h" + + +int +ptw32_semwait (sem_t * sem) + /* + * ------------------------------------------------------ + * DESCRIPTION + * This function waits on a POSIX semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * the calling thread (or process) is blocked until it can + * successfully decrease the value. + * + * Unlike sem_wait(), this routine is non-cancelable. + * + * RESULTS + * 0 successfully decreased semaphore, + * -1 failed, error in errno. + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + if (s == NULL) + { + result = EINVAL; + } + else + { + if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + int v; + + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + v = --s->value; + (void) pthread_mutex_unlock (&s->lock); + + if (v < 0) + { + /* Must wait */ + if (WaitForSingleObject (s->sem, INFINITE) == WAIT_OBJECT_0) + { +#if defined(NEED_SEM) + if (pthread_mutex_lock (&s->lock) == 0) + { + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + if (s->leftToUnblock > 0) + { + --s->leftToUnblock; + SetEvent(s->sem); + } + (void) pthread_mutex_unlock (&s->lock); + } +#endif + return 0; + } + } + else + { + return 0; + } + } + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* ptw32_semwait */ diff --git a/libs/pthreads/src/ptw32_spinlock_check_need_init.c b/libs/pthreads/src/ptw32_spinlock_check_need_init.c new file mode 100644 index 0000000000..8808454ee8 --- /dev/null +++ b/libs/pthreads/src/ptw32_spinlock_check_need_init.c @@ -0,0 +1,78 @@ +/* + * ptw32_spinlock_check_need_init.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +INLINE int +ptw32_spinlock_check_need_init (pthread_spinlock_t * lock) +{ + int result = 0; + ptw32_mcs_local_node_t node; + + /* + * The following guarded test is specifically for statically + * initialised spinlocks (via PTHREAD_SPINLOCK_INITIALIZER). + */ + ptw32_mcs_lock_acquire(&ptw32_spinlock_test_init_lock, &node); + + /* + * We got here possibly under race + * conditions. Check again inside the critical section + * and only initialise if the spinlock is valid (not been destroyed). + * If a static spinlock has been destroyed, the application can + * re-initialise it only by calling pthread_spin_init() + * explicitly. + */ + if (*lock == PTHREAD_SPINLOCK_INITIALIZER) + { + result = pthread_spin_init (lock, PTHREAD_PROCESS_PRIVATE); + } + else if (*lock == NULL) + { + /* + * The spinlock has been destroyed while we were waiting to + * initialise it, so the operation that caused the + * auto-initialisation should fail. + */ + result = EINVAL; + } + + ptw32_mcs_lock_release(&node); + + return (result); +} diff --git a/libs/pthreads/src/ptw32_threadDestroy.c b/libs/pthreads/src/ptw32_threadDestroy.c new file mode 100644 index 0000000000..41499b11b6 --- /dev/null +++ b/libs/pthreads/src/ptw32_threadDestroy.c @@ -0,0 +1,79 @@ +/* + * ptw32_threadDestroy.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void +ptw32_threadDestroy (pthread_t thread) +{ + ptw32_thread_t * tp = (ptw32_thread_t *) thread.p; + ptw32_thread_t threadCopy; + + if (tp != NULL) + { + /* + * Copy thread state so that the thread can be atomically NULLed. + */ + memcpy (&threadCopy, tp, sizeof (threadCopy)); + + /* + * Thread ID structs are never freed. They're NULLed and reused. + * This also sets the thread to PThreadStateInitial (invalid). + */ + ptw32_threadReusePush (thread); + + /* Now work on the copy. */ + if (threadCopy.cancelEvent != NULL) + { + CloseHandle (threadCopy.cancelEvent); + } + +#if ! (defined(__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__) + /* + * See documentation for endthread vs endthreadex. + */ + if (threadCopy.threadH != 0) + { + CloseHandle (threadCopy.threadH); + } +#endif + + } +} /* ptw32_threadDestroy */ + diff --git a/libs/pthreads/src/ptw32_threadStart.c b/libs/pthreads/src/ptw32_threadStart.c new file mode 100644 index 0000000000..e83ede0ec4 --- /dev/null +++ b/libs/pthreads/src/ptw32_threadStart.c @@ -0,0 +1,357 @@ +/* + * ptw32_threadStart.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include + +#if defined(__CLEANUP_C) +# include +#endif + +#if defined(__CLEANUP_SEH) + +static DWORD +ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei) +{ + switch (ep->ExceptionRecord->ExceptionCode) + { + case EXCEPTION_PTW32_SERVICES: + { + DWORD param; + DWORD numParams = ep->ExceptionRecord->NumberParameters; + + numParams = (numParams > 3) ? 3 : numParams; + + for (param = 0; param < numParams; param++) + { + ei[param] = ep->ExceptionRecord->ExceptionInformation[param]; + } + + return EXCEPTION_EXECUTE_HANDLER; + break; + } + default: + { + /* + * A system unexpected exception has occurred running the user's + * routine. We need to cleanup before letting the exception + * out of thread scope. + */ + pthread_t self = pthread_self (); + + ptw32_callUserDestroyRoutines (self); + + return EXCEPTION_CONTINUE_SEARCH; + break; + } + } +} + +#elif defined(__CLEANUP_CXX) + +#if defined(_MSC_VER) +# include +#elif defined(__WATCOMC__) +# include +# include +typedef terminate_handler + terminate_function; +#else +# if defined(__GNUC__) && __GNUC__ < 3 +# include +# else +# include +using + std::terminate_handler; +using + std::terminate; +using + std::set_terminate; +# endif +typedef terminate_handler + terminate_function; +#endif + +static terminate_function + ptw32_oldTerminate; + +void +ptw32_terminate () +{ + set_terminate (ptw32_oldTerminate); + (void) pthread_win32_thread_detach_np (); + terminate (); +} + +#endif + +#if ! (defined(__MINGW64__) || defined(__MINGW32__)) || (defined (__MSVCRT__) && ! defined (__DMC__)) +unsigned + __stdcall +#else +void +#endif +ptw32_threadStart (void *vthreadParms) +{ + ThreadParms * threadParms = (ThreadParms *) vthreadParms; + pthread_t self; + ptw32_thread_t * sp; + void * (PTW32_CDECL *start) (void *); + void * arg; + +#if defined(__CLEANUP_SEH) + DWORD + ei[] = { 0, 0, 0 }; +#endif + +#if defined(__CLEANUP_C) + int setjmp_rc; +#endif + + ptw32_mcs_local_node_t stateLock; + void * status = (void *) 0; + + self = threadParms->tid; + sp = (ptw32_thread_t *) self.p; + start = threadParms->start; + arg = threadParms->arg; + + free (threadParms); + +#if (defined(__MINGW64__) || defined(__MINGW32__)) && ! defined (__MSVCRT__) + /* + * beginthread does not return the thread id and is running + * before it returns us the thread handle, and so we do it here. + */ + sp->thread = GetCurrentThreadId (); + /* + * Here we're using stateLock as a general-purpose lock + * to make the new thread wait until the creating thread + * has the new handle. + */ + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); + pthread_setspecific (ptw32_selfThreadKey, sp); +#else + pthread_setspecific (ptw32_selfThreadKey, sp); + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); +#endif + + sp->state = PThreadStateRunning; + ptw32_mcs_lock_release (&stateLock); + +#if defined(__CLEANUP_SEH) + + __try + { + /* + * Run the caller's routine; + */ + status = sp->exitStatus = (*start) (arg); + sp->state = PThreadStateExiting; + +#if defined(_UWIN) + if (--pthread_count <= 0) + exit (0); +#endif + + } + __except (ExceptionFilter (GetExceptionInformation (), ei)) + { + switch (ei[0]) + { + case PTW32_EPS_CANCEL: + status = sp->exitStatus = PTHREAD_CANCELED; +#if defined(_UWIN) + if (--pthread_count <= 0) + exit (0); +#endif + break; + case PTW32_EPS_EXIT: + status = sp->exitStatus; + break; + default: + status = sp->exitStatus = PTHREAD_CANCELED; + break; + } + } + +#else /* __CLEANUP_SEH */ + +#if defined(__CLEANUP_C) + + setjmp_rc = setjmp (sp->start_mark); + + if (0 == setjmp_rc) + { + + /* + * Run the caller's routine; + */ + status = sp->exitStatus = (*start) (arg); + sp->state = PThreadStateExiting; + } + else + { + switch (setjmp_rc) + { + case PTW32_EPS_CANCEL: + status = sp->exitStatus = PTHREAD_CANCELED; + break; + case PTW32_EPS_EXIT: + status = sp->exitStatus; + break; + default: + status = sp->exitStatus = PTHREAD_CANCELED; + break; + } + } + +#else /* __CLEANUP_C */ + +#if defined(__CLEANUP_CXX) + + ptw32_oldTerminate = set_terminate (&ptw32_terminate); + + try + { + /* + * Run the caller's routine in a nested try block so that we + * can run the user's terminate function, which may call + * pthread_exit() or be canceled. + */ + try + { + status = sp->exitStatus = (*start) (arg); + sp->state = PThreadStateExiting; + } + catch (ptw32_exception &) + { + /* + * Pass these through to the outer block. + */ + throw; + } + catch (...) + { + /* + * We want to run the user's terminate function if supplied. + * That function may call pthread_exit() or be canceled, which will + * be handled by the outer try block. + * + * ptw32_terminate() will be called if there is no user + * supplied function. + */ + terminate_function + term_func = set_terminate (0); + set_terminate (term_func); + + if (term_func != 0) + { + term_func (); + } + throw; + } + } + catch (ptw32_exception_cancel &) + { + /* + * Thread was canceled. + */ + status = sp->exitStatus = PTHREAD_CANCELED; + } + catch (ptw32_exception_exit &) + { + /* + * Thread was exited via pthread_exit(). + */ + status = sp->exitStatus; + } + catch (...) + { + /* + * A system unexpected exception has occurred running the user's + * terminate routine. We get control back within this block + * and exit with a substitute status. If the thread was not + * cancelled then this indicates the unhandled exception. + */ + status = sp->exitStatus = PTHREAD_CANCELED; + } + + (void) set_terminate (ptw32_oldTerminate); + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ +#endif /* __CLEANUP_C */ +#endif /* __CLEANUP_SEH */ + +#if defined(PTW32_STATIC_LIB) + /* + * We need to cleanup the pthread now if we have + * been statically linked, in which case the cleanup + * in dllMain won't get done. Joinable threads will + * only be partially cleaned up and must be fully cleaned + * up by pthread_join() or pthread_detach(). + * + * Note: if this library has been statically linked, + * implicitly created pthreads (those created + * for Win32 threads which have called pthreads routines) + * must be cleaned up explicitly by the application + * (by calling pthread_win32_thread_detach_np()). + * For the dll, dllMain will do the cleanup automatically. + */ + (void) pthread_win32_thread_detach_np (); +#endif + +#if ! (defined(__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__) + _endthreadex ((unsigned)(size_t) status); +#else + _endthread (); +#endif + + /* + * Never reached. + */ + +#if ! (defined(__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__) + return (unsigned)(size_t) status; +#endif + +} /* ptw32_threadStart */ diff --git a/libs/pthreads/src/ptw32_throw.c b/libs/pthreads/src/ptw32_throw.c new file mode 100644 index 0000000000..1404e940f5 --- /dev/null +++ b/libs/pthreads/src/ptw32_throw.c @@ -0,0 +1,189 @@ +/* + * ptw32_throw.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + +#if defined(__CLEANUP_C) +# include +#endif + +/* + * ptw32_throw + * + * All canceled and explicitly exited POSIX threads go through + * here. This routine knows how to exit both POSIX initiated threads and + * 'implicit' POSIX threads for each of the possible language modes (C, + * C++, and SEH). + */ +#if defined(_MSC_VER) +/* + * Ignore the warning: + * "C++ exception specification ignored except to indicate that + * the function is not __declspec(nothrow)." + */ +#pragma warning(disable:4290) +#endif +void +ptw32_throw (DWORD exception) +#if defined(__CLEANUP_CXX) + throw(ptw32_exception_cancel,ptw32_exception_exit) +#endif +{ + /* + * Don't use pthread_self() to avoid creating an implicit POSIX thread handle + * unnecessarily. + */ + ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); + +#if defined(__CLEANUP_SEH) + DWORD exceptionInformation[3]; +#endif + + sp->state = PThreadStateExiting; + + if (exception != PTW32_EPS_CANCEL && exception != PTW32_EPS_EXIT) + { + /* Should never enter here */ + exit (1); + } + + if (NULL == sp || sp->implicit) + { + /* + * We're inside a non-POSIX initialised Win32 thread + * so there is no point to jump or throw back to. Just do an + * explicit thread exit here after cleaning up POSIX + * residue (i.e. cleanup handlers, POSIX thread handle etc). + */ +#if ! (defined(__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__) + unsigned exitCode = 0; + + switch (exception) + { + case PTW32_EPS_CANCEL: + exitCode = (unsigned)(size_t) PTHREAD_CANCELED; + break; + case PTW32_EPS_EXIT: + if (NULL != sp) + { + exitCode = (unsigned)(size_t) sp->exitStatus; + } + break; + } +#endif + +#if defined(PTW32_STATIC_LIB) + + pthread_win32_thread_detach_np (); + +#endif + +#if ! (defined(__MINGW64__) || defined(__MINGW32__)) || defined (__MSVCRT__) || defined (__DMC__) + _endthreadex (exitCode); +#else + _endthread (); +#endif + + } + +#if defined(__CLEANUP_SEH) + + + exceptionInformation[0] = (DWORD) (exception); + exceptionInformation[1] = (DWORD) (0); + exceptionInformation[2] = (DWORD) (0); + + RaiseException (EXCEPTION_PTW32_SERVICES, 0, 3, exceptionInformation); + +#else /* __CLEANUP_SEH */ + +#if defined(__CLEANUP_C) + + ptw32_pop_cleanup_all (1); + longjmp (sp->start_mark, exception); + +#else /* __CLEANUP_C */ + +#if defined(__CLEANUP_CXX) + + switch (exception) + { + case PTW32_EPS_CANCEL: + throw ptw32_exception_cancel (); + break; + case PTW32_EPS_EXIT: + throw ptw32_exception_exit (); + break; + } + +#else + +#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. + +#endif /* __CLEANUP_CXX */ + +#endif /* __CLEANUP_C */ + +#endif /* __CLEANUP_SEH */ + + /* Never reached */ +} + + +void +ptw32_pop_cleanup_all (int execute) +{ + while (NULL != ptw32_pop_cleanup (execute)) + { + } +} + + +DWORD +ptw32_get_exception_services_code (void) +{ +#if defined(__CLEANUP_SEH) + + return EXCEPTION_PTW32_SERVICES; + +#else + + return (DWORD)0; + +#endif +} diff --git a/libs/pthreads/src/ptw32_timespec.c b/libs/pthreads/src/ptw32_timespec.c new file mode 100644 index 0000000000..6318957a89 --- /dev/null +++ b/libs/pthreads/src/ptw32_timespec.c @@ -0,0 +1,83 @@ +/* + * ptw32_timespec.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#if defined(NEED_FTIME) + +/* + * time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds + */ +#define PTW32_TIMESPEC_TO_FILETIME_OFFSET \ + ( ((int64_t) 27111902 << 32) + (int64_t) 3577643008 ) + +INLINE void +ptw32_timespec_to_filetime (const struct timespec *ts, FILETIME * ft) + /* + * ------------------------------------------------------------------- + * converts struct timespec + * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. + * into FILETIME (as set by GetSystemTimeAsFileTime), where the time is + * expressed in 100 nanoseconds from Jan 1, 1601, + * ------------------------------------------------------------------- + */ +{ + *(int64_t *) ft = ts->tv_sec * 10000000 + + (ts->tv_nsec + 50) / 100 + PTW32_TIMESPEC_TO_FILETIME_OFFSET; +} + +INLINE void +ptw32_filetime_to_timespec (const FILETIME * ft, struct timespec *ts) + /* + * ------------------------------------------------------------------- + * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is + * expressed in 100 nanoseconds from Jan 1, 1601, + * into struct timespec + * where the time is expressed in seconds and nanoseconds from Jan 1, 1970. + * ------------------------------------------------------------------- + */ +{ + ts->tv_sec = + (int) ((*(int64_t *) ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET) / 10000000); + ts->tv_nsec = + (int) ((*(int64_t *) ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET - + ((int64_t) ts->tv_sec * (int64_t) 10000000)) * 100); +} + +#endif /* NEED_FTIME */ diff --git a/libs/pthreads/src/ptw32_tkAssocCreate.c b/libs/pthreads/src/ptw32_tkAssocCreate.c new file mode 100644 index 0000000000..50d6c500c3 --- /dev/null +++ b/libs/pthreads/src/ptw32_tkAssocCreate.c @@ -0,0 +1,118 @@ +/* + * ptw32_tkAssocCreate.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +int +ptw32_tkAssocCreate (ptw32_thread_t * sp, pthread_key_t key) + /* + * ------------------------------------------------------------------- + * This routine creates an association that + * is unique for the given (thread,key) combination.The association + * is referenced by both the thread and the key. + * This association allows us to determine what keys the + * current thread references and what threads a given key + * references. + * See the detailed description + * at the beginning of this file for further details. + * + * Notes: + * 1) New associations are pushed to the beginning of the + * chain so that the internal ptw32_selfThreadKey association + * is always last, thus allowing selfThreadExit to + * be implicitly called last by pthread_exit. + * 2) + * + * Parameters: + * thread + * current running thread. + * key + * key on which to create an association. + * Returns: + * 0 - if successful, + * ENOMEM - not enough memory to create assoc or other object + * EINVAL - an internal error occurred + * ENOSYS - an internal error occurred + * ------------------------------------------------------------------- + */ +{ + ThreadKeyAssoc *assoc; + + /* + * Have to create an association and add it + * to both the key and the thread. + * + * Both key->keyLock and thread->threadLock are locked before + * entry to this routine. + */ + assoc = (ThreadKeyAssoc *) calloc (1, sizeof (*assoc)); + + if (assoc == NULL) + { + return ENOMEM; + } + + assoc->thread = sp; + assoc->key = key; + + /* + * Register assoc with key + */ + assoc->prevThread = NULL; + assoc->nextThread = (ThreadKeyAssoc *) key->threads; + if (assoc->nextThread != NULL) + { + assoc->nextThread->prevThread = assoc; + } + key->threads = (void *) assoc; + + /* + * Register assoc with thread + */ + assoc->prevKey = NULL; + assoc->nextKey = (ThreadKeyAssoc *) sp->keys; + if (assoc->nextKey != NULL) + { + assoc->nextKey->prevKey = assoc; + } + sp->keys = (void *) assoc; + + return (0); + +} /* ptw32_tkAssocCreate */ diff --git a/libs/pthreads/src/ptw32_tkAssocDestroy.c b/libs/pthreads/src/ptw32_tkAssocDestroy.c new file mode 100644 index 0000000000..fedebf5935 --- /dev/null +++ b/libs/pthreads/src/ptw32_tkAssocDestroy.c @@ -0,0 +1,114 @@ +/* + * ptw32_tkAssocDestroy.c + * + * Description: + * This translation unit implements routines which are private to + * the implementation and may be used throughout it. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +void +ptw32_tkAssocDestroy (ThreadKeyAssoc * assoc) + /* + * ------------------------------------------------------------------- + * This routine releases all resources for the given ThreadKeyAssoc + * once it is no longer being referenced + * ie) either the key or thread has stopped referencing it. + * + * Parameters: + * assoc + * an instance of ThreadKeyAssoc. + * Returns: + * N/A + * ------------------------------------------------------------------- + */ +{ + + /* + * Both key->keyLock and thread->threadLock are locked before + * entry to this routine. + */ + if (assoc != NULL) + { + ThreadKeyAssoc * prev, * next; + + /* Remove assoc from thread's keys chain */ + prev = assoc->prevKey; + next = assoc->nextKey; + if (prev != NULL) + { + prev->nextKey = next; + } + if (next != NULL) + { + next->prevKey = prev; + } + + if (assoc->thread->keys == assoc) + { + /* We're at the head of the thread's keys chain */ + assoc->thread->keys = next; + } + if (assoc->thread->nextAssoc == assoc) + { + /* + * Thread is exiting and we're deleting the assoc to be processed next. + * Hand thread the assoc after this one. + */ + assoc->thread->nextAssoc = next; + } + + /* Remove assoc from key's threads chain */ + prev = assoc->prevThread; + next = assoc->nextThread; + if (prev != NULL) + { + prev->nextThread = next; + } + if (next != NULL) + { + next->prevThread = prev; + } + + if (assoc->key->threads == assoc) + { + /* We're at the head of the key's threads chain */ + assoc->key->threads = next; + } + + free (assoc); + } + +} /* ptw32_tkAssocDestroy */ diff --git a/libs/pthreads/src/rwlock.c b/libs/pthreads/src/rwlock.c new file mode 100644 index 0000000000..4a3cd2594c --- /dev/null +++ b/libs/pthreads/src/rwlock.c @@ -0,0 +1,51 @@ +/* + * rwlock.c + * + * Description: + * This translation unit implements read/write lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "ptw32_rwlock_check_need_init.c" +#include "ptw32_rwlock_cancelwrwait.c" +#include "pthread_rwlock_init.c" +#include "pthread_rwlock_destroy.c" +#include "pthread_rwlockattr_init.c" +#include "pthread_rwlockattr_destroy.c" +#include "pthread_rwlockattr_getpshared.c" +#include "pthread_rwlockattr_setpshared.c" +#include "pthread_rwlock_rdlock.c" +#include "pthread_rwlock_timedrdlock.c" +#include "pthread_rwlock_wrlock.c" +#include "pthread_rwlock_timedwrlock.c" +#include "pthread_rwlock_unlock.c" +#include "pthread_rwlock_tryrdlock.c" +#include "pthread_rwlock_trywrlock.c" diff --git a/libs/pthreads/src/sched.c b/libs/pthreads/src/sched.c new file mode 100644 index 0000000000..ed30ea7b24 --- /dev/null +++ b/libs/pthreads/src/sched.c @@ -0,0 +1,53 @@ +/* + * sched.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +#include "pthread_attr_setschedpolicy.c" +#include "pthread_attr_getschedpolicy.c" +#include "pthread_attr_setschedparam.c" +#include "pthread_attr_getschedparam.c" +#include "pthread_attr_setinheritsched.c" +#include "pthread_attr_getinheritsched.c" +#include "pthread_setschedparam.c" +#include "pthread_getschedparam.c" +#include "sched_get_priority_max.c" +#include "sched_get_priority_min.c" +#include "sched_setscheduler.c" +#include "sched_getscheduler.c" +#include "sched_yield.c" diff --git a/libs/pthreads/src/sched.h b/libs/pthreads/src/sched.h new file mode 100644 index 0000000000..f36a97a66b --- /dev/null +++ b/libs/pthreads/src/sched.h @@ -0,0 +1,183 @@ +/* + * Module: sched.h + * + * Purpose: + * Provides an implementation of POSIX realtime extensions + * as defined in + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(_SCHED_H) +#define _SCHED_H + +#undef PTW32_SCHED_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_SCHED_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_SCHED_LEVEL +#define PTW32_SCHED_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_SCHED_LEVEL +#define PTW32_SCHED_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_SCHED_LEVEL_MAX 3 + +#if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL) +#define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX +/* Include everything */ +#endif + + +#if defined(__GNUC__) && !defined(__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#if !defined(PTW32_STATIC_LIB) +# if defined(PTW32_BUILD) +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#if !defined(PTW32_CONFIG_H) +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(__MINGW64__) +# define HAVE_STRUCT_TIMESPEC +# define HAVE_MODE_T +# elif defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX +#if defined(NEED_ERRNO) +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */ + +#if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN) +# if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX +/* For pid_t */ +# include +/* Required by Unix 98 */ +# include +# else + typedef int pid_t; +# endif +#else + typedef int pid_t; +#endif + +/* Thread scheduling policies */ + +enum { + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param { + int sched_priority; +}; + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +PTW32_DLLPORT int __cdecl sched_yield (void); + +PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); + +PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); + +PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); + +PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); + +/* + * Note that this macro returns ENOTSUP rather than + * ENOSYS as might be expected. However, returning ENOSYS + * should mean that sched_get_priority_{min,max} are + * not implemented as well as sched_rr_get_interval. + * This is not the case, since we just don't support + * round-robin scheduling. Therefore I have chosen to + * return the same value as sched_setscheduler when + * SCHED_RR is passed to it. + */ +#define sched_rr_get_interval(_pid, _interval) \ + ( errno = ENOTSUP, (int) -1 ) + + +#if defined(__cplusplus) +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_SCHED_LEVEL +#undef PTW32_SCHED_LEVEL_MAX + +#endif /* !_SCHED_H */ + diff --git a/libs/pthreads/src/sched_get_priority_max.c b/libs/pthreads/src/sched_get_priority_max.c new file mode 100644 index 0000000000..cabf2320a7 --- /dev/null +++ b/libs/pthreads/src/sched_get_priority_max.c @@ -0,0 +1,134 @@ +/* + * sched_get_priority_max.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +/* + * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and + * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine. + * + * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5 + * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny: + * highest priority use smaller numbers) and the following happens: + * + * sched_get_priority_min() returns 5 + * sched_get_priority_max() returns 1 + * + * The following table shows the base priority levels for combinations + * of priority class and priority value in Win32. + * + * Process Priority Class Thread Priority Level + * ----------------------------------------------------------------- + * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 17 REALTIME_PRIORITY_CLASS -7 + * 18 REALTIME_PRIORITY_CLASS -6 + * 19 REALTIME_PRIORITY_CLASS -5 + * 20 REALTIME_PRIORITY_CLASS -4 + * 21 REALTIME_PRIORITY_CLASS -3 + * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 27 REALTIME_PRIORITY_CLASS 3 + * 28 REALTIME_PRIORITY_CLASS 4 + * 29 REALTIME_PRIORITY_CLASS 5 + * 30 REALTIME_PRIORITY_CLASS 6 + * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * + * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. + */ + + +int +sched_get_priority_max (int policy) +{ + if (policy < SCHED_MIN || policy > SCHED_MAX) + { + errno = EINVAL; + return -1; + } + +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) + /* WinCE? */ + return PTW32_MAX (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#else + /* This is independent of scheduling policy in Win32. */ + return PTW32_MAX (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#endif +} diff --git a/libs/pthreads/src/sched_get_priority_min.c b/libs/pthreads/src/sched_get_priority_min.c new file mode 100644 index 0000000000..9c4f8591e5 --- /dev/null +++ b/libs/pthreads/src/sched_get_priority_min.c @@ -0,0 +1,135 @@ +/* + * sched_get_priority_min.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +/* + * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and + * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine. + * + * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5 + * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny: + * highest priority use smaller numbers) and the following happens: + * + * sched_get_priority_min() returns 5 + * sched_get_priority_max() returns 1 + * + * The following table shows the base priority levels for combinations + * of priority class and priority value in Win32. + * + * Process Priority Class Thread Priority Level + * ----------------------------------------------------------------- + * 1 IDLE_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 1 HIGH_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 2 IDLE_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 3 IDLE_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 4 IDLE_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 4 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 5 IDLE_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 5 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 5 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 6 IDLE_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 6 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 6 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 7 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 7 Background NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 7 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 8 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 8 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 8 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 8 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 9 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 9 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 9 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 10 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 10 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 11 Foreground NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 11 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 11 HIGH_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 12 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 12 HIGH_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 13 HIGH_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 14 HIGH_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 15 HIGH_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 IDLE_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 BELOW_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 15 ABOVE_NORMAL_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * 16 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_IDLE + * 17 REALTIME_PRIORITY_CLASS -7 + * 18 REALTIME_PRIORITY_CLASS -6 + * 19 REALTIME_PRIORITY_CLASS -5 + * 20 REALTIME_PRIORITY_CLASS -4 + * 21 REALTIME_PRIORITY_CLASS -3 + * 22 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_LOWEST + * 23 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_BELOW_NORMAL + * 24 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_NORMAL + * 25 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_ABOVE_NORMAL + * 26 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_HIGHEST + * 27 REALTIME_PRIORITY_CLASS 3 + * 28 REALTIME_PRIORITY_CLASS 4 + * 29 REALTIME_PRIORITY_CLASS 5 + * 30 REALTIME_PRIORITY_CLASS 6 + * 31 REALTIME_PRIORITY_CLASS THREAD_PRIORITY_TIME_CRITICAL + * + * Windows NT: Values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are not supported. + * + */ + + +int +sched_get_priority_min (int policy) +{ + if (policy < SCHED_MIN || policy > SCHED_MAX) + { + errno = EINVAL; + return -1; + } + +#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL) + /* WinCE? */ + return PTW32_MIN (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#else + /* This is independent of scheduling policy in Win32. */ + return PTW32_MIN (THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL); +#endif +} diff --git a/libs/pthreads/src/sched_getscheduler.c b/libs/pthreads/src/sched_getscheduler.c new file mode 100644 index 0000000000..8769c15e5a --- /dev/null +++ b/libs/pthreads/src/sched_getscheduler.c @@ -0,0 +1,71 @@ +/* + * sched_getscheduler.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +sched_getscheduler (pid_t pid) +{ + /* + * Win32 only has one policy which we call SCHED_OTHER. + * However, we try to provide other valid side-effects + * such as EPERM and ESRCH errors. + */ + if (0 != pid) + { + int selfPid = (int) GetCurrentProcessId (); + + if (pid != selfPid) + { + HANDLE h = + OpenProcess (PROCESS_QUERY_INFORMATION, PTW32_FALSE, (DWORD) pid); + + if (NULL == h) + { + errno = + (GetLastError () == + (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; + return -1; + } + else + CloseHandle(h); + } + } + + return SCHED_OTHER; +} diff --git a/libs/pthreads/src/sched_setscheduler.c b/libs/pthreads/src/sched_setscheduler.c new file mode 100644 index 0000000000..8691316371 --- /dev/null +++ b/libs/pthreads/src/sched_setscheduler.c @@ -0,0 +1,83 @@ +/* + * sched_setscheduler.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +sched_setscheduler (pid_t pid, int policy) +{ + /* + * Win32 only has one policy which we call SCHED_OTHER. + * However, we try to provide other valid side-effects + * such as EPERM and ESRCH errors. Choosing to check + * for a valid policy last allows us to get the most value out + * of this function. + */ + if (0 != pid) + { + int selfPid = (int) GetCurrentProcessId (); + + if (pid != selfPid) + { + HANDLE h = + OpenProcess (PROCESS_SET_INFORMATION, PTW32_FALSE, (DWORD) pid); + + if (NULL == h) + { + errno = + (GetLastError () == + (0xFF & ERROR_ACCESS_DENIED)) ? EPERM : ESRCH; + return -1; + } + else + CloseHandle(h); + } + } + + if (SCHED_OTHER != policy) + { + errno = ENOSYS; + return -1; + } + + /* + * Don't set anything because there is nothing to set. + * Just return the current (the only possible) value. + */ + return SCHED_OTHER; +} diff --git a/libs/pthreads/src/sched_yield.c b/libs/pthreads/src/sched_yield.c new file mode 100644 index 0000000000..6ac5ed9263 --- /dev/null +++ b/libs/pthreads/src/sched_yield.c @@ -0,0 +1,71 @@ +/* + * sched_yield.c + * + * Description: + * POSIX thread functions that deal with thread scheduling. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" +#include "sched.h" + +int +sched_yield (void) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function indicates that the calling thread is + * willing to give up some time slices to other threads. + * + * PARAMETERS + * N/A + * + * + * DESCRIPTION + * This function indicates that the calling thread is + * willing to give up some time slices to other threads. + * NOTE: Since this is part of POSIX 1003.1b + * (realtime extensions), it is defined as returning + * -1 if an error occurs and sets errno to the actual + * error. + * + * RESULTS + * 0 successfully created semaphore, + * ENOSYS sched_yield not supported, + * + * ------------------------------------------------------ + */ +{ + Sleep (0); + + return 0; +} diff --git a/libs/pthreads/src/sem_close.c b/libs/pthreads/src/sem_close.c new file mode 100644 index 0000000000..6d7280f299 --- /dev/null +++ b/libs/pthreads/src/sem_close.c @@ -0,0 +1,58 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_close.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#if defined(_MSC_VER) +#pragma warning( disable : 4100 ) +#endif + +int +sem_close (sem_t * sem) +{ + errno = ENOSYS; + return -1; +} /* sem_close */ diff --git a/libs/pthreads/src/sem_destroy.c b/libs/pthreads/src/sem_destroy.c new file mode 100644 index 0000000000..6c98e80b93 --- /dev/null +++ b/libs/pthreads/src/sem_destroy.c @@ -0,0 +1,144 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_destroy.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_destroy (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function destroys an unnamed semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function destroys an unnamed semaphore. + * + * RESULTS + * 0 successfully destroyed semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EBUSY threads (or processes) are currently + * blocked on 'sem' + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = NULL; + + if (sem == NULL || *sem == NULL) + { + result = EINVAL; + } + else + { + s = *sem; + + if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + if (s->value < 0) + { + (void) pthread_mutex_unlock (&s->lock); + result = EBUSY; + } + else + { + /* There are no threads currently blocked on this semaphore. */ + + if (!CloseHandle (s->sem)) + { + (void) pthread_mutex_unlock (&s->lock); + result = EINVAL; + } + else + { + /* + * Invalidate the semaphore handle when we have the lock. + * Other sema operations should test this after acquiring the lock + * to check that the sema is still valid, i.e. before performing any + * operations. This may only be necessary before the sema op routine + * returns so that the routine can return EINVAL - e.g. if setting + * s->value to SEM_VALUE_MAX below does force a fall-through. + */ + *sem = NULL; + + /* Prevent anyone else actually waiting on or posting this sema. + */ + s->value = SEM_VALUE_MAX; + + (void) pthread_mutex_unlock (&s->lock); + + do + { + /* Give other threads a chance to run and exit any sema op + * routines. Due to the SEM_VALUE_MAX value, if sem_post or + * sem_wait were blocked by us they should fall through. + */ + Sleep(0); + } + while (pthread_mutex_destroy (&s->lock) == EBUSY); + } + } + } + } + + if (result != 0) + { + errno = result; + return -1; + } + + free (s); + + return 0; + +} /* sem_destroy */ diff --git a/libs/pthreads/src/sem_getvalue.c b/libs/pthreads/src/sem_getvalue.c new file mode 100644 index 0000000000..baafb02cf0 --- /dev/null +++ b/libs/pthreads/src/sem_getvalue.c @@ -0,0 +1,110 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_getvalue.c + * + * Purpose: + * Semaphores aren't actually part of PThreads. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1-2001 + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_getvalue (sem_t * sem, int *sval) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function stores the current count value of the + * semaphore. + * RESULTS + * + * Return value + * + * 0 sval has been set. + * -1 failed, error in errno + * + * in global errno + * + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS this function is not supported, + * + * + * PARAMETERS + * + * sem pointer to an instance of sem_t + * + * sval pointer to int. + * + * DESCRIPTION + * This function stores the current count value of the semaphore + * pointed to by sem in the int pointed to by sval. + */ +{ + if (sem == NULL || *sem == NULL || sval == NULL) + { + errno = EINVAL; + return -1; + } + else + { + long value; + register sem_t s = *sem; + int result = 0; + + if ((result = pthread_mutex_lock(&s->lock)) == 0) + { + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + value = s->value; + (void) pthread_mutex_unlock(&s->lock); + *sval = value; + } + + return result; + } + +} /* sem_getvalue */ diff --git a/libs/pthreads/src/sem_init.c b/libs/pthreads/src/sem_init.c new file mode 100644 index 0000000000..f682f4b204 --- /dev/null +++ b/libs/pthreads/src/sem_init.c @@ -0,0 +1,169 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_init.c + * + * Purpose: + * Semaphores aren't actually part of PThreads. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1-2001 + * + * ------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + +int +sem_init (sem_t * sem, int pshared, unsigned int value) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function initializes a semaphore. The + * initial value of the semaphore is 'value' + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * pshared + * if zero, this semaphore may only be shared between + * threads in the same process. + * if nonzero, the semaphore can be shared between + * processes + * + * value + * initial value of the semaphore counter + * + * DESCRIPTION + * This function initializes a semaphore. The + * initial value of the semaphore is set to 'value'. + * + * RESULTS + * 0 successfully created semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, or + * 'value' >= SEM_VALUE_MAX + * ENOMEM out of memory, + * ENOSPC a required resource has been exhausted, + * ENOSYS semaphores are not supported, + * EPERM the process lacks appropriate privilege + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = NULL; + + if (pshared != 0) + { + /* + * Creating a semaphore that can be shared between + * processes + */ + result = EPERM; + } + else if (value > (unsigned int)SEM_VALUE_MAX) + { + result = EINVAL; + } + else + { + s = (sem_t) calloc (1, sizeof (*s)); + + if (NULL == s) + { + result = ENOMEM; + } + else + { + + s->value = value; + if (pthread_mutex_init(&s->lock, NULL) == 0) + { + +#if defined(NEED_SEM) + + s->sem = CreateEvent (NULL, + PTW32_FALSE, /* auto (not manual) reset */ + PTW32_FALSE, /* initial state is unset */ + NULL); + + if (0 == s->sem) + { + free (s); + (void) pthread_mutex_destroy(&s->lock); + result = ENOSPC; + } + else + { + s->leftToUnblock = 0; + } + +#else /* NEED_SEM */ + + if ((s->sem = CreateSemaphore (NULL, /* Always NULL */ + (long) 0, /* Force threads to wait */ + (long) SEM_VALUE_MAX, /* Maximum value */ + NULL)) == 0) /* Name */ + { + (void) pthread_mutex_destroy(&s->lock); + result = ENOSPC; + } + +#endif /* NEED_SEM */ + + } + else + { + result = ENOSPC; + } + + if (result != 0) + { + free(s); + } + } + } + + if (result != 0) + { + errno = result; + return -1; + } + + *sem = s; + + return 0; + +} /* sem_init */ diff --git a/libs/pthreads/src/sem_open.c b/libs/pthreads/src/sem_open.c new file mode 100644 index 0000000000..fb1cc541f8 --- /dev/null +++ b/libs/pthreads/src/sem_open.c @@ -0,0 +1,58 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_open.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#if defined(_MSC_VER) +#pragma warning( disable : 4100 ) +#endif + +int +sem_open (const char *name, int oflag, mode_t mode, unsigned int value) +{ + errno = ENOSYS; + return -1; +} /* sem_open */ diff --git a/libs/pthreads/src/sem_post.c b/libs/pthreads/src/sem_post.c new file mode 100644 index 0000000000..34832527b8 --- /dev/null +++ b/libs/pthreads/src/sem_post.c @@ -0,0 +1,128 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_post.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_post (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function posts a wakeup to a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function posts a wakeup to a semaphore. If there + * are waiting threads (or processes), one is awakened; + * otherwise, the semaphore value is incremented by one. + * + * RESULTS + * 0 successfully posted semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * ERANGE semaphore count is too big + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + if (s == NULL) + { + result = EINVAL; + } + else if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + result = EINVAL; + return -1; + } + + if (s->value < SEM_VALUE_MAX) + { +#if defined(NEED_SEM) + if (++s->value <= 0 + && !SetEvent(s->sem)) + { + s->value--; + result = EINVAL; + } +#else + if (++s->value <= 0 + && !ReleaseSemaphore (s->sem, 1, NULL)) + { + s->value--; + result = EINVAL; + } +#endif /* NEED_SEM */ + } + else + { + result = ERANGE; + } + + (void) pthread_mutex_unlock (&s->lock); + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* sem_post */ diff --git a/libs/pthreads/src/sem_post_multiple.c b/libs/pthreads/src/sem_post_multiple.c new file mode 100644 index 0000000000..44c168c6cf --- /dev/null +++ b/libs/pthreads/src/sem_post_multiple.c @@ -0,0 +1,142 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_post_multiple.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_post_multiple (sem_t * sem, int count) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function posts multiple wakeups to a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * count + * counter, must be greater than zero. + * + * DESCRIPTION + * This function posts multiple wakeups to a semaphore. If there + * are waiting threads (or processes), n <= count are awakened; + * the semaphore value is incremented by count - n. + * + * RESULTS + * 0 successfully posted semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore + * or count is less than or equal to zero. + * ERANGE semaphore count is too big + * + * ------------------------------------------------------ + */ +{ + int result = 0; + long waiters; + sem_t s = *sem; + + if (s == NULL || count <= 0) + { + result = EINVAL; + } + else if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + result = EINVAL; + return -1; + } + + if (s->value <= (SEM_VALUE_MAX - count)) + { + waiters = -s->value; + s->value += count; + if (waiters > 0) + { +#if defined(NEED_SEM) + if (SetEvent(s->sem)) + { + waiters--; + s->leftToUnblock += count - 1; + if (s->leftToUnblock > waiters) + { + s->leftToUnblock = waiters; + } + } +#else + if (ReleaseSemaphore (s->sem, (waiters<=count)?waiters:count, 0)) + { + /* No action */ + } +#endif + else + { + s->value -= count; + result = EINVAL; + } + } + } + else + { + result = ERANGE; + } + (void) pthread_mutex_unlock (&s->lock); + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* sem_post_multiple */ diff --git a/libs/pthreads/src/sem_timedwait.c b/libs/pthreads/src/sem_timedwait.c new file mode 100644 index 0000000000..638431cf1f --- /dev/null +++ b/libs/pthreads/src/sem_timedwait.c @@ -0,0 +1,238 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_timedwait.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +typedef struct { + sem_t sem; + int * resultPtr; +} sem_timedwait_cleanup_args_t; + + +static void PTW32_CDECL +ptw32_sem_timedwait_cleanup (void * args) +{ + sem_timedwait_cleanup_args_t * a = (sem_timedwait_cleanup_args_t *)args; + sem_t s = a->sem; + + if (pthread_mutex_lock (&s->lock) == 0) + { + /* + * We either timed out or were cancelled. + * If someone has posted between then and now we try to take the semaphore. + * Otherwise the semaphore count may be wrong after we + * return. In the case of a cancellation, it is as if we + * were cancelled just before we return (after taking the semaphore) + * which is ok. + */ + if (WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0) + { + /* We got the semaphore on the second attempt */ + *(a->resultPtr) = 0; + } + else + { + /* Indicate we're no longer waiting */ + s->value++; +#if defined(NEED_SEM) + if (s->value > 0) + { + s->leftToUnblock = 0; + } +#else + /* + * Don't release the W32 sema, it doesn't need adjustment + * because it doesn't record the number of waiters. + */ +#endif + } + (void) pthread_mutex_unlock (&s->lock); + } +} + + +int +sem_timedwait (sem_t * sem, const struct timespec *abstime) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a semaphore possibly until + * 'abstime' time. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * abstime + * pointer to an instance of struct timespec + * + * DESCRIPTION + * This function waits on a semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * the calling thread (or process) is blocked until it can + * successfully decrease the value or until interrupted by + * a signal. + * + * If 'abstime' is a NULL pointer then this function will + * block until it can successfully decrease the value or + * until interrupted by a signal. + * + * RESULTS + * 0 successfully decreased semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * ETIMEDOUT abstime elapsed before success. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + pthread_testcancel(); + + if (sem == NULL) + { + result = EINVAL; + } + else + { + DWORD milliseconds; + + if (abstime == NULL) + { + milliseconds = INFINITE; + } + else + { + /* + * Calculate timeout as milliseconds from current system time. + */ + milliseconds = ptw32_relmillisecs (abstime); + } + + if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + int v; + + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + v = --s->value; + (void) pthread_mutex_unlock (&s->lock); + + if (v < 0) + { +#if defined(NEED_SEM) + int timedout; +#endif + sem_timedwait_cleanup_args_t cleanup_args; + + cleanup_args.sem = s; + cleanup_args.resultPtr = &result; + +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth(0) +#endif + /* Must wait */ + pthread_cleanup_push(ptw32_sem_timedwait_cleanup, (void *) &cleanup_args); +#if defined(NEED_SEM) + timedout = +#endif + result = pthreadCancelableTimedWait (s->sem, milliseconds); + pthread_cleanup_pop(result); +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth() +#endif + +#if defined(NEED_SEM) + + if (!timedout && pthread_mutex_lock (&s->lock) == 0) + { + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + if (s->leftToUnblock > 0) + { + --s->leftToUnblock; + SetEvent(s->sem); + } + (void) pthread_mutex_unlock (&s->lock); + } + +#endif /* NEED_SEM */ + + } + } + + } + + if (result != 0) + { + + errno = result; + return -1; + + } + + return 0; + +} /* sem_timedwait */ diff --git a/libs/pthreads/src/sem_trywait.c b/libs/pthreads/src/sem_trywait.c new file mode 100644 index 0000000000..63614ba2b8 --- /dev/null +++ b/libs/pthreads/src/sem_trywait.c @@ -0,0 +1,117 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_trywait.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +int +sem_trywait (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function tries to wait on a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function tries to wait on a semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * this function returns immediately with the error EAGAIN + * + * RESULTS + * 0 successfully decreased semaphore, + * -1 failed, error in errno + * ERRNO + * EAGAIN the semaphore was already locked, + * EINVAL 'sem' is not a valid semaphore, + * ENOTSUP sem_trywait is not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + if (s == NULL) + { + result = EINVAL; + } + else if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + if (s->value > 0) + { + s->value--; + } + else + { + result = EAGAIN; + } + + (void) pthread_mutex_unlock (&s->lock); + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* sem_trywait */ diff --git a/libs/pthreads/src/sem_unlink.c b/libs/pthreads/src/sem_unlink.c new file mode 100644 index 0000000000..fb80569a0a --- /dev/null +++ b/libs/pthreads/src/sem_unlink.c @@ -0,0 +1,58 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_unlink.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + +/* ignore warning "unreferenced formal parameter" */ +#if defined(_MSC_VER) +#pragma warning( disable : 4100 ) +#endif + +int +sem_unlink (const char *name) +{ + errno = ENOSYS; + return -1; +} /* sem_unlink */ diff --git a/libs/pthreads/src/sem_wait.c b/libs/pthreads/src/sem_wait.c new file mode 100644 index 0000000000..50c11d8080 --- /dev/null +++ b/libs/pthreads/src/sem_wait.c @@ -0,0 +1,187 @@ +/* + * ------------------------------------------------------------- + * + * Module: sem_wait.c + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +static void PTW32_CDECL +ptw32_sem_wait_cleanup(void * sem) +{ + sem_t s = (sem_t) sem; + + if (pthread_mutex_lock (&s->lock) == 0) + { + /* + * If sema is destroyed do nothing, otherwise:- + * If the sema is posted between us being cancelled and us locking + * the sema again above then we need to consume that post but cancel + * anyway. If we don't get the semaphore we indicate that we're no + * longer waiting. + */ + if (*((sem_t *)sem) != NULL && !(WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0)) + { + ++s->value; +#if defined(NEED_SEM) + if (s->value > 0) + { + s->leftToUnblock = 0; + } +#else + /* + * Don't release the W32 sema, it doesn't need adjustment + * because it doesn't record the number of waiters. + */ +#endif /* NEED_SEM */ + } + (void) pthread_mutex_unlock (&s->lock); + } +} + +int +sem_wait (sem_t * sem) + /* + * ------------------------------------------------------ + * DOCPUBLIC + * This function waits on a semaphore. + * + * PARAMETERS + * sem + * pointer to an instance of sem_t + * + * DESCRIPTION + * This function waits on a semaphore. If the + * semaphore value is greater than zero, it decreases + * its value by one. If the semaphore value is zero, then + * the calling thread (or process) is blocked until it can + * successfully decrease the value or until interrupted by + * a signal. + * + * RESULTS + * 0 successfully decreased semaphore, + * -1 failed, error in errno + * ERRNO + * EINVAL 'sem' is not a valid semaphore, + * ENOSYS semaphores are not supported, + * EINTR the function was interrupted by a signal, + * EDEADLK a deadlock condition was detected. + * + * ------------------------------------------------------ + */ +{ + int result = 0; + sem_t s = *sem; + + pthread_testcancel(); + + if (s == NULL) + { + result = EINVAL; + } + else + { + if ((result = pthread_mutex_lock (&s->lock)) == 0) + { + int v; + + /* See sem_destroy.c + */ + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + v = --s->value; + (void) pthread_mutex_unlock (&s->lock); + + if (v < 0) + { +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth(0) +#endif + /* Must wait */ + pthread_cleanup_push(ptw32_sem_wait_cleanup, (void *) s); + result = pthreadCancelableWait (s->sem); + /* Cleanup if we're canceled or on any other error */ + pthread_cleanup_pop(result); +#if defined(_MSC_VER) && _MSC_VER < 1400 +#pragma inline_depth() +#endif + } +#if defined(NEED_SEM) + + if (!result && pthread_mutex_lock (&s->lock) == 0) + { + if (*sem == NULL) + { + (void) pthread_mutex_unlock (&s->lock); + errno = EINVAL; + return -1; + } + + if (s->leftToUnblock > 0) + { + --s->leftToUnblock; + SetEvent(s->sem); + } + (void) pthread_mutex_unlock (&s->lock); + } + +#endif /* NEED_SEM */ + + } + + } + + if (result != 0) + { + errno = result; + return -1; + } + + return 0; + +} /* sem_wait */ diff --git a/libs/pthreads/src/semaphore.c b/libs/pthreads/src/semaphore.c new file mode 100644 index 0000000000..64fc0e366d --- /dev/null +++ b/libs/pthreads/src/semaphore.c @@ -0,0 +1,69 @@ +/* + * ------------------------------------------------------------- + * + * Module: semaphore.c + * + * Purpose: + * Concatenated version of separate modules to allow + * inlining optimisation, which it is assumed can only + * be effective within a single module. + * + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * ------------------------------------------------------------- + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#if !defined(NEED_FTIME) +# include +#endif + +#include + +#include "pthread.h" +#include "semaphore.h" +#include "implement.h" + + +#include "sem_init.c" +#include "sem_destroy.c" +#include "sem_trywait.c" +#include "sem_wait.c" +#include "sem_timedwait.c" +#include "sem_post.c" +#include "sem_post_multiple.c" +#include "sem_getvalue.c" +#include "sem_open.c" +#include "sem_close.c" +#include "sem_unlink.c" diff --git a/libs/pthreads/src/semaphore.h b/libs/pthreads/src/semaphore.h new file mode 100644 index 0000000000..c6e9407e25 --- /dev/null +++ b/libs/pthreads/src/semaphore.h @@ -0,0 +1,169 @@ +/* + * Module: semaphore.h + * + * Purpose: + * Semaphores aren't actually part of the PThreads standard. + * They are defined by the POSIX Standard: + * + * POSIX 1003.1b-1993 (POSIX.1b) + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined( SEMAPHORE_H ) +#define SEMAPHORE_H + +#undef PTW32_SEMAPHORE_LEVEL + +#if defined(_POSIX_SOURCE) +#define PTW32_SEMAPHORE_LEVEL 0 +/* Early POSIX */ +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 +#undef PTW32_SEMAPHORE_LEVEL +#define PTW32_SEMAPHORE_LEVEL 1 +/* Include 1b, 1c and 1d */ +#endif + +#if defined(INCLUDE_NP) +#undef PTW32_SEMAPHORE_LEVEL +#define PTW32_SEMAPHORE_LEVEL 2 +/* Include Non-Portable extensions */ +#endif + +#define PTW32_SEMAPHORE_LEVEL_MAX 3 + +#if !defined(PTW32_SEMAPHORE_LEVEL) +#define PTW32_SEMAPHORE_LEVEL PTW32_SEMAPHORE_LEVEL_MAX +/* Include everything */ +#endif + +#if defined(__GNUC__) && ! defined (__declspec) +# error Please upgrade your GNU compiler to one that supports __declspec. +#endif + +/* + * When building the library, you should define PTW32_BUILD so that + * the variables/functions are exported correctly. When using the library, + * do NOT define PTW32_BUILD, and then the variables/functions will + * be imported correctly. + */ +#if !defined(PTW32_STATIC_LIB) +# if defined(PTW32_BUILD) +# define PTW32_DLLPORT __declspec (dllexport) +# else +# define PTW32_DLLPORT __declspec (dllimport) +# endif +#else +# define PTW32_DLLPORT +#endif + +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#if !defined(PTW32_CONFIG_H) +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(__MINGW64__) +# define HAVE_STRUCT_TIMESPEC +# define HAVE_MODE_T +# elif defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#if PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX +#if defined(NEED_ERRNO) +#include "need_errno.h" +#else +#include +#endif +#endif /* PTW32_SEMAPHORE_LEVEL >= PTW32_SEMAPHORE_LEVEL_MAX */ + +#define _POSIX_SEMAPHORES + +#if defined(__cplusplus) +extern "C" +{ +#endif /* __cplusplus */ + +#if !defined(HAVE_MODE_T) +typedef unsigned int mode_t; +#endif + + +typedef struct sem_t_ * sem_t; + +PTW32_DLLPORT int __cdecl sem_init (sem_t * sem, + int pshared, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_destroy (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_trywait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_wait (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_timedwait (sem_t * sem, + const struct timespec * abstime); + +PTW32_DLLPORT int __cdecl sem_post (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_post_multiple (sem_t * sem, + int count); + +PTW32_DLLPORT int __cdecl sem_open (const char * name, + int oflag, + mode_t mode, + unsigned int value); + +PTW32_DLLPORT int __cdecl sem_close (sem_t * sem); + +PTW32_DLLPORT int __cdecl sem_unlink (const char * name); + +PTW32_DLLPORT int __cdecl sem_getvalue (sem_t * sem, + int * sval); + +#if defined(__cplusplus) +} /* End of extern "C" */ +#endif /* __cplusplus */ + +#undef PTW32_SEMAPHORE_LEVEL +#undef PTW32_SEMAPHORE_LEVEL_MAX + +#endif /* !SEMAPHORE_H */ diff --git a/libs/pthreads/src/signal.c b/libs/pthreads/src/signal.c new file mode 100644 index 0000000000..eef466962b --- /dev/null +++ b/libs/pthreads/src/signal.c @@ -0,0 +1,179 @@ +/* + * signal.c + * + * Description: + * Thread-aware signal functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * Possible future strategy for implementing pthread_kill() + * ======================================================== + * + * Win32 does not implement signals. + * Signals are simply software interrupts. + * pthread_kill() asks the system to deliver a specified + * signal (interrupt) to a specified thread in the same + * process. + * Signals are always asynchronous (no deferred signals). + * Pthread-win32 has an async cancelation mechanism. + * A similar system can be written to deliver signals + * within the same process (on ix86 processors at least). + * + * Each thread maintains information about which + * signals it will respond to. Handler routines + * are set on a per-process basis - not per-thread. + * When signalled, a thread will check it's sigmask + * and, if the signal is not being ignored, call the + * handler routine associated with the signal. The + * thread must then (except for some signals) return to + * the point where it was interrupted. + * + * Ideally the system itself would check the target thread's + * mask before possibly needlessly bothering the thread + * itself. This could be done by pthread_kill(), that is, + * in the signaling thread since it has access to + * all pthread_t structures. It could also retrieve + * the handler routine address to minimise the target + * threads response overhead. This may also simplify + * serialisation of the access to the per-thread signal + * structures. + * + * pthread_kill() eventually calls a routine similar to + * ptw32_cancel_thread() which manipulates the target + * threads processor context to cause the thread to + * run the handler launcher routine. pthread_kill() must + * save the target threads current context so that the + * handler launcher routine can restore the context after + * the signal handler has returned. Some handlers will not + * return, eg. the default SIGKILL handler may simply + * call pthread_exit(). + * + * The current context is saved in the target threads + * pthread_t structure. + */ + +#include "pthread.h" +#include "implement.h" + +#if defined(HAVE_SIGSET_T) + +static void +ptw32_signal_thread () +{ +} + +static void +ptw32_signal_callhandler () +{ +} + +int +pthread_sigmask (int how, sigset_t const *set, sigset_t * oset) +{ + pthread_t thread = pthread_self (); + + if (thread.p == NULL) + { + return ENOENT; + } + + /* Validate the `how' argument. */ + if (set != NULL) + { + switch (how) + { + case SIG_BLOCK: + break; + case SIG_UNBLOCK: + break; + case SIG_SETMASK: + break; + default: + /* Invalid `how' argument. */ + return EINVAL; + } + } + + /* Copy the old mask before modifying it. */ + if (oset != NULL) + { + memcpy (oset, &(thread.p->sigmask), sizeof (sigset_t)); + } + + if (set != NULL) + { + unsigned int i; + + /* FIXME: this code assumes that sigmask is an even multiple of + the size of a long integer. */ + + unsigned long *src = (unsigned long const *) set; + unsigned long *dest = (unsigned long *) &(thread.p->sigmask); + + switch (how) + { + case SIG_BLOCK: + for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++) + { + /* OR the bit field longword-wise. */ + *dest++ |= *src++; + } + break; + case SIG_UNBLOCK: + for (i = 0; i < (sizeof (sigset_t) / sizeof (unsigned long)); i++) + { + /* XOR the bitfield longword-wise. */ + *dest++ ^= *src++; + } + case SIG_SETMASK: + /* Replace the whole sigmask. */ + memcpy (&(thread.p->sigmask), set, sizeof (sigset_t)); + break; + } + } + + return 0; +} + +int +sigwait (const sigset_t * set, int *sig) +{ + /* This routine is a cancellation point */ + pthread_test_cancel(); +} + +int +sigaction (int signum, const struct sigaction *act, struct sigaction *oldact) +{ +} + +#endif /* HAVE_SIGSET_T */ diff --git a/libs/pthreads/src/spin.c b/libs/pthreads/src/spin.c new file mode 100644 index 0000000000..41b5aa5251 --- /dev/null +++ b/libs/pthreads/src/spin.c @@ -0,0 +1,46 @@ +/* + * spin.c + * + * Description: + * This translation unit implements spin lock primitives. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "ptw32_spinlock_check_need_init.c" +#include "pthread_spin_init.c" +#include "pthread_spin_destroy.c" +#include "pthread_spin_lock.c" +#include "pthread_spin_unlock.c" +#include "pthread_spin_trylock.c" diff --git a/libs/pthreads/src/sync.c b/libs/pthreads/src/sync.c new file mode 100644 index 0000000000..5e56fa9a1f --- /dev/null +++ b/libs/pthreads/src/sync.c @@ -0,0 +1,43 @@ +/* + * sync.c + * + * Description: + * This translation unit implements functions related to thread + * synchronisation. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_detach.c" +#include "pthread_join.c" diff --git a/libs/pthreads/src/tsd.c b/libs/pthreads/src/tsd.c new file mode 100644 index 0000000000..ed44fe6cb4 --- /dev/null +++ b/libs/pthreads/src/tsd.c @@ -0,0 +1,44 @@ +/* + * tsd.c + * + * Description: + * POSIX thread functions which implement thread-specific data (TSD). + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +#include "pthread_key_create.c" +#include "pthread_key_delete.c" +#include "pthread_setspecific.c" +#include "pthread_getspecific.c" diff --git a/libs/pthreads/src/w32_CancelableWait.c b/libs/pthreads/src/w32_CancelableWait.c new file mode 100644 index 0000000000..070633e0f9 --- /dev/null +++ b/libs/pthreads/src/w32_CancelableWait.c @@ -0,0 +1,161 @@ +/* + * w32_CancelableWait.c + * + * Description: + * This translation unit implements miscellaneous thread functions. + * + * -------------------------------------------------------------------------- + * + * Pthreads-win32 - POSIX Threads Library for Win32 + * Copyright(C) 1998 John E. Bossom + * Copyright(C) 1999,2005 Pthreads-win32 contributors + * + * Contact Email: rpj@callisto.canberra.edu.au + * + * The current list of contributors is contained + * in the file CONTRIBUTORS included with the source + * code distribution. The list can also be seen at the + * following World Wide Web location: + * http://sources.redhat.com/pthreads-win32/contributors.html + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library in the file COPYING.LIB; + * if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include "pthread.h" +#include "implement.h" + + +static INLINE int +ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout) + /* + * ------------------------------------------------------------------- + * This provides an extra hook into the pthread_cancel + * mechanism that will allow you to wait on a Windows handle and make it a + * cancellation point. This function blocks until the given WIN32 handle is + * signaled or pthread_cancel has been called. It is implemented using + * WaitForMultipleObjects on 'waitHandle' and a manually reset WIN32 + * event used to implement pthread_cancel. + * + * Given this hook it would be possible to implement more of the cancellation + * points. + * ------------------------------------------------------------------- + */ +{ + int result; + pthread_t self; + ptw32_thread_t * sp; + HANDLE handles[2]; + DWORD nHandles = 1; + DWORD status; + + handles[0] = waitHandle; + + self = pthread_self(); + sp = (ptw32_thread_t *) self.p; + + if (sp != NULL) + { + /* + * Get cancelEvent handle + */ + if (sp->cancelState == PTHREAD_CANCEL_ENABLE) + { + + if ((handles[1] = sp->cancelEvent) != NULL) + { + nHandles++; + } + } + } + else + { + handles[1] = NULL; + } + + status = WaitForMultipleObjects (nHandles, handles, PTW32_FALSE, timeout); + + switch (status - WAIT_OBJECT_0) + { + case 0: + /* + * Got the handle. + * In the event that both handles are signalled, the smallest index + * value (us) is returned. As it has been arranged, this ensures that + * we don't drop a signal that we should act on (i.e. semaphore, + * mutex, or condition variable etc). + */ + result = 0; + break; + + case 1: + /* + * Got cancel request. + * In the event that both handles are signaled, the cancel will + * be ignored (see case 0 comment). + */ + ResetEvent (handles[1]); + + if (sp != NULL) + { + ptw32_mcs_local_node_t stateLock; + /* + * Should handle POSIX and implicit POSIX threads.. + * Make sure we haven't been async-canceled in the meantime. + */ + ptw32_mcs_lock_acquire (&sp->stateLock, &stateLock); + if (sp->state < PThreadStateCanceling) + { + sp->state = PThreadStateCanceling; + sp->cancelState = PTHREAD_CANCEL_DISABLE; + ptw32_mcs_lock_release (&stateLock); + ptw32_throw (PTW32_EPS_CANCEL); + + /* Never reached */ + } + ptw32_mcs_lock_release (&stateLock); + } + + /* Should never get to here. */ + result = EINVAL; + break; + + default: + if (status == WAIT_TIMEOUT) + { + result = ETIMEDOUT; + } + else + { + result = EINVAL; + } + break; + } + + return (result); + +} /* CancelableWait */ + +int +pthreadCancelableWait (HANDLE waitHandle) +{ + return (ptw32_cancelable_wait (waitHandle, INFINITE)); +} + +int +pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout) +{ + return (ptw32_cancelable_wait (waitHandle, timeout)); +} -- cgit v1.2.3