crawl, fixes

This commit is contained in:
Pascal Engélibert 2025-12-19 16:50:56 +01:00
commit f5145f80ea
7 changed files with 326 additions and 58 deletions

View file

@ -158,6 +158,33 @@ sudo make install
* https://www.haproxy.com/blog/state-of-ssl-stacks * https://www.haproxy.com/blog/state-of-ssl-stacks
* 2025 * 2025
* OpenSSL * OpenSSL
* https://ieeexplore.ieee.org/abstract/document/5983970
* TLS and energy consumption on a mobile device: A measurement study
* 2011
* TLS
* Nokia phone
* https://dspace.mit.edu/handle/1721.1/111861
* Energy-efficient protocols and hardware architectures for transport layer security
* 2017
* https://dl.acm.org/doi/abs/10.1145/871506.871518
* Analyzing the energy consumption of security protocols
* 2003
* SSL
* https://ieeexplore.ieee.org/abstract/document/1563998
* A study of the energy consumption characteristics of cryptographic algorithms and security protocols
* 2003
* SSL
* https://ieeexplore.ieee.org/abstract/document/8598334
* Energy and Processing Demand Analysis of TLS Protocol in Internet of Things Applications
* 2016
* TLS
* https://dl.acm.org/doi/10.1145/3345768.3355924
* A Comprehensive Empirical Analysis of TLS Handshake and Record Layer on IoT Platforms
* 2019
* IoT, TLS
* https://hal.science/hal-04197885/document
* Empreinte carbone de la transmission de données sur le backbone RENATER
* 2021
## Sources ## Sources
@ -290,11 +317,12 @@ sudo chmod +s /sbin/sa
Install OpenSSL with debug symbols: Install OpenSSL with debug symbols:
```bash ```bash
#./Configure --release -g
# Options from Debian build # Options from Debian build
# Debian package libssl3t64 -> Developer Information -> buildd reproducibility -> trixie rbuild # Debian package libssl3t64 -> Developer Information -> buildd reproducibility -> trixie rbuild
# https://tests.reproducible-builds.org/debian/rb-pkg/trixie/amd64/openssl.html # https://tests.reproducible-builds.org/debian/rb-pkg/trixie/amd64/openssl.html
/usr/bin/perl ./Configure --release -g --prefix=/usr --openssldir=/usr/lib/ssl --libdir=lib/x86_64-linux-gnu shared no-idea no-mdc2 no-rc5 no-ssl3 no-ssl3-method enable-rfc3779 enable-cms no-capieng no-rdrand enable-tfo enable-zstd enable-zlib enable-fips enable-ec_nistp_64_gcc_128 /usr/bin/perl ./Configure --release -g --prefix=/usr --openssldir=/usr/lib/ssl --libdir=lib/x86_64-linux-gnu shared no-idea no-mdc2 no-rc5 no-ssl3 no-ssl3-method enable-rfc3779 enable-cms no-capieng no-rdrand enable-tfo enable-zstd enable-zlib enable-fips enable-ec_nistp_64_gcc_128
# Or, if OpenSSL 1.1:
/usr/bin/perl ./Configure --release -g --prefix=/usr --openssldir=/usr/lib/ssl --libdir=lib/x86_64-linux-gnu shared no-idea no-mdc2 no-rc5 no-ssl3 no-ssl3-method enable-rfc3779 enable-cms no-capieng no-rdrand enable-zlib enable-ec_nistp_64_gcc_128 linux-x86_64
``` ```
Backup your system's `libcrypto.so` and `libssl.so` and replace them with the new ones. Backup your system's `libcrypto.so` and `libssl.so` and replace them with the new ones.
@ -330,3 +358,17 @@ Avant d'enregistrer le trafic, il faut observer les domaines utilisés puis gén
CertVerify est l'extension dans le ServerHello qui signe la discussion passée avec la clé secrète du certificat. CertVerify est l'extension dans le ServerHello qui signe la discussion passée avec la clé secrète du certificat.
Il a fallu désactiver la réutilisation de session, qui en TLS1.3 passe par le PSK, pour pouvoir mesurer le CertVerify. Il a fallu désactiver la réutilisation de session, qui en TLS1.3 passe par le PSK, pour pouvoir mesurer le CertVerify.
## Size overhead and usage survey
```bash
openssl s_server -port 8000 -cert /dev/shm/exp/certs/prime256v1/wikipedia.org.crt -key /dev/shm/exp/certs/prime256v1/wikipedia.org.key
curl https://wikipedia.org --tlsv1.3 --curves x25519 --connect-to wikipedia.org:443:127.0.0.1:8000 -k
```
Get the most used domains here https://www.akamai.com/fr/security-research/akarank
```bash
python crawler.py crawl /dev/shm/top1K.csv
python crawler.py stat /dev/shm/crawl.json
```

94
crawler.py Normal file
View file

@ -0,0 +1,94 @@
import json,re, subprocess, sys, threading, time
BATCH = 50
TIMEOUT = 4
CAPTURES = {
"read_bytes": "SSL handshake has read (\\d+) bytes and written \\d+ bytes\n",
"written_bytes": "SSL handshake has read \\d+ bytes and written (\\d+) bytes\n",
"cert_sig": "Peer signature type: ([a-zA-Z0-9_.-]+)\n",
"cert_pk_size": "Server public key is (\\d+) bit\n",
"kx": "(?:Negotiated TLS1\\.3 group|Peer Temp Key): ([a-zA-Z0-9_.-]+)(?:\n|,)",
"cipher": "Cipher is ([a-zA-Z0-9_.-]+)\n",
"protocol": "Protocol: ([a-zA-Z0-9_.-]+)\n",
}
lock = threading.Lock()
results = {}
subs = []
def probe(domain, ossl):
# End of input data, cleanly stops the session and the process
ossl.stdin.write(b"")
ossl.stdin.close()
results[domain] = output = ossl.stdout.read().decode()
ossl.kill()
if __name__ == "__main__":
if sys.argv[1] == "crawl":
threads = []
f = open(sys.argv[2], "r")
for line in f.readlines()[1:]:
#line = line.removesuffix("\n")
line = line[:line.find(",")-1]
print("start", line)
addr = f"{line}:443"
ossl = subprocess.Popen(["openssl", "s_client", "-no-interactive", addr], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
t = threading.Thread(target=probe, args=(line, ossl,))
threads.append((t, ossl, time.time()))
time.sleep(0.05)
t.start()
if len(threads) >= BATCH:
print("wait")
for (t, ossl, start) in threads:
t.join(max(0, TIMEOUT - (time.time() - start)))
try:
ossl.kill()
except:
pass
threads.clear()
print("waited")
f.close()
for (t, ossl, start) in threads:
t.join(max(0, TIMEOUT - (time.time() - start)))
try:
ossl.kill()
except:
pass
threads.clear()
print("finished")
f = open("/dev/shm/crawl.json", "w")
json.dump(results, f)
f.close()
print("written")
sys.exit(0)
elif sys.argv[1] == "stat":
regexes = {}
for r in CAPTURES:
regexes[r] = re.compile(CAPTURES[r])
stats = {}
f = open(sys.argv[2], "r")
c = json.load(f)
for domain in c:
for r in CAPTURES:
try:
val = regexes[r].finditer(c[domain]).__next__().group(1)
#print(r, val)
if r in ["domain", "read_bytes", "written_bytes"]:
continue
if not r in stats:
stats[r] = {}
if not val in stats[r]:
stats[r][val] = 1
else:
stats[r][val] += 1
except StopIteration:
pass
#print("Not found:", line, r)
print(stats)

111
exp.py
View file

@ -2,18 +2,49 @@
import os, sys, subprocess import os, sys, subprocess
CONFIGS = { CONFIGS = {
# placid -> pi3 # i7-4790 local
"pi": { "local": {
"experiments": [ "experiments": [
"impl-cipher-ver", "impl-cipher-ver",
"impl-cert-ver", "impl-cert-ver",
"impl-kex-ver", "impl-kex-ver",
], ],
"setups": [
"none-local",
"client-local",
"server-local",
],
"records": [
{ "filename": "youtube", "repeat": 1 },
],
"repodir": "/home/tuxmain/reps/tlsbench",
"expdir": "/dev/shm/exp",
"log_backup_dir": "/home/tuxmain",
"p2_hostname": "localhost",
"p2_addr": "127.0.0.1",
"p2_repodir": "/home/tuxmain/reps/tlsbench",
"wattmeter": False,
"perf": True,
"perf_dir": "/home/tuxmain/.cache/exp",
"p3_suffix": ".localhost",
"p3_port_plain": 8080,
"p3_port_tls": 8443,
},
# i7-4790 -> pi3
"pi3": {
"experiments": [
#"impl-cipher-ver",
"impl-cert-ver",
#"impl-kex-ver",
],
"setups": [ "setups": [
"none", "none",
"client", "client",
"server", "server",
], ],
"records": [
{ "filename": "youtube", "repeat": 100 },
],
"repodir": "/home/tuxmain/reps/tlsbench", "repodir": "/home/tuxmain/reps/tlsbench",
"expdir": "/dev/shm/exp", "expdir": "/dev/shm/exp",
"log_backup_dir": "/home/tuxmain", "log_backup_dir": "/home/tuxmain",
@ -29,8 +60,7 @@ CONFIGS = {
"p3_port_tls": 443, "p3_port_tls": 443,
"idle": "idle - - - - - - 600.000081539154 0.0 896 4792 0.5399999999999991 -", "idle": "idle - - - - - - 600.000081539154 0.0 896 4792 0.5399999999999991 -",
}, },
# placid local "pi3-local": {
"local": {
"experiments": [ "experiments": [
"impl-cipher-ver", "impl-cipher-ver",
"impl-cert-ver", "impl-cert-ver",
@ -41,21 +71,24 @@ CONFIGS = {
"client-local", "client-local",
"server-local", "server-local",
], ],
"repodir": "/home/tuxmain/reps/tlsbench", "records": [
{ "filename": "wikipedia", "repeat": 5 },
],
"repodir": "/home/exp/exp",
"expdir": "/dev/shm/exp", "expdir": "/dev/shm/exp",
"log_backup_dir": "/home/tuxmain", "log_backup_dir": "/home/exp",
"p2_hostname": "localhost", "p2_hostname": "localhost",
"p2_addr": "127.0.0.1", "p2_addr": "127.0.0.1",
"p2_repodir": "/home/tuxmain/reps/tlsbench", "p2_repodir": "/home/exp/exp",
"wattmeter": False, "wattmeter": False,
"perf": True, "perf": True,
"perf_dir": "/home/tuxmain/.cache/exp", "perf_dir": "/home/exp/.cache/exp",
"p3_suffix": ".localhost", "p3_suffix": ".localhost",
"p3_port_plain": 8080, "p3_port_plain": 8080,
"p3_port_tls": 8443, "p3_port_tls": 8443,
}, },
# placid -> pifou # i7-4790 -> core2
"pifou": { "core2": {
"experiments": [ "experiments": [
"impl-cipher-ver", "impl-cipher-ver",
"impl-cert-ver", "impl-cert-ver",
@ -66,13 +99,17 @@ CONFIGS = {
"client", "client",
"server", "server",
], ],
"records": [
{ "filename": "wikipedia", "repeat": 400 },
{ "filename": "youtube", "repeat": 100 },
],
"repodir": "/home/tuxmain/reps/tlsbench", "repodir": "/home/tuxmain/reps/tlsbench",
"expdir": "/dev/shm/exp", "expdir": "/dev/shm/exp",
"log_backup_dir": "/home/tuxmain", "log_backup_dir": "/home/tuxmain",
"p2_hostname": "192.168.3.3", "p2_hostname": "192.168.3.3",
"p2_addr": "192.168.3.3", "p2_addr": "192.168.3.3",
"p2_ssh": "exp@192.168.3.3", "p2_ssh": "exp@192.168.3.3",
"p2_psw": "exp", "p2_psw": None,
"p2_repodir": "/home/exp/exp", "p2_repodir": "/home/exp/exp",
"wattmeter": True, "wattmeter": True,
"perf": False, "perf": False,
@ -81,8 +118,7 @@ CONFIGS = {
"p3_port_tls": 443, "p3_port_tls": 443,
"idle": "idle - - - - - - 600.0001013278961 0.0 735 4942 1.7759999999999962 -", "idle": "idle - - - - - - 600.0001013278961 0.0 735 4942 1.7759999999999962 -",
}, },
# placid local "core2-local": {
"pifou-local": {
"experiments": [ "experiments": [
"impl-cipher-ver", "impl-cipher-ver",
"impl-cert-ver", "impl-cert-ver",
@ -93,6 +129,9 @@ CONFIGS = {
"client-local", "client-local",
"server-local", "server-local",
], ],
"records": [
{ "filename": "wikipedia", "repeat": 10 },
],
"repodir": "/home/exp/exp", "repodir": "/home/exp/exp",
"expdir": "/dev/shm/exp", "expdir": "/dev/shm/exp",
"log_backup_dir": "/home/exp", "log_backup_dir": "/home/exp",
@ -132,13 +171,6 @@ DOMAINS_ = [
"videos.domainepublic.net", "videos.domainepublic.net",
] ]
RECORDS = [
#{ "filename": "youtube", "repeat": 100 },
#{ "filename": "peertube", "repeat": 10 },
{ "filename": "wikipedia", "repeat": 400 },
#{ "filename": "apple", "repeat": 1000 },
#{ "filename": "google", "repeat": 1000 },
]
CERT_SIGN_ALGS = [ CERT_SIGN_ALGS = [
"prime256v1", # widely used "prime256v1", # widely used
"secp384r1", # rarely used but supported by browsers because it's NIST standard "secp384r1", # rarely used but supported by browsers because it's NIST standard
@ -146,7 +178,7 @@ CERT_SIGN_ALGS = [
"rsa2048", "rsa3072", "rsa4096", # widely used "rsa2048", "rsa3072", "rsa4096", # widely used
] ]
IMPLS = [ IMPLS = [
"aws_lc_rs", # Amazon's Rust crypto widely used in Rust stuff "aws_lc", # Amazon's Rust crypto widely used in Rust stuff
"boring", # Google's fork of OpenSSL used in Chrome and Android "boring", # Google's fork of OpenSSL used in Chrome and Android
"openssl", # widely used "openssl", # widely used
"ring", # used in most Rust stuff "ring", # used in most Rust stuff
@ -171,6 +203,9 @@ KEXES = [
"X25519", "X25519",
"SECP256R1", "SECP256R1",
"SECP384R1", "SECP384R1",
"X25519MLKEM768",
"SECP256R1MLKEM768",
"MLKEM768",
] ]
# Testing all combinations would be too much. Instead we isolate independent parts. # Testing all combinations would be too much. Instead we isolate independent parts.
@ -178,7 +213,6 @@ EXPERIMENTS = {
# Compare ciphers among implementations and TLS versions # Compare ciphers among implementations and TLS versions
"impl-cipher-ver": { "impl-cipher-ver": {
"impls": IMPLS, "impls": IMPLS,
"records": RECORDS,
"ciphers": [ "ciphers": [
"AES_128_GCM_SHA256", "AES_128_GCM_SHA256",
"AES_256_GCM_SHA384", "AES_256_GCM_SHA384",
@ -193,7 +227,6 @@ EXPERIMENTS = {
# Compare signatures among implementations and TLS versions # Compare signatures among implementations and TLS versions
"impl-cert-ver": { "impl-cert-ver": {
"impls": IMPLS, "impls": IMPLS,
"records": RECORDS,
"ciphers": [ "ciphers": [
"AES_128_GCM_SHA256", "AES_128_GCM_SHA256",
#"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256", #"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
@ -210,17 +243,22 @@ EXPERIMENTS = {
# Compare key exchange groups among implementations and TLS versions # Compare key exchange groups among implementations and TLS versions
"impl-kex-ver": { "impl-kex-ver": {
"impls": IMPLS, "impls": IMPLS,
"records": RECORDS,
"ciphers": [ "ciphers": [
"AES_128_GCM_SHA256", "AES_128_GCM_SHA256",
#"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256", #"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
], ],
"kexes": ["X25519", "SECP256R1", "SECP384R1"], "kexes": [
"X25519",
"SECP256R1",
"SECP384R1",
"X25519MLKEM768",
"SECP256R1MLKEM768",
"MLKEM768",
],
"cert": ["prime256v1"], "cert": ["prime256v1"],
}, },
"debug": { "debug": {
"impls": IMPLS, "impls": IMPLS,
"records": RECORDS,
"ciphers": [ "ciphers": [
"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256", "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
#"ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", #"ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
@ -230,6 +268,16 @@ EXPERIMENTS = {
}, },
} }
# Some algorithms are not available in all implementations
def alg_filter(kex, cert, cipher, impl):
if "MLKEM" in kex and impl != "openssl" and impl != "aws_lc":
return False
if kex == "SECP256R1MLKEM768" and impl == "openssl":
return False
if cert == "secp384r1" and impl == "boring":
return False
return True
DOMAINS = [] DOMAINS = []
for domain in DOMAINS_: for domain in DOMAINS_:
if not domain in DOMAINS: if not domain in DOMAINS:
@ -644,11 +692,13 @@ def run_exp(config, only_record=None, idle=False):
ssh_run(ssh, f"python {p2_path}/exp.py cert {config_name} {alg}") ssh_run(ssh, f"python {p2_path}/exp.py cert {config_name} {alg}")
for kex in exp["kexes"]: for kex in exp["kexes"]:
for cipher in exp["ciphers"]: for cipher in exp["ciphers"]:
if not alg_filter(kex, alg, cipher, impl):
continue
for setup in config["setups"]: for setup in config["setups"]:
if SETUPS[setup]["tls_invariant"] and not first_set: if SETUPS[setup]["tls_invariant"] and not first_set:
continue continue
setupdir = expdir+"setups/"+setup setupdir = expdir+"setups/"+setup
for record in exp["records"]: for record in config["records"]:
print(f"EXPERIMENT {expname}: {impl} {alg} {kex} {cipher} {setup}") print(f"EXPERIMENT {expname}: {impl} {alg} {kex} {cipher} {setup}")
p2_rpxy_config = SETUPS[setup]["rpxy_config"] p2_rpxy_config = SETUPS[setup]["rpxy_config"]
vars = {"CIPHERS": cipher, "KEXES": kex, "RUST_LOG": "warning"} vars = {"CIPHERS": cipher, "KEXES": kex, "RUST_LOG": "warning"}
@ -703,7 +753,7 @@ def run_exp(config, only_record=None, idle=False):
#time.sleep(30) #time.sleep(30)
#sh("killall netreplay") #sh("killall netreplay")
try: try:
ssh_run(ssh, f"rm /dev/shm/access.log /dev/shm/rpxy.log") #ssh_run(ssh, f"rm /dev/shm/access.log /dev/shm/rpxy.log")
pass pass
except invoke.exceptions.UnexpectedExit as e: except invoke.exceptions.UnexpectedExit as e:
pass pass
@ -841,13 +891,14 @@ Run options:
exps = 0 exps = 0
for expname in config["experiments"]: for expname in config["experiments"]:
exp = config["experiments"][expname] exp = config["experiments"][expname]
exps += len(exp["impls"]) * len(exp["cert"]) * len(exp["kexes"]) * len(exp["ciphers"]) * len(exp["records"]) exps += len(exp["impls"]) * len(exp["cert"]) * len(exp["kexes"]) * len(exp["ciphers"]) * len(config["records"])
print("Experiments to make:", exps * len(config["setups"])) print("Experiments to make:", exps * len(config["setups"]))
exit(0) exit(0)
import time import time
import invoke
import re import re
if "p2_ssh" in config:
import invoke
import fabric import fabric
if config["wattmeter"]: if config["wattmeter"]:

View file

@ -61,7 +61,7 @@ CERT_SIGN_ALGS = [
"rsa2048", "rsa3072", "rsa4096", # widely used "rsa2048", "rsa3072", "rsa4096", # widely used
] ]
IMPLS = [ IMPLS = [
#"aws_lc_rs", # Amazon's Rust crypto widely used in Rust stuff #"aws_lc", # Amazon's Rust crypto widely used in Rust stuff
#"boring", # Google's fork of OpenSSL used in Chrome and Android #"boring", # Google's fork of OpenSSL used in Chrome and Android
#"openssl", # widely used #"openssl", # widely used
"ring", # used in most Rust stuff "ring", # used in most Rust stuff

113
plots.py
View file

@ -3,20 +3,23 @@ import profile
# Nice labels for algorithms of all kinds # Nice labels for algorithms of all kinds
ALG_LABEL = { ALG_LABEL = {
"AES_128_GCM_SHA256": "AES128", "AES_128_GCM_SHA256": "aes128",
"AES_256_GCM_SHA384": "AES256", "AES_256_GCM_SHA384": "aes256",
"CHACHA20_POLY1305_SHA256": "CHACHA20", "CHACHA20_POLY1305_SHA256": "chacha20",
"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256": "AES128", "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256": "aes128",
"ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,ECDHE_RSA_WITH_AES_256_GCM_SHA384": "AES256", "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,ECDHE_RSA_WITH_AES_256_GCM_SHA384": "aes256",
"ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": "CHACHA20", "ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": "chacha20",
"prime256v1": "prime256v1", "prime256v1": "p256",
"secp384r1": "secp384r1", "secp384r1": "p384",
"rsa2048": "rsa2048", "rsa2048": "rsa2048",
"rsa3072": "rsa3072", "rsa3072": "rsa3072",
"rsa4096": "rsa4096", "rsa4096": "rsa4096",
"X25519": "X25519", "X25519": "x25519",
"SECP256R1": "SECP256R1", "SECP256R1": "p256",
"SECP384R1": "SECP384R1" "SECP384R1": "p384",
"X25519MLKEM768": "x25519mlkem",
"SECP256R1MLKEM768": "p256mlkem",
"MLKEM768": "mlkem",
} }
# Nice labels for TLS versions using ciphers # Nice labels for TLS versions using ciphers
@ -56,6 +59,10 @@ CRITERION_TITLE = {
"kex": "key exchange" "kex": "key exchange"
} }
def impl_title(impl):
# Gnuplot does not escape underscores when generating tex
return impl.replace("_", "-")
# Where gnuplot files, data files and images are output # Where gnuplot files, data files and images are output
PLOTS_DIR = "/dev/shm/plots" PLOTS_DIR = "/dev/shm/plots"
@ -87,6 +94,9 @@ set grid y lt 1 lw .75 lc "gray"
plot \ plot \
newhistogram "", "{plots_dir}/{object}_by_{criterion}_{side}_{record}.dat" using 2:xticlabels(1) notitle col, \ newhistogram "", "{plots_dir}/{object}_by_{criterion}_{side}_{record}.dat" using 2:xticlabels(1) notitle col, \
newhistogram "", "{plots_dir}/{object}_by_{criterion}_{side}_{record}.dat" using 3:xticlabels(1) title col{cluster} newhistogram "", "{plots_dir}/{object}_by_{criterion}_{side}_{record}.dat" using 3:xticlabels(1) title col{cluster}
set term cairolatex pdf
set output "{plots_dir}/{object}_by_{criterion}_{side}_{record}.tex"
replot
""".format(plots_dir=PLOTS_DIR, cluster=cluster, **kwargs)) """.format(plots_dir=PLOTS_DIR, cluster=cluster, **kwargs))
f.close() f.close()
os.system("gnuplot {plots_dir}/{object}_by_{criterion}_{side}_{record}.gnuplot".format(plots_dir=PLOTS_DIR, **kwargs)) os.system("gnuplot {plots_dir}/{object}_by_{criterion}_{side}_{record}.gnuplot".format(plots_dir=PLOTS_DIR, **kwargs))
@ -108,14 +118,23 @@ set style fill solid 1.0 border lt -1
set style histogram rowstacked set style histogram rowstacked
set style data histograms set style data histograms
set title font "CMU Sans Serif,12" "{object_title} by {criterion_title} ({record}, {side}{machine}) ({unit})" set title font "CMU Sans Serif,12" "{object_title} by {criterion_title} ({record}, {side}{machine}) ({unit})"
set xtics border in scale 0,0 nomirror noenhanced rotate by -15 autojustify set xtics border in scale 0,0 nomirror noenhanced rotate by 30 right
set lmargin 9
set rmargin 1
set bmargin 5
set tmargin 2.5
set key fixed left top vertical Left noenhanced autotitle nobox invert reverse opaque set key fixed left top vertical Left noenhanced autotitle nobox invert reverse opaque
set colorbox vertical origin screen 0.9, 0.2 size screen 0.05, 0.6 front noinvert bdefault set colorbox vertical origin screen 0.9, 0.2 size screen 0.05, 0.6 front noinvert bdefault
set xrange [ * : * ] noreverse writeback set xrange [ * : * ] noreverse writeback
set yrange [ 0 : * ] set yrange [ 0 : * ]
set grid y lt 1 lw .75 lc "gray" set grid y lt 1 lw .75 lc "gray"
plot for [i=2:{nb_functions}] "{plots_dir}/{object}_by_{criterion}_{side}_{record}.dat" using i:xticlabels(1) title col plot for [i=2:{nb_functions}] "{plots_dir}/{object}_by_{criterion}_{side}_{record}.dat" using i:xticlabels(1) title col
""".format(plots_dir=PLOTS_DIR, cluster=cluster, **kwargs)) #set term cairolatex pdf
set term pict2e font ",10"
set output "{plots_dir}/{object}_by_{criterion}_{side}_{record}.tex"
set key font ",10" spacing 0.8
replot
""".format(plots_dir=PLOTS_DIR, cluster=cluster, **kwargs).replace("aws_lc", "aws-lc"))
f.close() f.close()
os.system("gnuplot {plots_dir}/{object}_by_{criterion}_{side}_{record}.gnuplot".format(plots_dir=PLOTS_DIR, **kwargs)) os.system("gnuplot {plots_dir}/{object}_by_{criterion}_{side}_{record}.gnuplot".format(plots_dir=PLOTS_DIR, **kwargs))
@ -145,19 +164,26 @@ def make_log_plot(logs, exp, criterion, side, obj, record, machine=None):
if log["impl"] not in impls: if log["impl"] not in impls:
impls.append(log["impl"]) impls.append(log["impl"])
impls.sort() impls.sort()
f.write("{} none {}\n".format(criterion, " ".join(impls))) f.write("{} none {}\n".format(criterion, " ".join([impl_title(impl) for impl in impls])))
f.write(plain_line+" -"*len(impls)+"\n") f.write(plain_line+" -"*len(impls)+"\n")
for cipher in ciphers: for cipher in ciphers:
for impl in impls: for impl in impls:
if impl not in ciphers[cipher]: if impl not in ciphers[cipher]:
ciphers[cipher][impl] = 0 ciphers[cipher][impl] = 0
f.write("{}({}) - {}\n".format( """f.write("{}({}) - {}\n".format(
ALG_LABEL[cipher], ALG_LABEL[cipher],
VER_LABEL[log["cipher"]], VER_LABEL[log["cipher"]],
" ".join([ " ".join([
str(ciphers[cipher][impl]) str(ciphers[cipher][impl])
for impl in impls for impl in impls
]), ]),
))"""
f.write("{} - {}\n".format(
ALG_LABEL[cipher],
" ".join([
str(ciphers[cipher][impl])
for impl in impls
]),
)) ))
f.close() f.close()
gnuplot_histogram( gnuplot_histogram(
@ -186,7 +212,7 @@ def make_profile_plot(logs, exp, criterion, side, record, no_flamegraph=False, m
profile_results = profile.extract_from_file(svg_filename) profile_results = profile.extract_from_file(svg_filename)
except FileNotFoundError: except FileNotFoundError:
print(f"Cannot read {svg_filename}") print(f"Cannot read {svg_filename}")
return continue
print(profile_results) print(profile_results)
for function in profile_results: for function in profile_results:
if function not in functions: if function not in functions:
@ -198,7 +224,7 @@ def make_profile_plot(logs, exp, criterion, side, record, no_flamegraph=False, m
}) })
f.write("{} {}\n".format(criterion, " ".join(functions))) f.write("{} {}\n".format(criterion, " ".join(functions)))
for run in runs: for run in runs:
f.write("\"{} {}({})\" {}\n".format( """f.write("\"{} {}({})\" {}\n".format(
run["impl"], run["impl"],
ALG_LABEL[run[criterion]], ALG_LABEL[run[criterion]],
VER_LABEL[log["cipher"]], VER_LABEL[log["cipher"]],
@ -206,6 +232,14 @@ def make_profile_plot(logs, exp, criterion, side, record, no_flamegraph=False, m
str(run["functions"][function][0]) str(run["functions"][function][0])
for function in functions for function in functions
]), ]),
))"""
f.write("\"{} {}\" {}\n".format(
impl_title(run["impl"]),
ALG_LABEL[run[criterion]],
" ".join([
str(run["functions"][function][0])
for function in functions
]),
)) ))
f.close() f.close()
gnuplot_stacked_histogram( gnuplot_stacked_histogram(
@ -220,6 +254,46 @@ def make_profile_plot(logs, exp, criterion, side, record, no_flamegraph=False, m
machine=machine machine=machine
) )
# Are CPU and energy proportional
def make_linear_regression(logs):
idle_cpu = None
idle_energy = None
for log in logs:
if log["exp"] == "idle":
idle_cpu = float(log["cpu"]) / float(log["time"])
idle_energy = float(log["Wh"]) / float(log["time"])
break
samples_cpu = {"global":[]}
samples_energy = {"global":[]}
for log in logs:
if log["impl"] == "-":
continue
sample_cpu = float(log["cpu"]) - idle_cpu * float(log["time"])
sample_energy = float(log["Wh"]) - idle_energy * float(log["time"])
samples_cpu["global"].append(sample_cpu)
samples_energy["global"].append(sample_energy)
if log["impl"] not in samples_cpu:
samples_cpu[log["impl"]] = []
samples_energy[log["impl"]] = []
samples_cpu[log["impl"]].append(sample_cpu)
samples_energy[log["impl"]].append(sample_energy)
print("Pearson correlation coefficients (energy/cpu)")
results = {}
for impl in samples_cpu:
res = stats.linregress(samples_cpu[impl], samples_energy[impl])
print(impl, "\t", res.rvalue)
results[impl] = res
if impl != "global":
plt.plot(samples_cpu[impl], samples_energy[impl], 'o', label=impl)
#plt.plot(samples_cpu["global"], samples_energy["global"], 'o', label='samples')
plt.plot(samples_cpu["global"], res.intercept + res.slope*np.array(samples_cpu["global"]), 'r', label='fitted line')
plt.xlabel("CPU (s)")
plt.ylabel("Energy (Wh)")
plt.legend()
#plt.show()
plt.savefig(f"{PLOTS_DIR}/correlation_energy_cpu.png")
def getargv(arg:str, default="", n:int=1, args:list=sys.argv): def getargv(arg:str, default="", n:int=1, args:list=sys.argv):
if arg in args and len(args) > args.index(arg)+n: if arg in args and len(args) > args.index(arg)+n:
return args[args.index(arg)+n] return args[args.index(arg)+n]
@ -267,3 +341,8 @@ if __name__ == "__main__":
make_profile_plot(logs, "impl-cipher-ver", "cipher", side, record, no_flamegraph=no_flamegraph, machine=machine) make_profile_plot(logs, "impl-cipher-ver", "cipher", side, record, no_flamegraph=no_flamegraph, machine=machine)
make_profile_plot(logs, "impl-cert-ver", "cert", side, record, no_flamegraph=no_flamegraph, machine=machine) make_profile_plot(logs, "impl-cert-ver", "cert", side, record, no_flamegraph=no_flamegraph, machine=machine)
make_profile_plot(logs, "impl-kex-ver", "kex", side, record, no_flamegraph=no_flamegraph, machine=machine) make_profile_plot(logs, "impl-kex-ver", "kex", side, record, no_flamegraph=no_flamegraph, machine=machine)
elif cmd == "correl":
from scipy import stats
import matplotlib.pyplot as plt
import numpy as np
make_linear_regression(logs)

View file

@ -7,27 +7,27 @@ FUNCTIONS = {
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::cipher::MessageEncrypter>::encrypt": "encrypt", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::cipher::MessageEncrypter>::encrypt": "encrypt",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::Hkdf>::expander_for_okm": "hkdf",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::SecureRandom>::fill": "rand",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::SupportedKxGroup>::start": "kx",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::hash::Hash>::start": "hash", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::hash::Hash>::start": "hash",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::hash::Context>::finish": "hash", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::hash::Context>::finish": "hash",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::hash::Context>::update": "hash", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::hash::Context>::update": "hash",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::hash::Context>::fork_finish": "hash", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::hash::Context>::fork_finish": "hash",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::Hkdf>::extract_from_secret": "hkdf", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::SupportedKxGroup>::start": "kx",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::ActiveKeyExchange>::complete": "kx", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::ActiveKeyExchange>::complete": "kx",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::SupportedKxGroup>::start_and_complete": "kx",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::SupportedKxGroup>::start": "kx",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::SecureRandom>::fill": "rand",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::Hkdf>::expander_for_okm": "hkdf",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::Hkdf>::extract_from_secret": "hkdf",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::HkdfExpander>::hash_len": "hkdf", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::HkdfExpander>::hash_len": "hkdf",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::HkdfExpander>::expand_slice": "hkdf", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::HkdfExpander>::expand_slice": "hkdf",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::Hkdf>::extract_from_secret": "hkdf", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::Hkdf>::extract_from_secret": "hkdf",
"<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::Hkdf>::hmac_sign": "hkdf", "<[a-zA-Z0-9_:<>]+ as rustls::crypto::tls13::Hkdf>::hmac_sign": "hkdf",
"ring::hkdf::fill_okm": "hkdf", "ring::hkdf::fill_okm": "hkdf",
#"ring::hkdf::Salt::extract": "hkdf",
"aws_lc_0_32_2_HKDF": "hkdf", "aws_lc_0_32_2_HKDF": "hkdf",
#"rustls_openssl::tls13::<impl rustls::crypto::cipher::Tls13AeadAlgorithm for rustls_openssl::aead::Algorithm>::encrypter": "encrypt", #"rustls_openssl::tls13::<impl rustls::crypto::cipher::Tls13AeadAlgorithm for rustls_openssl::aead::Algorithm>::encrypter": "encrypt",

2
servers.txt Normal file
View file

@ -0,0 +1,2 @@
domain_name,output_rank,date
google.com.,1,2025-12-18