From 4b6498ede3194145abc556ffeb874cc40780833c15ee483debb3f919d53188ed Mon Sep 17 00:00:00 2001 From: Nadim Kobeissi Date: Thu, 26 Jun 2025 12:19:00 +0200 Subject: [PATCH] Migrate back to Git LFS --- .gitattributes | 11 + .gitignore | 33 + NOTES.md | 13 + README.md | 23 + assignments/README.md | 8 + assignments/labs/Makefile | 17 + assignments/labs/README.md | 9 + assignments/labs/password-manager.tex | 159 + assignments/labs/proverif.tex | 167 + assignments/labs/secure-messenger.tex | 169 + assignments/labs/zk-battleship.tex | 159 + assignments/problem-sets/Makefile | 13 + assignments/problem-sets/NOTES.md | 28 + assignments/problem-sets/README.md | 5 + assignments/problem-sets/problem-set-1.tex | 342 + assignments/problem-sets/problem-set-2.tex | 259 + assignments/problem-sets/problem-set-3.tex | 225 + misc/fonts/InriaSans-Bold.ttf | 3 + misc/fonts/InriaSans-BoldItalic.ttf | 3 + misc/fonts/InriaSans-Italic.ttf | 3 + misc/fonts/InriaSans-Regular.ttf | 3 + misc/fonts/JetBrainsMono-Bold.ttf | 3 + misc/fonts/JetBrainsMono-BoldItalic.ttf | 3 + misc/fonts/JetBrainsMono-Italic.ttf | 3 + misc/fonts/JetBrainsMono-Regular.ttf | 3 + misc/fonts/STIXTwoMath-Regular.ttf | 3 + misc/fonts/STIXTwoText-Bold.ttf | 3 + misc/fonts/STIXTwoText-BoldItalic.ttf | 3 + misc/fonts/STIXTwoText-Italic.ttf | 3 + misc/fonts/STIXTwoText-Regular.ttf | 3 + misc/fonts/fonts.sty | 8 + misc/macros/classhandout.sty | 61 + misc/macros/joc.sty | 98 + misc/macros/msc5.sty | 4173 ++++++ slides/1-1.tex | 806 + slides/1-2.tex | 500 + slides/1-3.tex | 1279 ++ slides/1-4.tex | 2163 +++ slides/1-5.tex | 1657 +++ slides/1-6.tex | 1058 ++ slides/1-7.tex | 1415 ++ slides/1-8.tex | 1300 ++ slides/2-1.tex | 2633 ++++ slides/2-10.tex | 28 + slides/2-2.tex | 974 ++ slides/2-3.tex | 1837 +++ slides/2-4.tex | 28 + slides/2-5.tex | 28 + slides/2-6.tex | 28 + slides/2-7.tex | 28 + slides/2-8.tex | 28 + slides/2-9.tex | 28 + slides/Makefile | 73 + slides/README.md | 37 + slides/images/aead_scenario_1.pdf | 3 + slides/images/aead_scenario_2.pdf | 3 + slides/images/aead_scenario_4.pdf | 3 + slides/images/aes_subbytes.png | 3 + slides/images/attacker_interface.pdf | 3 + slides/images/attacker_interface_prog.pdf | 3 + slides/images/aub_white.png | 3 + slides/images/battleship.jpg | 3 + slides/images/block_cipher_modes.png | 3 + slides/images/caesar.png | 3 + slides/images/cbc_with_dec.pdf | 3 + slides/images/cedar.jpg | 3 + slides/images/clock_13.jpg | 3 + slides/images/complexity.png | 3 + slides/images/ctr_dec.pdf | 3 + slides/images/ctr_dec_delta.pdf | 3 + slides/images/ctr_with_dec.pdf | 3 + slides/images/deep_crack_a.jpg | 3 + slides/images/deep_crack_b.jpg | 3 + slides/images/dh.png | 3 + slides/images/djb.jpg | 3 + slides/images/elliptic_curve_add.png | 3 + slides/images/elliptic_curve_double.png | 3 + slides/images/elliptic_curve_integers.png | 3 + slides/images/elliptic_curve_real.png | 3 + slides/images/export_1.jpg | 3 + slides/images/export_2.jpg | 3 + slides/images/export_3.jpg | 3 + slides/images/feistel_cipher.pdf | 3 + slides/images/feistel_cipher_inv.pdf | 3 + slides/images/fischer.png | 3 + slides/images/fischer_sectioned.png | 3 + slides/images/fischer_theory.png | 3 + slides/images/fischer_tls_13_bubbles.png | 3 + slides/images/gcm.pdf | 3 + slides/images/gpu_farm.jpg | 3 + slides/images/keyed_enc.pdf | 3 + slides/images/letsencrypt_certs.png | 3 + slides/images/letsencrypt_https.png | 3 + slides/images/letsencrypt_issuance.png | 3 + slides/images/logjam_1.png | 3 + slides/images/logjam_2.png | 3 + slides/images/logjam_3.png | 3 + slides/images/merkle_damgard.pdf | 3 + slides/images/naive_enc.pdf | 3 + slides/images/nist_peanut.png | 3 + slides/images/noelle_spamton.png | 3 + slides/images/oracle_painting_zoom.jpg | 3 + slides/images/persistence_of_memory.jpg | 3 + slides/images/pgp_keyserver.png | 3 + slides/images/pgp_pubkey.png | 3 + slides/images/pidgin_chat.jpg | 3 + slides/images/pidgin_otr.jpg | 3 + slides/images/prf_enc_2.pdf | 3 + slides/images/prf_enc_malleable.pdf | 3 + slides/images/prg_distributions.pdf | 3 + slides/images/qiao.png | 3 + slides/images/rc4_bias.png | 3 + slides/images/rc4_prga_py.png | 3 + slides/images/safecurves.png | 3 + slides/images/sha2.png | 3 + slides/images/sigma_test.png | 3 + slides/images/signal.jpg | 3 + slides/images/signal_verification.png | 3 + slides/images/sponge.png | 3 + slides/images/tls_13_handshake.png | 3 + slides/images/tls_13_sketch.png | 3 + slides/images/tls_attacks_timeline_2015.png | 3 + slides/images/tls_borat.jpg | 3 + slides/images/tls_collision.png | 3 + slides/images/tls_freak.png | 3 + slides/images/tls_handshake.png | 3 + slides/images/tls_illustrated.png | 3 + slides/images/tls_smack.png | 3 + slides/images/tux_encrypted_ctr.png | 3 + slides/images/tux_encrypted_ecb.png | 3 + slides/images/tux_plaintext.png | 3 + slides/images/vigenere.png | 3 + slides/images/xor_dec.png | 3 + slides/images/xor_enc.png | 3 + slides/images/yoda_meme.jpg | 3 + slides/theme/beamercolorthemecipher.sty | 58 + slides/theme/beamerfontthemecipher.sty | 29 + slides/theme/beamerinnerthemecipher.sty | 191 + slides/theme/beamerouterthemecipher.sty | 29 + slides/theme/beamerthemecipher.sty | 22 + syllabus/Makefile | 2 + syllabus/README.md | 5 + syllabus/syllabus.tex | 149 + website/error.html | 15 + website/favicon.ico | 3 + website/index.html | 728 + test => website/labs/.gitkeep | 0 website/papers/.gitkeep | 0 website/papers/confidential-cloud.pdf | 3 + website/papers/ecc-practice.pdf | 3 + website/papers/everest-perspectives.pdf | 3 + website/papers/google-poodle.pdf | 3 + website/papers/group-chats.pdf | 3 + website/papers/group-healing.pdf | 3 + website/papers/hkdf-scheme.pdf | 3 + website/papers/imperfect-dh.pdf | 3 + website/papers/inria-collisions.pdf | 3 + website/papers/inria-sweet32.pdf | 3 + website/papers/invalid-curve.pdf | 3 + website/papers/jhu-imessage.pdf | 3 + website/papers/johnny-cant.pdf | 3 + website/papers/johnny-still.pdf | 3 + website/papers/key-commitment.pdf | 3 + website/papers/lessons-tls.pdf | 3 + website/papers/luby-rackoff.pdf | 3 + website/papers/lucky-thirteen.pdf | 3 + website/papers/matter-heartbleed.pdf | 3 + website/papers/nintendo-hard.pdf | 3 + website/papers/otr-analysis.pdf | 3 + website/papers/otr-auth.pdf | 3 + website/papers/otr-messaging.pdf | 3 + website/papers/pcs-impossibility.pdf | 3 + website/papers/pq3-analysis.pdf | 3 + website/papers/pqxdh-analysis.pdf | 3 + website/papers/pragmatic-mpc.pdf | 3 + website/papers/prime-order.pdf | 3 + website/papers/rc4-absab.pdf | 3 + website/papers/rc4-attacks.pdf | 3 + website/papers/rc4-biases.pdf | 3 + website/papers/rc4-ksa.pdf | 3 + website/papers/rc4-tls.pdf | 3 + website/papers/rom-methodology.pdf | 3 + website/papers/scrypt-memory.pdf | 3 + website/papers/session-handling.pdf | 3 + website/papers/shattered-sha1.pdf | 3 + website/papers/sigma-ake.pdf | 3 + website/papers/signal-analysis.pdf | 3 + website/papers/smack-tls.pdf | 3 + website/papers/sok-verif.pdf | 3 + website/papers/telegram-exchange.pdf | 3 + website/papers/tlock-bls.pdf | 3 + website/papers/tls-deployment.pdf | 3 + website/papers/tls13-verif.pdf | 3 + website/papers/triple-handshakes.pdf | 3 + website/papers/triple-ratchet.pdf | 3 + website/papers/wallez-thesis.pdf | 3 + website/papers/whatsapp-groups.pdf | 3 + website/papers/wild-cryptography.pdf | 3 + website/papers/xwing-hybrid.pdf | 3 + website/problem-sets/.gitkeep | 0 website/res/css/error.css | 16 + website/res/css/style.css | 892 ++ website/res/fonts/google/google.css | 208 + .../ptRMTiqXYfZMCOiVj9kQ1Of4KCFtpe4OZA.woff2 | 3 + .../v14/ptRMTiqXYfZMCOiVj9kQ1On4KCFtpe4.woff2 | 3 + ...ptROTiqXYfZMCOiVj9kQ1OzIJCtqh-w-ZUcw.woff2 | 3 + .../ptROTiqXYfZMCOiVj9kQ1OzIKitqh-w-ZQ.woff2 | 3 + ...RPTiqXYfZMCOiVj9kQ3ELaPQJPqMQ0bX8JQA.woff2 | 3 + .../ptRPTiqXYfZMCOiVj9kQ3ELaPQxPqMQ0bX8.woff2 | 3 + ...RPTiqXYfZMCOiVj9kQ3FLdPQJPqMQ0bX8JQA.woff2 | 3 + .../ptRPTiqXYfZMCOiVj9kQ3FLdPQxPqMQ0bX8.woff2 | 3 + ...TiqXYfZMCOiVj9kQ1OzAgQl_pM4zT305QaYc.woff2 | 3 + ...RRTiqXYfZMCOiVj9kQ1OzAgQl_qs4zT305QQ.woff2 | 3 + ...TiqXYfZMCOiVj9kQ1OzAkQ5_pM4zT305QaYc.woff2 | 3 + ...RRTiqXYfZMCOiVj9kQ1OzAkQ5_qs4zT305QQ.woff2 | 3 + ...V2o-flEEny0FZhsfKu5WU4xD1OwGtT0rU3BE.woff2 | 3 + ...tDbV2o-flEEny0FZhsfKu5WU4xD7OwGtT0rU.woff2 | 3 + ...-flEEny0FZhsfKu5WU4xD-Cw2nSGjW7BDEAQ.woff2 | 3 + ...X2o-flEEny0FZhsfKu5WU4xD-CwOnSGjW7BA.woff2 | 3 + .../res/fonts/phosphor/Phosphor-Duotone.woff2 | 3 + website/res/fonts/phosphor/phosphor.css | 12111 ++++++++++++++++ website/res/img/aub_black.png | 3 + website/res/img/aub_red.png | 3 + website/res/img/aub_white.png | 3 + website/res/img/by-nc-sa.svg | 3 + website/res/img/cedar.webp | 3 + website/res/img/favicon.png | 3 + website/res/img/joy.webp | 3 + website/res/img/og.jpg | 3 + website/res/img/try_again.gif | 3 + website/res/img/waiting.gif | 3 + website/res/js/collapsible.js | 8 + website/res/js/main.js | 5 + website/res/js/menu.js | 17 + website/res/js/updated.js | 39 + website/robots.txt | 2 + website/slides/.gitkeep | 0 237 files changed, 36953 insertions(+) create mode 100644 .gitattributes create mode 100755 .gitignore create mode 100644 NOTES.md create mode 100644 README.md create mode 100644 assignments/README.md create mode 100644 assignments/labs/Makefile create mode 100644 assignments/labs/README.md create mode 100755 assignments/labs/password-manager.tex create mode 100755 assignments/labs/proverif.tex create mode 100755 assignments/labs/secure-messenger.tex create mode 100755 assignments/labs/zk-battleship.tex create mode 100644 assignments/problem-sets/Makefile create mode 100644 assignments/problem-sets/NOTES.md create mode 100644 assignments/problem-sets/README.md create mode 100644 assignments/problem-sets/problem-set-1.tex create mode 100644 assignments/problem-sets/problem-set-2.tex create mode 100644 assignments/problem-sets/problem-set-3.tex create mode 100644 misc/fonts/InriaSans-Bold.ttf create mode 100644 misc/fonts/InriaSans-BoldItalic.ttf create mode 100644 misc/fonts/InriaSans-Italic.ttf create mode 100644 misc/fonts/InriaSans-Regular.ttf create mode 100644 misc/fonts/JetBrainsMono-Bold.ttf create mode 100644 misc/fonts/JetBrainsMono-BoldItalic.ttf create mode 100644 misc/fonts/JetBrainsMono-Italic.ttf create mode 100644 misc/fonts/JetBrainsMono-Regular.ttf create mode 100644 misc/fonts/STIXTwoMath-Regular.ttf create mode 100644 misc/fonts/STIXTwoText-Bold.ttf create mode 100644 misc/fonts/STIXTwoText-BoldItalic.ttf create mode 100644 misc/fonts/STIXTwoText-Italic.ttf create mode 100644 misc/fonts/STIXTwoText-Regular.ttf create mode 100644 misc/fonts/fonts.sty create mode 100644 misc/macros/classhandout.sty create mode 100644 misc/macros/joc.sty create mode 100644 misc/macros/msc5.sty create mode 100644 slides/1-1.tex create mode 100644 slides/1-2.tex create mode 100644 slides/1-3.tex create mode 100644 slides/1-4.tex create mode 100644 slides/1-5.tex create mode 100644 slides/1-6.tex create mode 100644 slides/1-7.tex create mode 100644 slides/1-8.tex create mode 100644 slides/2-1.tex create mode 100644 slides/2-10.tex create mode 100644 slides/2-2.tex create mode 100644 slides/2-3.tex create mode 100644 slides/2-4.tex create mode 100644 slides/2-5.tex create mode 100644 slides/2-6.tex create mode 100644 slides/2-7.tex create mode 100644 slides/2-8.tex create mode 100644 slides/2-9.tex create mode 100644 slides/Makefile create mode 100644 slides/README.md create mode 100644 slides/images/aead_scenario_1.pdf create mode 100644 slides/images/aead_scenario_2.pdf create mode 100644 slides/images/aead_scenario_4.pdf create mode 100644 slides/images/aes_subbytes.png create mode 100644 slides/images/attacker_interface.pdf create mode 100644 slides/images/attacker_interface_prog.pdf create mode 100644 slides/images/aub_white.png create mode 100644 slides/images/battleship.jpg create mode 100644 slides/images/block_cipher_modes.png create mode 100644 slides/images/caesar.png create mode 100644 slides/images/cbc_with_dec.pdf create mode 100644 slides/images/cedar.jpg create mode 100644 slides/images/clock_13.jpg create mode 100644 slides/images/complexity.png create mode 100644 slides/images/ctr_dec.pdf create mode 100644 slides/images/ctr_dec_delta.pdf create mode 100644 slides/images/ctr_with_dec.pdf create mode 100644 slides/images/deep_crack_a.jpg create mode 100644 slides/images/deep_crack_b.jpg create mode 100644 slides/images/dh.png create mode 100644 slides/images/djb.jpg create mode 100644 slides/images/elliptic_curve_add.png create mode 100644 slides/images/elliptic_curve_double.png create mode 100644 slides/images/elliptic_curve_integers.png create mode 100644 slides/images/elliptic_curve_real.png create mode 100644 slides/images/export_1.jpg create mode 100644 slides/images/export_2.jpg create mode 100644 slides/images/export_3.jpg create mode 100644 slides/images/feistel_cipher.pdf create mode 100644 slides/images/feistel_cipher_inv.pdf create mode 100644 slides/images/fischer.png create mode 100644 slides/images/fischer_sectioned.png create mode 100644 slides/images/fischer_theory.png create mode 100644 slides/images/fischer_tls_13_bubbles.png create mode 100644 slides/images/gcm.pdf create mode 100644 slides/images/gpu_farm.jpg create mode 100644 slides/images/keyed_enc.pdf create mode 100644 slides/images/letsencrypt_certs.png create mode 100644 slides/images/letsencrypt_https.png create mode 100644 slides/images/letsencrypt_issuance.png create mode 100644 slides/images/logjam_1.png create mode 100644 slides/images/logjam_2.png create mode 100644 slides/images/logjam_3.png create mode 100644 slides/images/merkle_damgard.pdf create mode 100644 slides/images/naive_enc.pdf create mode 100644 slides/images/nist_peanut.png create mode 100644 slides/images/noelle_spamton.png create mode 100644 slides/images/oracle_painting_zoom.jpg create mode 100644 slides/images/persistence_of_memory.jpg create mode 100644 slides/images/pgp_keyserver.png create mode 100644 slides/images/pgp_pubkey.png create mode 100644 slides/images/pidgin_chat.jpg create mode 100644 slides/images/pidgin_otr.jpg create mode 100644 slides/images/prf_enc_2.pdf create mode 100644 slides/images/prf_enc_malleable.pdf create mode 100644 slides/images/prg_distributions.pdf create mode 100644 slides/images/qiao.png create mode 100644 slides/images/rc4_bias.png create mode 100644 slides/images/rc4_prga_py.png create mode 100644 slides/images/safecurves.png create mode 100644 slides/images/sha2.png create mode 100644 slides/images/sigma_test.png create mode 100644 slides/images/signal.jpg create mode 100644 slides/images/signal_verification.png create mode 100644 slides/images/sponge.png create mode 100644 slides/images/tls_13_handshake.png create mode 100644 slides/images/tls_13_sketch.png create mode 100644 slides/images/tls_attacks_timeline_2015.png create mode 100644 slides/images/tls_borat.jpg create mode 100644 slides/images/tls_collision.png create mode 100644 slides/images/tls_freak.png create mode 100644 slides/images/tls_handshake.png create mode 100644 slides/images/tls_illustrated.png create mode 100644 slides/images/tls_smack.png create mode 100644 slides/images/tux_encrypted_ctr.png create mode 100644 slides/images/tux_encrypted_ecb.png create mode 100644 slides/images/tux_plaintext.png create mode 100644 slides/images/vigenere.png create mode 100644 slides/images/xor_dec.png create mode 100644 slides/images/xor_enc.png create mode 100644 slides/images/yoda_meme.jpg create mode 100644 slides/theme/beamercolorthemecipher.sty create mode 100644 slides/theme/beamerfontthemecipher.sty create mode 100644 slides/theme/beamerinnerthemecipher.sty create mode 100644 slides/theme/beamerouterthemecipher.sty create mode 100644 slides/theme/beamerthemecipher.sty create mode 100644 syllabus/Makefile create mode 100644 syllabus/README.md create mode 100755 syllabus/syllabus.tex create mode 100644 website/error.html create mode 100644 website/favicon.ico create mode 100755 website/index.html rename test => website/labs/.gitkeep (100%) create mode 100644 website/papers/.gitkeep create mode 100644 website/papers/confidential-cloud.pdf create mode 100644 website/papers/ecc-practice.pdf create mode 100644 website/papers/everest-perspectives.pdf create mode 100644 website/papers/google-poodle.pdf create mode 100644 website/papers/group-chats.pdf create mode 100644 website/papers/group-healing.pdf create mode 100644 website/papers/hkdf-scheme.pdf create mode 100644 website/papers/imperfect-dh.pdf create mode 100644 website/papers/inria-collisions.pdf create mode 100644 website/papers/inria-sweet32.pdf create mode 100644 website/papers/invalid-curve.pdf create mode 100644 website/papers/jhu-imessage.pdf create mode 100644 website/papers/johnny-cant.pdf create mode 100644 website/papers/johnny-still.pdf create mode 100644 website/papers/key-commitment.pdf create mode 100644 website/papers/lessons-tls.pdf create mode 100644 website/papers/luby-rackoff.pdf create mode 100644 website/papers/lucky-thirteen.pdf create mode 100644 website/papers/matter-heartbleed.pdf create mode 100644 website/papers/nintendo-hard.pdf create mode 100644 website/papers/otr-analysis.pdf create mode 100644 website/papers/otr-auth.pdf create mode 100644 website/papers/otr-messaging.pdf create mode 100644 website/papers/pcs-impossibility.pdf create mode 100644 website/papers/pq3-analysis.pdf create mode 100644 website/papers/pqxdh-analysis.pdf create mode 100644 website/papers/pragmatic-mpc.pdf create mode 100644 website/papers/prime-order.pdf create mode 100644 website/papers/rc4-absab.pdf create mode 100644 website/papers/rc4-attacks.pdf create mode 100644 website/papers/rc4-biases.pdf create mode 100644 website/papers/rc4-ksa.pdf create mode 100644 website/papers/rc4-tls.pdf create mode 100644 website/papers/rom-methodology.pdf create mode 100644 website/papers/scrypt-memory.pdf create mode 100644 website/papers/session-handling.pdf create mode 100644 website/papers/shattered-sha1.pdf create mode 100644 website/papers/sigma-ake.pdf create mode 100644 website/papers/signal-analysis.pdf create mode 100644 website/papers/smack-tls.pdf create mode 100644 website/papers/sok-verif.pdf create mode 100644 website/papers/telegram-exchange.pdf create mode 100644 website/papers/tlock-bls.pdf create mode 100644 website/papers/tls-deployment.pdf create mode 100644 website/papers/tls13-verif.pdf create mode 100644 website/papers/triple-handshakes.pdf create mode 100644 website/papers/triple-ratchet.pdf create mode 100644 website/papers/wallez-thesis.pdf create mode 100644 website/papers/whatsapp-groups.pdf create mode 100644 website/papers/wild-cryptography.pdf create mode 100644 website/papers/xwing-hybrid.pdf create mode 100644 website/problem-sets/.gitkeep create mode 100644 website/res/css/error.css create mode 100644 website/res/css/style.css create mode 100644 website/res/fonts/google/google.css create mode 100644 website/res/fonts/google/inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1Of4KCFtpe4OZA.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1On4KCFtpe4.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIJCtqh-w-ZUcw.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIKitqh-w-ZQ.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQJPqMQ0bX8JQA.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQxPqMQ0bX8.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQJPqMQ0bX8JQA.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQxPqMQ0bX8.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_pM4zT305QaYc.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_qs4zT305QQ.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_pM4zT305QaYc.woff2 create mode 100644 website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_qs4zT305QQ.woff2 create mode 100644 website/res/fonts/google/jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD1OwGtT0rU3BE.woff2 create mode 100644 website/res/fonts/google/jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD7OwGtT0rU.woff2 create mode 100644 website/res/fonts/google/jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-Cw2nSGjW7BDEAQ.woff2 create mode 100644 website/res/fonts/google/jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-CwOnSGjW7BA.woff2 create mode 100644 website/res/fonts/phosphor/Phosphor-Duotone.woff2 create mode 100644 website/res/fonts/phosphor/phosphor.css create mode 100644 website/res/img/aub_black.png create mode 100644 website/res/img/aub_red.png create mode 100644 website/res/img/aub_white.png create mode 100644 website/res/img/by-nc-sa.svg create mode 100644 website/res/img/cedar.webp create mode 100644 website/res/img/favicon.png create mode 100644 website/res/img/joy.webp create mode 100644 website/res/img/og.jpg create mode 100644 website/res/img/try_again.gif create mode 100644 website/res/img/waiting.gif create mode 100644 website/res/js/collapsible.js create mode 100644 website/res/js/main.js create mode 100644 website/res/js/menu.js create mode 100644 website/res/js/updated.js create mode 100644 website/robots.txt create mode 100644 website/slides/.gitkeep diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ef28798 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +*.pdf filter=lfs diff=lfs merge=lfs -text +*.woff2 filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.otf filter=lfs diff=lfs merge=lfs -text +*.jpeg filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.webp filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.gif filter=lfs diff=lfs merge=lfs -text +*.svg filter=lfs diff=lfs merge=lfs -text +*.ico filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..5cde1ec --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# macOS +.DS_Store + +# LaTeX +*.aux +*.bcf +*.idx +*.log +*.out +*.bbl +*.blg +*.xml +*.toc +*.fls +*.fdb_latexmk +*.lot +*.lof +*.ind +*.ilg +*.xdv +__latex* +*synctex* +*.listing +*.fmt +*.nav +*.snm +*.vrb + +# Compiled materials +website/slides/*.pdf +website/labs/*.pdf +website/problem-sets/*.pdf +website/syllabus.pdf diff --git a/NOTES.md b/NOTES.md new file mode 100644 index 0000000..e16f21a --- /dev/null +++ b/NOTES.md @@ -0,0 +1,13 @@ +# Random Notes for Me (Please Ignore) + +- [ ] Every time I show a new security property in Part 1, I should link it to an attack. This means redoing all the Part 1 slides after a first pass where I integrate the Joy of Cryptography materials. Eg. I describe what uniform sampling is? OK, look what happened with [PuTTY](https://thehackernews.com/2024/04/widely-used-putty-ssh-client-found.html) when they didn't respect this! See? This stuff matters in the real world! +- [ ] An "escape hatch" into more informal proofs should be readily available in the event of running out of time, etc., but should not be too heavily relied upon. +- [ ] None of the material covers key management. [Alfred Menezes](https://www.youtube.com/watch?v=C9e023bTfes&list=PLA1qgQLL41SRn_23p8zD0vUpKM4qOgt_T&index=6) may come to the rescue. +- [ ] **Must** be up-front about exam-required materials. Tell students what's required for each exam first thing. That way, you remove anxiety, and allow them to explore the materials at their leisure. +- [ ] [This website](https://asecuritysite.com/range/age) is full of useful practical examples, here we have range proofs. +- [ ] Not enough attack labs. +- [ ] Might be fun to cover QUIC, HTTP/3, Passkeys... +- [ ] Session on side-channels? +- [ ] Integrate Verifpal as learning tool +- [ ] [Amazing teaching style](https://www.youtube.com/watch?v=fOGdb1CTu5c) +- [ ] [Excalidraw](https://excalidraw.com) might be useful. diff --git a/README.md b/README.md new file mode 100644 index 0000000..74f3911 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +AUB Logo + +# Applied Cryptography (CMPS 297AD/396AI) + +This repository contains source code of the course materials for Applied Cryptography (CMPS 297AD/396AI) at the American University of Beirut. + +If you are a student or someone trying to learn from this course's materials, there is no point in browsing this repository, since it only contains uncompiled sources. For a better experience, ignore this repository completely and access the materials through the course website: [appliedcryptography.page](https://appliedcryptography.page) + +## Contents + +- `assignments`: Course assignments and lab sessions. +- `misc`: LaTeX dependencies. +- `slides`: Course slides. +- `syllabus`: Course syllabus. +- `website`: [Course website](https://appliedcryptography.page). + +## Compiling LaTeX Materials + +Before compiling any of the LaTeX materials (slides, problem sets, lab sheets...), make sure to first install the fonts included in `misc/fonts/` on your system. + +## Author & License + +Applied Cryptography at the American University of Beirut by Nadim Kobeissi is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. diff --git a/assignments/README.md b/assignments/README.md new file mode 100644 index 0000000..25a2b63 --- /dev/null +++ b/assignments/README.md @@ -0,0 +1,8 @@ +# Assignments + +This folder contains assignments relevant to the course. + +## Contents + +- `labs`: Lab session project sheets. +- `problem-sets`: Graded problem sets. diff --git a/assignments/labs/Makefile b/assignments/labs/Makefile new file mode 100644 index 0000000..d691aaa --- /dev/null +++ b/assignments/labs/Makefile @@ -0,0 +1,17 @@ +all: + @make password-manager + @make secure-messenger + @make zk-battleship + @make proverif + +password-manager: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../../website/labs "password-manager.tex" + +secure-messenger: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../../website/labs "secure-messenger.tex" + +zk-battleship: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../../website/labs "zk-battleship.tex" + +proverif: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../../website/labs "proverif.tex" diff --git a/assignments/labs/README.md b/assignments/labs/README.md new file mode 100644 index 0000000..5ec3f15 --- /dev/null +++ b/assignments/labs/README.md @@ -0,0 +1,9 @@ +# Labs + +- [x] Password Manager +- [x] Secure Messenger +- [x] [ZK Battleship](https://github.com/nategraf/oscw-zkvms-battleship) +- [ ] [ProofFrog](https://prooffrog.github.io) +- [ ] [Verifpal](https://verifpal.com) +- [x] [ProVerif](https://proverif.inria.fr) or [Tamarin](https://tamarin-prover.com) +- [ ] [CTFs](https://ctftime.org/tasks/?tags=crypto&hidden-tags=crypto) if we have time? diff --git a/assignments/labs/password-manager.tex b/assignments/labs/password-manager.tex new file mode 100755 index 0000000..0e6c99e --- /dev/null +++ b/assignments/labs/password-manager.tex @@ -0,0 +1,159 @@ +\documentclass[10pt,a4paper,american]{article} +\newcommand{\aublogopath}{../../website/res/img/aub_black.png} +\usepackage{../../misc/macros/joc} +\usepackage{../../misc/fonts/fonts} +\usepackage{../../misc/macros/classhandout} + +\begin{document} + +\classhandoutheader + +\section*{Lab Assignment: Building a Secure Password Manager} + +\subsection*{Overview} +In this lab, you will design and implement a secure password manager application from scratch. This represents your first opportunity to apply cryptographic primitives to build a complete security protocol—albeit one that operates locally without network communication. Password managers are essential security tools that help users generate, store, and manage their credentials for various services. By building one, you'll gain practical experience with fundamental cryptographic primitives, secure storage techniques, and security-focused software design principles. Future lab assignments will build upon these skills by incorporating network components as you develop secure messengers, encrypted synchronization protocols, and other networked security applications. + +\subsection*{Learning Objectives} +After completing this lab, you should be able to: +\begin{itemize} + \item Apply cryptographic primitives like key derivation functions and authenticated encryption. + \item Implement secure data storage techniques. + \item Design and build a security-critical application with proper threat modeling. + \item Evaluate the security properties of a password management system. +\end{itemize} + +\subsection*{Background} +Password managers solve the problem of creating and remembering strong, unique passwords for multiple services. A password manager typically: +\begin{itemize} + \item Generates cryptographically strong random passwords. + \item Encrypts and securely stores passwords using a master password. + \item Provides convenient access to stored credentials. + \item Protects against various attacks including phishing and data breaches. +\end{itemize} + +\subsection*{Requirements} +Your password manager must implement the following core functionality: + +\begin{enumerate} + \item \textbf{Master Password Handling:} + \begin{itemize} + \item Derive an encryption key from a master password using a suitable KDF (e.g., Argon2, Scrypt). + \item Implement appropriate security parameters (salt, iterations). + \item Correctly handle key rotation in the event of a master password change. + \end{itemize} + + \item \textbf{Password Storage:} + \begin{itemize} + \item Store encrypted passwords with appropriate metadata (website, username). + \item Use authenticated encryption (e.g., AES-GCM) to protect confidentiality and integrity. + \item Implement secure serialization and deserialization. + \end{itemize} + + \item \textbf{Password Generation:} + \begin{itemize} + \item Generate cryptographically secure random passwords. + \item Allow configuration of password characteristics (length, character sets). + \end{itemize} + + \item \textbf{User Interface:} + \begin{itemize} + \item Create a simple CLI or GUI interface for interaction. + \item Implement basic operations: add, retrieve, update, and delete passwords. + \item Include master password verification. + \item Implement clipboard clearing after use. + \item Add timeout for automatic locking. + \item Include proper error handling without leaking sensitive information. + \end{itemize} +\end{enumerate} + +\subsection*{Implementation Guidelines} + +\subsubsection*{Step 1: Design} +Begin by creating a threat model for your password manager. Consider: +\begin{itemize} + \item Who are the attackers? (Malware, physical access, remote attackers) + \item What assets are you protecting? (Master password, stored credentials) + \item What are the attack vectors? (Memory dumps, disk access, etc.) + \item What cryptographic protections will you employ? +\end{itemize} + +Document your design decisions and security assumptions. + +\subsubsection*{Step 2: Cryptographic Building Blocks} +Implement or properly use existing libraries for: +\begin{itemize} + \item Key derivation from the master password. + \item Authenticated encryption of the password database. + \item Secure random password generation. +\end{itemize} + +\subsubsection*{Step 3: Core Functionality} +Implement the core functionality: +\begin{itemize} + \item Database creation and loading. + \item Password entry management. + \item Password generation with customizable par ameters. +\end{itemize} + +\subsubsection*{Step 4: User Interface} +Create an interface that balances security and usability: +\begin{itemize} + \item Master password input (with appropriate masking). + \item Commands for managing entries. + \item Secure display and clipboard operations. +\end{itemize} + +\subsubsection*{Step 5: Security Hardening} +Add security features like: +\begin{itemize} + \item Memory protection techniques. + \item Auto-locking functionality. + \item Input validation and error handling. +\end{itemize} + +\subsection*{Deliverables} +Submit the following: + +\begin{enumerate} + \item Source code for your password manager. + \item Design document including: + \begin{itemize} + \item Threat model and security assumptions. + \item Description of cryptographic mechanisms used. + \item Design decisions and their rationale. + \end{itemize} + \item User manual explaining how to use your password manager + \item Security analysis discussing: + \begin{itemize} + \item Strengths of your implementation. + \item Limitations and potential vulnerabilities. + \item Suggested improvements for a production version. + \end{itemize} +\end{enumerate} + +\subsection*{Evaluation Criteria} +Your project will be evaluated based on: + +\begin{itemize} + \item Correctness of cryptographic implementations. + \item Security of the overall design. + \item Completeness of required functionality. + \item Quality of code and documentation. + \item Thoughtfulness of security analysis. +\end{itemize} + +\subsection*{Resources} +\begin{itemize} + \item The course textbook and materials on symmetric encryption. + \item Libraries: libsodium, OpenSSL, or equivalent based on your language choice. + \item Research papers on password manager security (see course website). +\end{itemize} + +\subsection*{Submission Guidelines} +\begin{itemize} + \item Submit your code as a ZIP archive or through a Git repository. + \item Include all documentation in PDF or Markdown format. + \item Presentations: Prepare a 10-minute presentation demonstrating your password manager. +\end{itemize} + +\end{document} diff --git a/assignments/labs/proverif.tex b/assignments/labs/proverif.tex new file mode 100755 index 0000000..44e82a5 --- /dev/null +++ b/assignments/labs/proverif.tex @@ -0,0 +1,167 @@ +\documentclass[10pt,a4paper,american]{article} +\newcommand{\aublogopath}{../../website/res/img/aub_black.png} +\usepackage{../../misc/macros/joc} +\usepackage{../../misc/fonts/fonts} +\usepackage{../../misc/macros/classhandout} + +\begin{document} + +\classhandoutheader + +\section*{Lab Assignment: Designing and Verifying a TLS-like Protocol using ProVerif} + +\subsection*{Overview} +In this lab, you will design and formally verify a Transport Layer Security (TLS)-like protocol using ProVerif, a formal verification tool for cryptographic protocols. This represents your first opportunity to apply formal methods to verify the security properties of a complete cryptographic protocol—one that provides confidentiality, integrity, and authentication for network communications. By designing and verifying this protocol, you'll gain practical experience with cryptographic protocol design, formal verification, and security property specification. Future lab assignments will build upon these skills by incorporating more complex cryptographic protocols and verification scenarios. + +\subsection*{Learning Objectives} +After completing this lab, you should be able to: +\begin{itemize} + \item Apply formal verification to analyze security properties of cryptographic protocols. + \item Understand and use the ProVerif verification tool. + \item Design and specify a cryptographic protocol with proper threat modeling. + \item Evaluate protocol security properties such as secrecy, authentication, and forward secrecy. +\end{itemize} + +\subsection*{Background} +Formal verification tools like ProVerif allow protocol designers to mathematically verify security properties. In the context of a TLS-like protocol: +\begin{itemize} + \item ProVerif models attackers who have complete control over the communication network. + \item Security properties can be precisely defined and verified, such as confidentiality of session keys. + \item Verification is performed automatically by exploring all possible protocol executions. + \item ProVerif uses symbolic cryptography to reason about cryptographic primitives. +\end{itemize} + +\subsection*{Requirements} +Your TLS-like protocol must implement the following core functionality: + +\begin{enumerate} + \item \textbf{Protocol Initialization:} + \begin{itemize} + \item Design a secure handshake procedure between client and server. + \item Incorporate key exchange mechanisms (e.g., Diffie-Hellman). + \item Implement proper authentication through digital signatures or certificates. + \end{itemize} + + \item \textbf{Key Exchange:} + \begin{itemize} + \item Establish secure session keys between client and server. + \item Ensure forward secrecy for session communications. + \item Protect against Man-in-the-Middle attacks. + \end{itemize} + + \item \textbf{Secure Communication:} + \begin{itemize} + \item Design mechanisms for encrypting and authenticating messages. + \item Implement protection against replay and reordering attacks. + \item Ensure secure session termination. + \end{itemize} + + \item \textbf{Formal Specification:} + \begin{itemize} + \item Model the protocol in ProVerif's applied pi calculus. + \item Define security properties to be verified. + \item Design appropriate queries to check security properties. + \item Include proper protocol termination and error handling. + \end{itemize} +\end{enumerate} + +\subsection*{Implementation Guidelines} + +\subsubsection*{Step 1: Design} +Begin by creating a threat model for your TLS-like protocol. Consider: +\begin{itemize} + \item Who are the attackers? (Network adversaries, malicious endpoints) + \item What assets are you protecting? (Session keys, message confidentiality, authentication) + \item What are the attack vectors? (Man-in-the-Middle, replay, downgrade attacks) + \item What cryptographic protections will you employ? +\end{itemize} + +Document your design decisions and security assumptions. + +\subsubsection*{Step 2: Protocol Specification} +Design your protocol using formal notation: +\begin{itemize} + \item Define message formats and cryptographic operations. + \item Specify the exact sequence of messages exchanged. + \item Define the security properties you expect your protocol to satisfy. +\end{itemize} + +\subsubsection*{Step 3: ProVerif Modeling} +Implement your protocol in ProVerif: +\begin{itemize} + \item Model cryptographic primitives using ProVerif's type system. + \item Define processes for client and server roles. + \item Formalize security properties as queries. + \item Set up the attacker model in ProVerif. +\end{itemize} + +\subsubsection*{Step 4: Verification} +Verify your protocol's security properties: +\begin{itemize} + \item Run ProVerif to check for secrecy violations. + \item Verify authentication properties. + \item Test for resistance against replay attacks. + \item Verify forward secrecy. +\end{itemize} + +\subsubsection*{Step 5: Protocol Refinement} +Improve your protocol based on verification results: +\begin{itemize} + \item Address any vulnerabilities discovered. + \item Optimize the protocol if possible. + \item Document changes and their justifications. +\end{itemize} + +\subsection*{Deliverables} +Submit the following: + +\begin{enumerate} + \item Protocol specification including: + \begin{itemize} + \item Formal description of your TLS-like protocol. + \item Message sequence diagrams. + \item Cryptographic primitives used and their roles. + \end{itemize} + \item ProVerif code implementing your protocol. + \item Design document including: + \begin{itemize} + \item Threat model and security assumptions. + \item Formal security properties being verified. + \item Design decisions and their rationale. + \end{itemize} + \item Security analysis discussing: + \begin{itemize} + \item Verification results from ProVerif. + \item Strengths of your protocol design. + \item Limitations and potential vulnerabilities. + \item Suggested improvements for a production version. + \end{itemize} +\end{enumerate} + +\subsection*{Evaluation Criteria} +Your project will be evaluated based on: + +\begin{itemize} + \item Correctness of ProVerif specifications and queries. + \item Security of the overall protocol design. + \item Completeness of required functionality. + \item Quality of code and documentation. + \item Thoughtfulness of security analysis. +\end{itemize} + +\subsection*{Resources} +\begin{itemize} + \item The course textbook and materials on cryptographic protocols. + \item ProVerif documentation and examples. + \item TLS 1.3 specification for reference. + \item Research papers on formal verification of security protocols (see course website). +\end{itemize} + +\subsection*{Submission Guidelines} +\begin{itemize} + \item Submit your ProVerif code as a ZIP archive or through a Git repository. + \item Include all documentation in PDF or Markdown format. + \item Presentations: Prepare a 10-minute presentation demonstrating your protocol design and verification results. +\end{itemize} + +\end{document} diff --git a/assignments/labs/secure-messenger.tex b/assignments/labs/secure-messenger.tex new file mode 100755 index 0000000..2cc40c5 --- /dev/null +++ b/assignments/labs/secure-messenger.tex @@ -0,0 +1,169 @@ +\documentclass[10pt,a4paper,american]{article} +\newcommand{\aublogopath}{../../website/res/img/aub_black.png} +\usepackage{../../misc/macros/joc} +\usepackage{../../misc/fonts/fonts} +\usepackage{../../misc/macros/classhandout} + +\begin{document} + +\classhandoutheader + +\section*{Lab Assignment: Building a Secure Messenger} + +\subsection*{Overview} +In this lab, you will design and implement a secure messaging application from scratch. This represents an opportunity to apply cryptographic primitives to build a complete end-to-end encrypted communication system. Secure messengers enable users to exchange private information over untrusted networks while protecting confidentiality, integrity, and authenticity of messages. By building one, you'll gain practical experience with cryptographic protocols, network security, and security-focused software design principles. This lab will require you to implement secure key exchange, encrypted message transmission, and proper security guarantees such as forward secrecy and deniability. + +\subsection*{Learning Objectives} +After completing this lab, you should be able to: +\begin{itemize} + \item Apply cryptographic primitives such as public key cryptography and authenticated encryption. + \item Implement secure communication protocols with proper key exchange. + \item Design and build a security-critical networked application with proper threat modeling. + \item Evaluate the security properties of end-to-end encrypted communication systems. +\end{itemize} + +\subsection*{Background} +Secure messaging applications provide private communication over potentially compromised networks. A secure messenger typically: +\begin{itemize} + \item Employs end-to-end encryption to ensure only the intended recipient can read messages. + \item Provides forward secrecy so compromise of current keys doesn't expose previous communications. + \item Authenticates correspondents to prevent message forgery and man-in-the-middle attacks. + \item Protects metadata where possible to minimize surveillance risks. + \item Enables secure group communications and file transfers. +\end{itemize} + +\subsection*{Requirements} +Your secure messenger must implement the following core functionality: + +\begin{enumerate} + \item \textbf{User Identity and Key Management:} + \begin{itemize} + \item Generate cryptographic identities for users (public/private key pairs). + \item Implement secure storage of private keys. + \item Create a mechanism for key exchange and verification. + \item Support key rotation and revocation. + \end{itemize} + + \item \textbf{Message Encryption:} + \begin{itemize} + \item Implement end-to-end encryption using a recognized protocol (e.g., Signal Protocol). + \item Use authenticated encryption for message confidentiality and integrity. + \item Support forward secrecy through proper key ratcheting. + \item Implement a mechanism for secure message serialization and deserialization. + \end{itemize} + + \item \textbf{Communication Features:} + \begin{itemize} + \item Support one-to-one messaging. + \item Include basic message delivery notifications. + \item Implement message persistence with proper encryption at rest. + \end{itemize} + + \item \textbf{User Interface:} + \begin{itemize} + \item Create a simple CLI or GUI interface for interaction. + \item Implement basic operations: send messages, view conversations, and manage contacts. + \item Include proper authentication and session management. + \item Add timeout for automatic logout. + \item Include proper error handling without leaking sensitive information. + \end{itemize} +\end{enumerate} + +\subsection*{Implementation Guidelines} + +\subsubsection*{Step 1: Design} +Begin by creating a threat model for your secure messenger. Consider: +\begin{itemize} + \item Who are the attackers? (Network adversaries, server operators, malicious contacts) + \item What assets are you protecting? (Message content, metadata, contact information) + \item What are the attack vectors? (TLS interception, server compromise, client malware) + \item What cryptographic protections will you employ? +\end{itemize} + +Document your design decisions and security assumptions. + +\subsubsection*{Step 2: Cryptographic Building Blocks} +Implement or properly use existing libraries for: +\begin{itemize} + \item Public-key cryptography for identity and initial key exchange. + \item Symmetric key ratcheting for forward secrecy. + \item Authenticated encryption for message protection. + \item Secure random number generation. +\end{itemize} + +\subsubsection*{Step 3: Core Functionality} +Implement the core functionality: +\begin{itemize} + \item User registration and identity establishment. + \item Contact discovery and key exchange. + \item Message encryption, transmission, and decryption. + \item Session management and key ratcheting. +\end{itemize} + +\subsubsection*{Step 4: User Interface} +Create an interface that balances security and usability: +\begin{itemize} + \item User authentication flow. + \item Conversation view and message composition. + \item Contact management and verification. + \item Security indicators and warnings. +\end{itemize} + +\subsubsection*{Step 5: Security Hardening} +Add security features like: +\begin{itemize} + \item Memory protection techniques for cryptographic material. + \item Protection against replay and message reordering attacks. + \item Input validation and error handling. + \item Secure deletion of messages when requested. +\end{itemize} + +\subsection*{Deliverables} +Submit the following: + +\begin{enumerate} + \item Source code for your secure messenger. + \item Design document including: + \begin{itemize} + \item Threat model and security assumptions. + \item Description of cryptographic mechanisms used. + \item Network protocol specifications. + \item Design decisions and their rationale. + \end{itemize} + \item User manual explaining how to use your secure messenger. + \item Security analysis discussing: + \begin{itemize} + \item Strengths of your implementation. + \item Limitations and potential vulnerabilities. + \item Suggested improvements for a production version. + \end{itemize} +\end{enumerate} + +\subsection*{Evaluation Criteria} +Your project will be evaluated based on: + +\begin{itemize} + \item Correctness of cryptographic implementations. + \item Security of the overall design and protocol. + \item Completeness of required functionality. + \item Quality of code and documentation. + \item Thoughtfulness of security analysis. + \item Robustness against the threats identified in your model. +\end{itemize} + +\subsection*{Resources} +\begin{itemize} + \item The course textbook and materials on public-key cryptography and secure protocols. + \item Libraries: libsodium, OpenSSL, Signal Protocol libraries based on your language choice. + \item Research papers on secure messaging protocols (see course website). + \item Specifications for Signal Protocol, OTR, or Matrix. +\end{itemize} + +\subsection*{Submission Guidelines} +\begin{itemize} + \item Submit your code as a ZIP archive or through a Git repository. + \item Include all documentation in PDF or Markdown format. + \item Presentations: Prepare a 10-minute presentation demonstrating your secure messenger. +\end{itemize} + +\end{document} diff --git a/assignments/labs/zk-battleship.tex b/assignments/labs/zk-battleship.tex new file mode 100755 index 0000000..df5ab72 --- /dev/null +++ b/assignments/labs/zk-battleship.tex @@ -0,0 +1,159 @@ +\documentclass[10pt,a4paper,american]{article} +\newcommand{\aublogopath}{../../website/res/img/aub_black.png} +\usepackage{../../misc/macros/joc} +\usepackage{../../misc/fonts/fonts} +\usepackage{../../misc/macros/classhandout} + +\begin{document} + +\classhandoutheader + +\section*{Lab Assignment: Building a Zero-Knowledge Battleship Game} + +\subsection*{Overview} +In this lab, you will design and implement a zero-knowledge battleship game using RISC Zero, a zero-knowledge virtual machine (zkVM). This represents your first opportunity to apply zero-knowledge proofs to build a complete cryptographic protocol—one that allows players to validate their moves without revealing the entire game state. Zero-knowledge battleship demonstrates how players can validate that their guesses produced the correct result (hit vs. no hit) while learning nothing about the opponent's board except what is explicitly revealed through gameplay. By building this game, you'll gain practical experience with zero-knowledge proofs, zkVMs, and cryptographic protocol design. Future lab assignments will build upon these skills by incorporating more complex zero-knowledge applications. + +\subsection*{Learning Objectives} +After completing this lab, you should be able to: +\begin{itemize} + \item Apply zero-knowledge proofs to create verifiable computations. + \item Understand and use zkVMs, particularly RISC Zero. + \item Design and build a cryptographic protocol with proper threat modeling. + \item Evaluate the security properties of zero-knowledge applications. +\end{itemize} + +\subsection*{Background} +Zero-knowledge proofs allow one party (the prover) to prove to another party (the verifier) that a statement is true without revealing any additional information. In the context of a battleship game: +\begin{itemize} + \item Player 1 can prove whether Player 2's guess hit or missed a ship. + \item The proof is verifiable by Player 2 without revealing the full board layout. + \item The game remains secure against cheating because all moves can be verified. + \item zkVMs like RISC Zero allow developers to generate proofs for arbitrary computations. +\end{itemize} + +\subsection*{Requirements} +Your zero-knowledge battleship game must implement the following core functionality: + +\begin{enumerate} + \item \textbf{Game Initialization:} + \begin{itemize} + \item Create a secure board setup procedure where players place ships. + \item Generate cryptographic commitments to board layouts. + \item Implement proper validation of initial board configurations. + \end{itemize} + + \item \textbf{Game Rounds:} + \begin{itemize} + \item Generate zero-knowledge proofs for hit/miss responses using RISC Zero. + \item Verify proofs to ensure honest gameplay. + \item Track game state securely throughout the game. + \end{itemize} + + \item \textbf{Game Logic:} + \begin{itemize} + \item Implement standard battleship rules. + \item Detect when a player has won the game. + \item Ensure all game state transitions are verifiable. + \end{itemize} + + \item \textbf{User Interface:} + \begin{itemize} + \item Create a simple CLI interface for gameplay. + \item Display the game boards (with appropriate information hiding). + \item Implement commands for making guesses and viewing game status. + \item Include proper error handling without leaking sensitive information. + \end{itemize} +\end{enumerate} + +\subsection*{Implementation Guidelines} + +\subsubsection*{Step 1: Design} +Begin by creating a threat model for your zero-knowledge battleship game. Consider: +\begin{itemize} + \item Who are the attackers? (Cheating players, observers) + \item What assets are you protecting? (Board layouts, game integrity) + \item What are the attack vectors? (False claims about hits/misses, board manipulation) + \item What cryptographic protections will you employ? +\end{itemize} + +Document your design decisions and security assumptions. + +\subsubsection*{Step 2: Cryptographic Building Blocks} +Implement or properly use RISC Zero for: +\begin{itemize} + \item Creating guest programs to verify hits and misses. + \item Generating and verifying zero-knowledge proofs. + \item Securing the game state throughout gameplay. +\end{itemize} + +\subsubsection*{Step 3: Core Functionality} +Implement the core functionality: +\begin{itemize} + \item Board initialization and commitment. + \item Move validation with zero-knowledge proofs. + \item Game state management and victory detection. +\end{itemize} + +\subsubsection*{Step 4: User Interface} +Create an interface that balances security and usability: +\begin{itemize} + \item Board visualization showing appropriate information. + \item Commands for making guesses. + \item Clear indication of proof validation results. +\end{itemize} + +\subsubsection*{Step 5: Security Hardening} +Add security features like: +\begin{itemize} + \item Verification of all cryptographic proofs. + \item Protection against replay and timing attacks. + \item Input validation and error handling. +\end{itemize} + +\subsection*{Deliverables} +Submit the following: + +\begin{enumerate} + \item Source code for your zero-knowledge battleship game. + \item Design document including: + \begin{itemize} + \item Threat model and security assumptions. + \item Description of zero-knowledge mechanisms used. + \item Design decisions and their rationale. + \end{itemize} + \item User manual explaining how to play your game. + \item Security analysis discussing: + \begin{itemize} + \item Strengths of your implementation. + \item Limitations and potential vulnerabilities. + \item Suggested improvements for a production version. + \end{itemize} +\end{enumerate} + +\subsection*{Evaluation Criteria} +Your project will be evaluated based on: + +\begin{itemize} + \item Correctness of zero-knowledge proof implementations. + \item Security of the overall design. + \item Completeness of required functionality. + \item Quality of code and documentation. + \item Thoughtfulness of security analysis. +\end{itemize} + +\subsection*{Resources} +\begin{itemize} + \item The course textbook and materials on zero-knowledge proofs. + \item RISC Zero documentation and examples. + \item Directory structure and README provided for the project. + \item Research papers on zero-knowledge applications (see course website). +\end{itemize} + +\subsection*{Submission Guidelines} +\begin{itemize} + \item Submit your code as a ZIP archive or through a Git repository. + \item Include all documentation in PDF or Markdown format. + \item Presentations: Prepare a 10-minute presentation demonstrating your zero-knowledge battleship game. +\end{itemize} + +\end{document} diff --git a/assignments/problem-sets/Makefile b/assignments/problem-sets/Makefile new file mode 100644 index 0000000..cffa098 --- /dev/null +++ b/assignments/problem-sets/Makefile @@ -0,0 +1,13 @@ +all: + @make problem-set-1 + @make problem-set-2 + @make problem-set-3 + +problem-set-1: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../../website/problem-sets "problem-set-1.tex" + +problem-set-2: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../../website/problem-sets "problem-set-2.tex" + +problem-set-3: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../../website/problem-sets "problem-set-3.tex" diff --git a/assignments/problem-sets/NOTES.md b/assignments/problem-sets/NOTES.md new file mode 100644 index 0000000..7f6b105 --- /dev/null +++ b/assignments/problem-sets/NOTES.md @@ -0,0 +1,28 @@ +# Ideas for later problem sets + +```latex +\item (5 points) \textbf{TLS Under Attack:} +An advanced persistent threat (APT) group has compromised several Certificate Authorities and can issue valid certificates for any domain. +\begin{enumerate} + \item Analyze exactly how this compromise allows attacks against TLS connections, even when users see the "secure" padlock icon. + \item Design countermeasures that could be deployed by browser vendors to detect and prevent these attacks. Consider both technical and usability constraints. + \item Evaluate certificate pinning as a solution: when does it work, when does it fail, and how should it be deployed? + \item Compare your solutions to Certificate Transparency. What attacks does CT prevent, and what attacks does it miss? +\end{enumerate} + +\item (5 points) \textbf{Signal's Double Ratchet Design Challenge:} +You're designing the next version of Signal's messaging protocol and want to improve upon the current Double Ratchet algorithm. +\begin{enumerate} + \item Analyze the trade-off between security and performance in the current design: why does Signal perform a new DH exchange for each message direction rather than just once per conversation? + \item Design an optimization that reduces the number of DH operations while maintaining the same security properties. What compromises would you accept? + \item Consider a group messaging scenario with 100 participants. How would you adapt your design to provide forward secrecy and post-compromise security for group conversations? +\end{enumerate} + +\item (5 points) \textbf{Quantum Timeline Decision Making:} +You're the CTO of a company building a secure messaging app expected to launch in 2028 and remain secure until 2040. Intelligence reports suggest large-scale quantum computers might exist by 2035, but with significant uncertainty (could be 2030 or 2045). +\begin{enumerate} + \item Design a migration strategy that balances current performance needs with future quantum threats. What algorithms do you deploy now, and when do you plan upgrades? + \item Analyze the "harvest now, decrypt later" threat: what data in your system needs protection beyond 2035, and how does this influence your cryptographic choices? + \item Evaluate the trade-offs between early adoption of post-quantum cryptography (larger keys, unproven security) versus delayed migration (quantum vulnerability risk). +\end{enumerate} +``` diff --git a/assignments/problem-sets/README.md b/assignments/problem-sets/README.md new file mode 100644 index 0000000..341d60b --- /dev/null +++ b/assignments/problem-sets/README.md @@ -0,0 +1,5 @@ +# Problem Sets + +- Problem Set 1: Covering lectures 1-1, 1-2 and 1-3. +- Problem Set 2: Covering lectures 1-4, 1-5 and 1-6. +- Problem Set 2: Covering lectures 1-7 and 1-8. diff --git a/assignments/problem-sets/problem-set-1.tex b/assignments/problem-sets/problem-set-1.tex new file mode 100644 index 0000000..fd18801 --- /dev/null +++ b/assignments/problem-sets/problem-set-1.tex @@ -0,0 +1,342 @@ +\documentclass[10pt,a4paper,american]{article} +\newcommand{\aublogopath}{../../website/res/img/aub_black.png} +\usepackage{../../misc/macros/joc} +\usepackage{../../misc/fonts/fonts} +\usepackage{../../misc/macros/classhandout} + +\begin{document} + +\classhandoutheader + +\section*{Problem Set 1: Provable Security Foundations} + +\begin{tcolorbox}[colframe=OliveGreen!30!white,colback=OliveGreen!5!white] + \textbf{Instructions:} This problem set covers the foundations of provable security from parts 1.1\footnote{\url{https://appliedcryptography.page/slides/1-1.pdf}}, 1.2\footnote{\url{https://appliedcryptography.page/slides/1-2.pdf}} and 1.3\footnote{\url{https://appliedcryptography.page/slides/1-3.pdf}} of the course. Submit your solutions as a neatly formatted PDF. You are encouraged to collaborate with classmates in studying the material, but your submitted solutions must be your own work. For proofs, clearly state your assumptions, steps, and conclusions. +\end{tcolorbox} + +\section{Cryptographic Foundations (20 points)} + +\subsection{Basic Concepts (10 points)} + +\begin{enumerate} + \item (3 points) Define the three primary security goals of cryptography in your own words and provide a real-world example for each that wasn't explicitly mentioned in the lectures. + + \item (3 points) Explain Kerckhoff's principle and why it remains fundamental to modern cryptography. Provide an example of a security system that violates this principle and describe the potential consequences. + + \item (4 points) Compare and contrast symmetric and asymmetric cryptography: + \begin{enumerate} + \item Explain the fundamental difference in their key management approach. + \item For each type, identify which mathematical or computational assumptions their security typically relies on. + \item Describe a scenario where one would be clearly preferable to the other. + \end{enumerate} +\end{enumerate} + +\subsection{Perfect Secrecy (10 points)} + +\begin{enumerate} + \item (3 points) Consider a modified one-time pad where we use the bitwise AND ($\land$) operation instead of XOR ($\oplus$): + + $\textsf{Enc}(K, M) = K \land M$ and $\textsf{Dec}(K, C) = ?$ + + \begin{enumerate} + \item Is this scheme correct? If yes, specify the decryption function. If not, explain why. + \item Does this scheme provide perfect secrecy? Justify your answer. + \end{enumerate} + + \item (4 points) Consider the following variant of a one-time pad operating on decimal digits (0-9): + + $\textsf{Enc}(K, M) = (K + M) \bmod 10$ and $\textsf{Dec}(K, C) = (C - K) \bmod 10$ + + where $K, M, C \in \{0, 1, 2, \ldots, 9\}$. + + \begin{enumerate} + \item Prove that this scheme is correct. + \item Prove that this scheme provides perfect secrecy, assuming $K$ is chosen uniformly at random. + \end{enumerate} + + \item (3 points) Consider a one-time pad where the key length is half the message length: + + $\textsf{Enc}(K, M) = (K \oplus M_1, K \oplus M_2)$ where $M = (M_1, M_2)$ and $|M_1| = |M_2| = |K|$. + + Provide a specific attack that breaks the confidentiality of this scheme, showing clearly the information an attacker can extract from the ciphertext. +\end{enumerate} + +\section{Provable Security (20 points)} + +\subsection{Libraries and Interchangeability (10 points)} + +\begin{enumerate} + \item (5 points) Consider the following libraries: + \begin{center} + \sslinked{ + \sslibrary{}{1}{ + \sslibrarysubroutine{init}{}{ + $K \twoheadleftarrow \bits^n$ + }{1}\\[1em] + \sslibrarysubroutine{query}{M}{ + return $K \oplus M$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{2}{ + \sslibrarysubroutine{init}{}{ + $R_1 \twoheadleftarrow \bits^n$ \\ + $R_2 \twoheadleftarrow \bits^n$ + }{1}\\[1em] + \sslibrarysubroutine{query}{M}{ + if $M = R_1$ return $R_2$ \\ + else return $M \oplus R_1 \oplus R_2$ + }{1} + }{1} + } + \end{center} + Are these libraries interchangeable? Either prove they are interchangeable or provide a distinguisher program that can tell them apart with non-negligible probability. + + \item (5 points) For each of the following pairs of libraries, state whether they are interchangeable and briefly justify your answer: + \begin{enumerate} + \item + \begin{center} + \sslinked{ + \sslibrary{}{A}{ + \sslibrarysubroutine{f}{x}{ + $y \twoheadleftarrow \bits^n$ \\ + return $y$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{B}{ + \sslibrarysubroutine{f}{x}{ + $y \twoheadleftarrow \bits^n$ \\ + $z \twoheadleftarrow \bits^n$ \\ + return $y$ + }{1} + }{1} + } + \end{center} + + \item + \begin{center} + \sslinked{ + \sslibrary{}{C}{ + $K \twoheadleftarrow \bits^n$\\[1em] + \sslibrarysubroutine{enc}{M}{ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1}\\[1em] + \sslibrarysubroutine{dec}{C}{ + $M \coloneq K \oplus C$ \\ + return $M$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{D}{ + \sslibrarysubroutine{enc}{M}{ + $C \twoheadleftarrow \bits^n$ \\ + return $C$ + }{1}\\[1em] + \sslibrarysubroutine{dec}{C}{ + $M \twoheadleftarrow \bits^n$ \\ + return $M$ + }{1} + }{1} + } + \end{center} + \end{enumerate} +\end{enumerate} + +\subsection{Security Proofs (10 points)} + +\begin{enumerate} + \item (5 points) Let $\Sigma = (\textsf{KeyGen}, \textsf{Enc}, \textsf{Dec})$ be a secure encryption scheme for messages in $\bits^n$. Consider the following modified scheme $\Sigma' = (\textsf{KeyGen}', \textsf{Enc}', \textsf{Dec}')$: + \begin{align*} + \textsf{KeyGen}'() & = K \twoheadleftarrow \textsf{KeyGen}() \\ + \textsf{Enc}'(K, M) & = (C_1, C_2) \text{ where } C_1 \twoheadleftarrow \textsf{Enc}(K, M) \text{ and } C_2 \twoheadleftarrow \textsf{Enc}(K, M \oplus 1^n) \\ + \textsf{Dec}'(K, (C_1, C_2)) & = \textsf{Dec}(K, C_1) + \end{align*} + + Determine whether $\Sigma'$ is a secure encryption scheme. If it is secure, provide a formal proof. If it is not secure, describe a concrete attack that breaks its confidentiality and explain why the attack works. + + \item (5 points) Consider the following game between a challenger and an adversary $\mathcal{A}$: + \begin{enumerate} + \item The adversary selects two messages $M_0$ and $M_1$ of the same length. + \item The challenger selects a uniform random bit $b \twoheadleftarrow \bits$ and a uniform random key $K \twoheadleftarrow \bits^n$. + \item The challenger computes $C = K \oplus M_b$ and gives $C$ to the adversary. + \item The adversary outputs a bit $b'$ as its guess for $b$. + \end{enumerate} + + Prove that for any adversary $\mathcal{A}$, the probability that $b' = b$ is exactly $1/2$. Explain what this result tells us about the security of the one-time pad. +\end{enumerate} + +\section{Computational Cryptography (30 points)} + +\subsection{Computational Security Concepts (15 points)} + +\begin{enumerate} + \item (5 points) Explain why computational security is important in practice despite the existence of information-theoretic security. Discuss the limitations of both approaches. + + \item (4 points) Consider a brute-force attack on AES-128: + \begin{enumerate} + \item Using the monetary cost table provided in the lecture, estimate how much it would cost to try all possible keys. + \item Discuss whether the computational approach to security makes sense in light of this cost. + \end{enumerate} + + \item (3 points) Define a negligible function formally. Then determine which of the following functions are negligible (where $\lambda$ is the security parameter): + \begin{enumerate} + \item $f_1(\lambda) = 2^{-\lambda}$ + \item $f_2(\lambda) = \lambda^{-\log \lambda}$ + \item $f_3(\lambda) = 2^{-\sqrt{\lambda}}$ + \item $f_4(\lambda) = \frac{1}{\lambda \cdot 2^{\lambda/2}}$ + \end{enumerate} + + \item (3 points) The ``birthday paradox'' is crucial for understanding many cryptographic attacks. If a hash function produces outputs of length $n$ bits: + \begin{enumerate} + \item Approximately how many random inputs would you need to hash before finding a collision with 50\% probability? + \item How many bits of output would a hash function need to be reasonably secure against birthday attacks for the next decade? + \end{enumerate} +\end{enumerate} + +\subsection{Distinguishability and Bad Events (15 points)} + +\begin{enumerate} + \item (6 points) Consider the following two libraries that implement a 256-bit hash function: + \begin{center} + \sslinked{ + \sslibrary{}{real}{ + \sslibrarysubroutine{hash}{X}{ + return SHA-256(x) + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{hash}{X}{ + if $L[X]$ undefined:\\ + \quad $L[X] \twoheadleftarrow \bits^{256}$\\ + return $L[X]$ + }{1} + }{1} + } + \end{center} + + \begin{enumerate} + \item Describe the ``bad event'' that would allow these libraries to be distinguished. + \item If an adversary is limited to $q$ queries, what is the probability of triggering this bad event? + \item Using the ``bad event'' proof technique, show that these libraries are computationally indistinguishable when $q$ is polynomial in the security parameter. + \end{enumerate} + + \item (4 points) Consider the following two libraries: + \begin{center} + \sslinked{ + \sslibrary{}{1}{ + \sslibrarysubroutine{sample}{}{ + $X \twoheadleftarrow \bits^n$ \\ + $Y \coloneq X \oplus 1^n$ \\ + return $(X, Y)$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{2}{ + \sslibrarysubroutine{sample}{}{ + $Y \twoheadleftarrow \bits^n$ \\ + $X \coloneq Y \oplus 1^n$ \\ + return $(X, Y)$ + }{1} + }{1} + } + \end{center} + Use the hybrid proof technique to show these libraries are interchangeable. Clearly describe each intermediate hybrid library. + + \item (5 points) Consider a PRF $F: \bits^n \times \bits^n \rightarrow \bits^n$ and the following two libraries: + \begin{center} + \sslinked{ + \sslibrary{}{{\text{PRF}}}{ + $K \twoheadleftarrow \bits^n$\\[1em] + \sslibrarysubroutine{query}{x}{ + return $F(K, X)$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{query}{x}{ + if $L[X]$ undefined:\\ + \quad $L[X] \twoheadleftarrow \bits^n$\\ + return $L[X]$ + }{1} + }{1} + } + \end{center} + Suppose we have a program $\mathcal{A}$ that can distinguish between these libraries with advantage $\varepsilon$. Construct a program $\mathcal{B}$ that uses $\mathcal{A}$ as a subroutine to distinguish a PRF from a truly random function with the same advantage $\varepsilon$. +\end{enumerate} + +\section{Application of Cryptographic Principles (30 points)} + +\begin{enumerate} + \item (10 points) \textbf{Block Cipher Mode Analysis} + + The lecture demonstrated how ECB mode reveals patterns in the plaintext. For each of the following block cipher modes, explain: + \begin{enumerate} + \item How the encryption and decryption work. + \item What would happen if the same key and IV (when applicable) were reused for multiple messages. + \item A specific real-world situation where this mode would be most appropriate. + \end{enumerate} + + Modes to analyze: + \begin{enumerate} + \item Cipher Block Chaining (CBC) + \item Counter Mode (CTR) + \end{enumerate} + + \item (10 points) \textbf{One-Time Pad in the Real World} + + A startup claims to have developed a ``quantum-resistant ultra-secure messaging system'' based on the one-time pad. They provide the following details: + + \begin{itemize} + \item The system uses a hardware random number generator to produce one-time pads. + \item Each user receives a 1TB USB drive containing pre-generated pad data during account registration. + \item When sending a message, the app encrypts it with a portion of the pad, marks that portion as used, and sends the ciphertext. + \item When the user has used 80\% of their pad, the app automatically requests a new USB drive. + \end{itemize} + + Provide a detailed critique of this system: + \begin{enumerate} + \item Identify at least three practical problems with this implementation. + \item Explain how each problem compromises security or usability. + \item Suggest improvements to address each issue while maintaining the theoretical security of OTP. + \end{enumerate} + + \item (10 points) \textbf{Symmetric Encryption Protocol Analysis} + + A software company is implementing a secure communication protocol for their instant messaging application. They propose the following scheme: + + \begin{itemize} + \item Each user generates a random 128-bit key $K$ during account creation. + \item To send a message $M$, the sender computes $C = K \oplus M$ and transmits $C$. + \item When two users want to communicate, they first exchange their keys through a ``top secret channel'' established by the company's server. + \item The company claims their protocol is ``as secure as one-time pad'' because they use the XOR operation. + \end{itemize} + + Address the following aspects of this system: + \begin{enumerate} + \item Using the provable security framework discussed in class, analyze whether this scheme provides the confidentiality properties claimed by the company. + \item Identify at least three major security vulnerabilities in the described approach. + \item The company is considering having users generate new keys daily instead of just once. Explain whether this modification would address the vulnerabilities you identified. + \item Propose a modified protocol that would significantly improve security while still using only symmetric cryptography concepts covered in class so far. Justify your choices using the security principles we've discussed. + \end{enumerate} +\end{enumerate} + +\begin{tcolorbox}[colframe=EarthBrown!30!white,colback=EarthBrown!5!white] + \textbf{Bonus Challenge (20 extra points):} The discrete logarithm problem is fundamental to many cryptographic systems. Consider a cyclic group $G$ of prime order $p$ with generator $g$. The discrete logarithm problem is: given $h \in G$, find $x$ such that $g^x = h$. + + Imagine a scenario where the discrete logarithm problem could be solved efficiently. Select one modern cryptographic protocol that relies on the hardness of this problem, and analyze: + + \begin{enumerate} + \item The specific impact on the protocol's security. + \item How the protocol would need to be modified to remain secure. + \item Whether any alternative mathematical problems could serve as suitable replacements. + \end{enumerate} + + Your answer should demonstrate deep understanding of both the protocol and the underlying mathematical principles. +\end{tcolorbox} + +\end{document} diff --git a/assignments/problem-sets/problem-set-2.tex b/assignments/problem-sets/problem-set-2.tex new file mode 100644 index 0000000..817c239 --- /dev/null +++ b/assignments/problem-sets/problem-set-2.tex @@ -0,0 +1,259 @@ +\documentclass[10pt,a4paper,american]{article} +\newcommand{\aublogopath}{../../website/res/img/aub_black.png} +\usepackage{../../misc/macros/joc} +\usepackage{../../misc/fonts/fonts} +\usepackage{../../misc/macros/classhandout} + +\begin{document} + +\classhandoutheader + +\section*{Problem Set 2: Symmetric Cryptography} + +\begin{tcolorbox}[colframe=OliveGreen!30!white,colback=OliveGreen!5!white] + \textbf{Instructions:} This problem set covers topics in provable security from parts 1.4\footnote{\url{https://appliedcryptography.page/slides/1-4.pdf}}, 1.5\footnote{\url{https://appliedcryptography.page/slides/1-5.pdf}} and 1.6\footnote{\url{https://appliedcryptography.page/slides/1-6.pdf}} of the course. Submit your solutions as a neatly formatted PDF. You are encouraged to collaborate with classmates in studying the material, but your submitted solutions must be your own work. For proofs, clearly state your assumptions, steps, and conclusions. +\end{tcolorbox} + +\section{Pseudorandomness (20 points)} + +\subsection{Pseudorandom Generators (10 points)} + +\begin{enumerate} + \item (3 points) Explain the limitations of the one-time pad for practical encryption and why pseudorandom generators (PRGs) are needed in modern cryptographic systems. + + \item (3 points) Analyze the security implications of the following PRG construction, where $G$ is a secure PRG: + \begin{align*} + H(S) = A \| B \| C \| D \text{ where } A \| B = G(S) \text{ and } C \| D = G(B) + \end{align*} + Determine whether $H$ is a secure PRG. If not, provide a distinguisher that can tell apart $H(S)$ from a truly random string with non-negligible advantage. + + \item (4 points) Consider the stream cipher RC4: + \begin{enumerate} + \item Describe the key components of RC4's design and how it generates a pseudorandom keystream. + \item Explain two significant weaknesses that led to RC4 being considered cryptographically broken today. + \item What modern alternatives would you recommend as replacements for RC4, and why? + \end{enumerate} +\end{enumerate} + +\subsection{Pseudorandom Functions and Permutations (10 points)} + +\begin{enumerate} + \item (3 points) Consider the following PRF construction: $F(K, X) = G(K) \oplus X$, where $G$ is a secure PRG. + \begin{enumerate} + \item Is $F$ a secure PRF? If not, describe a distinguisher that can effectively tell $F$ apart from a random function. + \item Explain how this example illustrates the ``Golden Rule of PRFs.'' + \end{enumerate} + + \item (4 points) For Feistel ciphers: + \begin{enumerate} + \item Explain why a 2-round Feistel cipher cannot be a secure pseudorandom permutation (PRP). + \item Prove that Feistel ciphers are always permutations, regardless of the security of their round functions. + \end{enumerate} + + \item (3 points) Compare and contrast PRFs and PRPs: + \begin{enumerate} + \item Explain the key differences in their definitions and properties. + \item Describe how PRPs can be ``downgraded'' to PRFs, but not necessarily vice versa. + \item Explain why collisions are inevitable for PRFs but not for PRPs. + \end{enumerate} +\end{enumerate} + +\section{Chosen-Plaintext and Chosen-Ciphertext Attacks (20 points)} + +\subsection{CPA Security (10 points)} + +\begin{enumerate} + \item (5 points) Consider the CPA security definition: + \begin{center} + \sslinked{ + \sslibrary{\Sigma}{cpa-real}{ + $K \twoheadleftarrow \Sigma.\mathcal{K}$\\[1em] + \sslibrarysubroutine{cpa.enc}{M}{ + $C \coloneq \Sigma.\texttt{Enc}(K, M)$\\ + return $C$ + }{1} + }{0.8} + }{\approxeq}{ + \sslibrary{\Sigma}{cpa-rand}{ + \sslibrarysubroutine{cpa.enc}{M}{ + $C \twoheadleftarrow \Sigma.\mathcal{C}(|M|)$\\ + return $C$ + }{1} + }{0.8} + } + \end{center} + \begin{enumerate} + \item Explain why deterministic encryption schemes always fail CPA security. + \item Construct a simple distinguisher program that can break the CPA security of any deterministic encryption scheme. + \item Analyze what practical security vulnerabilities exist in systems that use non-CPA-secure encryption. + \end{enumerate} + + \item (5 points) For each of the following encryption schemes, determine whether it achieves CPA security. If not, provide a specific attack: + \begin{enumerate} + \item $\textsf{Enc}(K, M) = (R, F(K, R) \oplus M)$ where $R \twoheadleftarrow \{0,1\}^{\lambda}$ and $F$ is a secure PRF. + \item $\textsf{Enc}(K, M) = (R, F(K, M) \oplus R)$ where $R \twoheadleftarrow \{0,1\}^{\lambda}$ and $F$ is a secure PRF. + \item AES in Electronic Codebook (ECB) mode. + \item AES in Counter (CTR) mode with a randomly chosen IV. + \end{enumerate} +\end{enumerate} + +\subsection{CCA Security and Authenticated Encryption (10 points)} + +\begin{enumerate} + \item (3 points) Format oracle attacks: + \begin{enumerate} + \item Explain how the null-oracle attack works against CTR mode encryption and why it's devastating despite CTR mode being CPA-secure. + \item Describe a real-world scenario where a format oracle might be inadvertently exposed in a cryptographic system. + \item Calculate the approximate number of oracle queries needed to recover a 1 KB file using the null-oracle attack, and explain why this is practical for an attacker. + \end{enumerate} + + \item (4 points) For the following encryption scheme constructions, determine whether each provides CCA security and/or authenticated encryption (AE). Justify your answers with brief explanations: + \begin{enumerate} + \item Encrypt-then-MAC: $C = \textsf{Enc}(K_e, M)$, $T = \textsf{MAC}(K_m, C)$, output $(C, T)$ + \item Encrypt-and-MAC: $C = \textsf{Enc}(K_e, M)$, $T = \textsf{MAC}(K_m, M)$, output $(C, T)$ + \item MAC-then-encrypt: $T = \textsf{MAC}(K_m, M)$, $C = \textsf{Enc}(K_e, M\|T)$, output $C$ + \item Explain a scenario where replay attacks could succeed even against a system using authenticated encryption, and how associated data (AD) addresses this vulnerability. + \end{enumerate} + + \item (3 points) AES-GCM (Galois/Counter Mode): + \begin{enumerate} + \item Explain how AES-GCM combines CTR mode encryption with Galois field multiplication for authentication. What security advantages does this provide over using separate encryption and MAC algorithms? + \item Describe the critical security implications of nonce reuse in AES-GCM. What specific vulnerabilities arise when the same nonce is used for multiple messages? + \item AES-GCM is sometimes implemented with different tag lengths. Analyze the security tradeoffs when using 128-bit tags versus 64-bit or 32-bit tags. + \item Aside from nonce reuse, what is an unexpected vulnerability in AES-GCM that developers and engineers might not be aware of, but that might significantly impact the security of their software? + \end{enumerate} +\end{enumerate} + +\section{Collision-Resistant Hash Functions (30 points)} + +\subsection{Hash Function Properties (15 points)} + +\begin{enumerate} + \item (5 points) Collision resistance: + \begin{enumerate} + \item Explain why collisions must exist in any hash function that maps arbitrary-length inputs to fixed-length outputs. + \item Using the birthday paradox, calculate approximately how many hashes must be computed to find a collision with 50\% probability in a 256-bit secure hash function. + \item Describe a practical attack scenario where finding hash collisions would compromise a security system. + \end{enumerate} + + \item (5 points) Hash function construction: + \begin{enumerate} + \item Compare and contrast the Merkle-Damgård construction (used in SHA-2) and the Sponge construction (used in SHA-3). + \item Explain how length extension attacks work against Merkle-Damgård hash functions and why the Sponge construction is resistant to these attacks. + \item Describe the HMAC construction and explain how it protects against length extension attacks. + \end{enumerate} + + \item (5 points) Hash function evolution: + \begin{enumerate} + \item Describe the successful attacks against MD5 and SHA-1 that led to their deprecation. + \item Explain the concept of chosen-prefix collisions and why they are particularly dangerous for certificate authorities. + \item Compare the security of SHA-2 and SHA-3 against known cryptanalytic techniques. + \end{enumerate} +\end{enumerate} + +\subsection{Password Hashing (15 points)} + +\begin{enumerate} + \item (5 points) For each of the following password storage approaches, analyze the security implications if a server database is compromised: + \begin{enumerate} + \item Storing passwords in plaintext. + \item Encrypting passwords with a key stored on the same server. + \item Storing unsalted SHA-256 hashes of passwords. + \item Storing salted SHA-256 hashes of passwords. + \item Using a specialized password hashing function like Scrypt. + \end{enumerate} + + \item (5 points) Salting: + \begin{enumerate} + \item Explain how salt protects against precomputation attacks like rainbow tables. + \item Calculate the storage requirements for properly salted password hashes, assuming 10,000 users, 16-byte salts, and 32-byte hash outputs. + \item Describe best practices for generating and storing salts. + \end{enumerate} + + \item (5 points) Specialized password hashing functions: + \begin{enumerate} + \item Explain why memory-hard functions like Scrypt provide better protection against specialized hardware attacks compared to PBKDF2. + \item Describe how each of Scrypt's parameters (N, r, p) affect its security and performance. + \item Compare the relative speeds of SHA-256, PBKDF2, and Scrypt for password hashing, and explain the security implications of these speed differences. + \end{enumerate} +\end{enumerate} + +\section{Applied Cryptography Case Studies (30 points)} + +\begin{enumerate} + \item (10 points) \textbf{Block Cipher Modes Analysis} + + With reference to the block cipher modes covered in lectures 1-4, 1-5, and 1-6, analyze the following scenarios: + \begin{enumerate} + \item A secure file storage application needs to encrypt user files at rest. Compare CBC, CTR, and AES-GCM modes for this application, discussing: + \begin{itemize} + \item Performance implications for large files. + \item Error propagation if parts of the ciphertext are corrupted. + \item The security implications of IV/nonce reuse. + \item Data integrity guarantees and the advantages of authenticated encryption with AES-GCM. + \end{itemize} + \item A real-time messaging application needs to encrypt short messages with minimal latency. Compare CBC, CTR, and AES-GCM modes for this application, discussing: + \begin{itemize} + \item Parallelizability for encryption/decryption. + \item Suitability for streaming data. + \item Protection against chosen-ciphertext attacks. + \item How AES-GCM addresses authentication needs compared to unauthenticated modes. + \end{itemize} + \item For AES-GCM specifically: + \begin{itemize} + \item Explain the security impact of nonce reuse in AES-GCM compared to nonce reuse in CTR mode. + \item Discuss the performance tradeoffs of AES-GCM compared to using separate encryption (CTR mode) and authentication (HMAC). + \item Explain how AES-GCM's authenticated encryption properties protect against attacks that would succeed against CBC or CTR modes. + \end{itemize} + \end{enumerate} + + \item (10 points) \textbf{Hash Function Security Analysis} + + A software update system uses hash functions to verify the integrity of downloads. The system works as follows: + \begin{itemize} + \item The software vendor posts SHA-1 hashes of legitimate update files on their HTTPS website. + \item Users download the update file over HTTP (not HTTPS) for bandwidth efficiency. + \item The update client verifies the downloaded file by computing its SHA-1 hash and comparing it to the hash obtained from the HTTPS website. + \item If the hashes match, the update is installed automatically. + \end{itemize} + + Analyze this system: + \begin{enumerate} + \item Identify at least three security vulnerabilities in this design. + \item For each vulnerability, describe a specific attack scenario. + \item Propose improvements to address each vulnerability while maintaining performance and usability. + \item Design a more secure alternative system using modern cryptographic primitives discussed in class. + \end{enumerate} + + \item (10 points) \textbf{Password Management System Design} + + You are designing a password management system for a new web application with the following requirements: + \begin{itemize} + \item Users must be able to securely recover their account if they forget their password. + \item The system must be resistant to offline dictionary attacks if the database is compromised. + \item The system must support high-performance authentication for a large user base. + \item The system should detect and prevent credential stuffing attacks. + \end{itemize} + + Design and analyze a complete solution: + \begin{enumerate} + \item Specify which cryptographic primitives you would use for password storage and why. + \item Describe your password recovery mechanism and analyze its security properties. + \item Explain how your system balances security and performance requirements. + \item Analyze potential vulnerabilities in your design and how they are mitigated. + \end{enumerate} +\end{enumerate} + +\begin{tcolorbox}[colframe=EarthBrown!30!white,colback=EarthBrown!5!white] + \textbf{Bonus Challenge (20 extra points):} The security of AES and other block ciphers depends on their resistance to various forms of cryptanalysis. Research and analyze one of the following advanced attacks: + + \begin{enumerate} + \item \textbf{Side-channel attacks}: Explain how timing attacks, power analysis, or cache attacks can leak information about encryption keys in practical implementations of AES. + \item \textbf{Related-key attacks}: Describe how related-key attacks work against block ciphers and why they are significant even when normal usage involves only unrelated keys. + \item \textbf{Quantum attacks}: Analyze the impact of Grover's algorithm on the security of AES with different key sizes (128, 192, 256 bits) and discuss appropriate post-quantum key length recommendations. + \end{enumerate} + + Your answer should include: a description of the attack, its practical feasibility, relevant examples of successful implementations against real systems, and appropriate countermeasures. +\end{tcolorbox} + +\end{document} diff --git a/assignments/problem-sets/problem-set-3.tex b/assignments/problem-sets/problem-set-3.tex new file mode 100644 index 0000000..3c44d6c --- /dev/null +++ b/assignments/problem-sets/problem-set-3.tex @@ -0,0 +1,225 @@ +\documentclass[10pt,a4paper,american]{article} +\newcommand{\aublogopath}{../../website/res/img/aub_black.png} +\usepackage{../../misc/macros/joc} +\usepackage{../../misc/fonts/fonts} +\usepackage{../../misc/macros/classhandout} + +\begin{document} + +\classhandoutheader + +\section*{Problem Set 3: Asymmetric Cryptography} + +\begin{tcolorbox}[colframe=OliveGreen!30!white,colback=OliveGreen!5!white] + \textbf{Instructions:} This problem set covers topics in provable security from parts 1.7\footnote{\url{https://appliedcryptography.page/slides/1-7.pdf}} and 1.8\footnote{\url{https://appliedcryptography.page/slides/1-8.pdf}} of the course. Submit your solutions as a neatly formatted PDF. You are encouraged to collaborate with classmates in studying the material, but your submitted solutions must be your own work. For proofs, clearly state your assumptions, steps, and conclusions. +\end{tcolorbox} + +\section{Cryptographic Hardness and Real-World Implications (20 points)} + +\subsection{Breaking Cryptography: Attack Scenarios (10 points)} + +\begin{enumerate} + \item (5 points) \textbf{The Cryptographic Apocalypse Scenario:} + Imagine you wake up tomorrow to headlines: \textit{``Breakthrough Algorithm Solves P vs NP - Computer Scientists Prove P = NP!''} + \begin{enumerate} + \item As the Chief Security Officer of a major bank, write a crisis response memo outlining which systems fail immediately, which have grace periods, and what emergency measures you would implement. + \item Design an alternative security model for online banking that could work in a post-P=NP world. What assumptions would you rely on instead? + \item Analyze why NP-complete problems, despite being \textit{``hard,''} wouldn't save us in this scenario. What's the fundamental difference between NP-complete hardness and cryptographic hardness? + \end{enumerate} + \item (5 points) \textbf{The Weak DH Parameters Problem:} + A security researcher discovers that a popular cryptographic library has been generating Diffie-Hellman parameters where the prime $p$ satisfies $p-1$ having many small factors, making 75\% of generated groups vulnerable to Pohlig-Hellman attacks that reduce the discrete log problem to much smaller subgroups. + \begin{enumerate} + \item Evaluate whether this discovery completely breaks Diffie-Hellman or only partially weakens it. Consider both the mathematical impact and practical deployment consequences. + \item Design a strategy for systems using this library: should they immediately regenerate all parameters, implement parameter validation, or pursue a different approach? + \item Compare this scenario to a hypothetical breakthrough that reduces the discrete logarithm problem in prime-order groups by a factor of $2^{20}$ but still leaves it exponential. Which vulnerability would be more urgent to address and why? + \end{enumerate} +\end{enumerate} + +\subsection{Discrete Logarithm Security Architecture (10 points)} + +\begin{enumerate} + \item (5 points) \textbf{The Weak Parameter Disaster:} + Your security audit discovers that a legacy system has been using $p = 2047$ (which factors as $23 \times 89$) for Diffie-Hellman key exchange, and the generator $g = 2$. + \begin{enumerate} + \item Analyze exactly why this parameter choice is catastrophically weak. Estimate how long it would take an attacker with a modern laptop to break this system. + \item Design an emergency response plan: how do you migrate users to secure parameters while maintaining service availability? + \item Compare the security implications if the system had instead used a proper 2048-bit prime but with a generator that only generates a small subgroup. + \end{enumerate} + \item (5 points) \textbf{Elliptic Curve vs. Finite Field Trade-off Analysis:} + You're designing a cryptographic protocol for IoT devices with severe computational and bandwidth constraints. + \begin{enumerate} + \item Compare elliptic curve and finite field DLP for your use case: which offers better security per bit of key size, and which offers better computational performance? + \item Analyze why index calculus attacks work against finite fields but not elliptic curves. How does this fundamental difference affect your security margins? + \item Design a hybrid approach that uses both elliptic curves and finite fields strategically. When might this provide benefits over using just one? + \end{enumerate} +\end{enumerate} + +\section{Diffie-Hellman in Hostile Environments (20 points)} + +\subsection{Attack and Defense Scenarios (10 points)} + +\begin{enumerate} + \item (5 points) \textbf{The Perfect Man-in-the-Middle:} + An attacker has complete control over the network between Alice and Bob, can modify any message, and can initiate connections that appear to come from either party. + \begin{enumerate} + \item Design the most effective man-in-the-middle attack against unauthenticated Diffie-Hellman. Your attack should be undetectable to Alice and Bob during the key exchange. + \item Alice and Bob have never met but each has the other's public key fingerprint written on a piece of paper. Design an authentication protocol that defeats your attack using only these fingerprints. + \item Compare your fingerprint-based solution to certificate authorities and web-of-trust models. What are the usability and security trade-offs? + \item The attacker now has quantum capabilities. How does this change your attack and defense strategies? + \end{enumerate} + \item (5 points) \textbf{The Paranoid Whistleblower Scenario:} + A whistleblower needs to securely communicate with a journalist. They assume the government monitors all internet traffic, has compromised most Certificate Authorities, and can perform man-in-the-middle attacks on any connection. + \begin{enumerate} + \item Design a key exchange protocol for this scenario using only methods available to ordinary civilians (no specialized hardware or pre-shared secrets). + \item Analyze what happens if the government can also compromise one of their devices after the key exchange. How can you provide forward secrecy? + \item Compare your solution to existing tools like Tor, Signal, and SecureDrop. What additional protection does your design provide? + \end{enumerate} +\end{enumerate} + +\subsection{Protocol Design Challenge (10 points)} + +\begin{enumerate} + \item (10 points) \textbf{SSH Trust-on-First-Use Analysis:} + Your organization wants to deploy SSH across 10,000 servers, but the current TOFU model creates security and usability problems at scale. + \begin{enumerate} + \item Analyze specific attack scenarios where the TOFU model fails in practice. When are users most vulnerable? + \item Design an improved authentication model that maintains SSH's simplicity while providing better security guarantees than pure TOFU. + \item Compare your solution to proposals like DNS-based SSH public key distribution (SSHFP records) and OAuth-based SSH certificates. What are the deployment challenges for each approach? + \end{enumerate} +\end{enumerate} + +\clearpage + +\section{Elliptic Curve Security Engineering (30 points)} + +\subsection{Curve Selection Under Pressure (15 points)} + +\begin{enumerate} + \item (5 points) \textbf{The Government Backdoor Controversy:} + You're the security architect for a new messaging app. Cryptographers are debating whether NIST P-256 contains a government backdoor, while Curve25519 offers better security properties but less widespread hardware support. + \begin{enumerate} + \item Analyze the specific concerns about NIST curves: what would a backdoor look like, and how could it be exploited without breaking the underlying mathematical problems? + \item Design a risk assessment framework for choosing between P-256 and Curve25519. What factors should influence your decision? + \item Your legal team reports that several countries require NIST-compliant cryptography for government sales. How does this constraint affect your technical decision? + \item Propose a solution that addresses both the backdoor concerns and the compliance requirements. What compromises would you make? + \end{enumerate} + + \item (5 points) \textbf{The Invalid Curve Attack Scenario:} + A security researcher discovers that your ECDH implementation doesn't validate input points, making it vulnerable to invalid curve attacks. + \begin{enumerate} + \item Design a specific attack exploiting this vulnerability. What information can an attacker extract, and how long would the attack take? + \item Analyze why this attack works: what mathematical properties of elliptic curves does it exploit? + \item Develop a comprehensive input validation strategy that prevents this attack class. What performance impact does your solution have? + \item Compare this vulnerability to other implementation mistakes like reusing nonces in ECDSA. Which class of error is more dangerous in practice? + \end{enumerate} + + \item (5 points) \textbf{Mobile Performance Optimization Challenge:} + Your mobile app needs to perform thousands of ECDH operations per minute on low-end smartphones, but battery life and performance are critical concerns. + \begin{enumerate} + \item Compare the performance characteristics of different elliptic curves for your use case. Consider both computational cost and memory usage. + \item Design an optimization strategy that balances security and performance. Would you use precomputed tables, special curve forms, or other techniques? + \item Analyze the security implications of your optimizations: what new attack surfaces do they create? + \item Evaluate whether quantum resistance should influence your current design decisions, given the mobile hardware lifecycle. + \end{enumerate} +\end{enumerate} + +\subsection{Implementation Vulnerability Analysis (15 points)} + +\begin{enumerate} + \item (5 points) \textbf{The PlayStation 3 Forensics Challenge:} + You're a digital forensics expert investigating cryptocurrency theft. You discover that the thief's wallet software reused nonces in ECDSA signatures, similar to the PlayStation 3 vulnerability. + \begin{enumerate} + \item Design a forensic analysis procedure to recover the private key from blockchain transaction signatures. What information do you need, and how would you process it? + \item Estimate how many transactions with reused nonces you would need to guarantee key recovery. How does this depend on the specific nonce reuse pattern? + \item Develop a tool to scan existing blockchains for this vulnerability. What would you look for, and how would you optimize the search? + \item Analyze the broader implications: if wallet software commonly had this bug, what percentage of cryptocurrency could be at risk? + \end{enumerate} + + \item (5 points) \textbf{Side-Channel Attack Laboratory:} + You're tasked with testing an embedded device's ECDSA implementation for side-channel vulnerabilities. + \begin{enumerate} + \item Design a timing attack against variable-time scalar multiplication. What information would you measure, and how would you extract the private key? + \item Develop countermeasures that maintain performance while resisting your attack. What constant-time techniques would you implement? + \item Analyze power analysis attacks: how would an attacker use power consumption traces to recover cryptographic keys? + \item Evaluate the trade-offs between security and performance for different countermeasures. Which threats should you prioritize defending against? + \end{enumerate} + + \item (5 points) \textbf{The Ed25519 Validation Crisis:} + You discover that two widely-used Ed25519 libraries accept different signatures as valid for the same message and public key, breaking interoperability. + \begin{enumerate} + \item Investigate what causes this inconsistency: what validation steps do different implementations handle differently? + \item Analyze the security implications: could an attacker exploit these differences to create practical attacks? + \item Design a test suite to identify which Ed25519 implementations are compatible with each other. What edge cases would you test? + \item Propose a strategy for the cryptographic community to resolve this issue without breaking existing deployments. + \end{enumerate} +\end{enumerate} + +\section{Applied Cryptography Case Studies (30 points)} + +\begin{enumerate} + \item (10 points) \textbf{Key Exchange Protocol Design} + You are designing a secure messaging application that needs to establish encrypted communication channels between users who have never communicated before. The application must work on mobile devices with limited computational resources and intermittent network connectivity. + \begin{enumerate} + \item Design a complete key exchange protocol using the cryptographic primitives from lectures 1.7 and 1.8. Your design should address: + \begin{itemize} + \item Initial key establishment between strangers + \item Authentication to prevent man-in-the-middle attacks + \item Forward secrecy for long-term security + \item Efficiency for mobile devices + \end{itemize} + \item Analyze the security properties of your protocol. What attacks does it defend against, and what are its limitations? + \item Discuss how your protocol would handle practical issues like key fingerprint verification and key rotation. + \end{enumerate} + + \item (10 points) \textbf{Cryptocurrency Signature Scheme Analysis} + A new cryptocurrency project is choosing between ECDSA and Ed25519 for transaction signatures. The system requirements include: + \begin{itemize} + \item High transaction throughput (thousands of signatures per second) + \item Long-term security (system should remain secure for decades) + \item Compatibility with hardware wallets and mobile devices + \item Deterministic transaction signing for reproducibility + \end{itemize} + Analyze this decision: + \begin{enumerate} + \item Compare ECDSA and Ed25519 for each requirement above. Which algorithm better meets each criterion and why? + \item Discuss the implications of signature malleability. How does this affect each algorithm and why might it matter for cryptocurrency applications? + \item Analyze the quantum resistance of both options. What migration path would you recommend for long-term security? + \item Consider the ecosystem effects: existing wallet software, hardware support, and developer familiarity. How do these practical factors influence the decision? + \item Make a final recommendation with justification, considering both technical and practical factors. + \end{enumerate} + + \item (10 points) \textbf{Secure Communication System Architecture} + You are architecting a secure communication system for a large organization (10,000+ employees) that needs to protect against both external attackers and potential insider threats. The system must support real-time messaging, file sharing, and voice calls. + Design and analyze a complete solution: + \begin{enumerate} + \item Specify your cryptographic algorithm choices for: + \begin{itemize} + \item Key exchange protocols + \item Digital signature schemes + \item Symmetric encryption algorithms + \item Hash functions and MACs + \end{itemize} + \item Describe your key management architecture. How do you bootstrap trust, distribute keys, and handle key rotation? + \item Analyze your system's security properties against various attack scenarios: + \begin{itemize} + \item Network eavesdropping + \item Server compromise + \item Endpoint compromise + \item Insider attacks + \end{itemize} + \item Discuss the performance implications of your design choices and how you would optimize for a large-scale deployment. + \item Evaluate your system's compliance with modern security standards and its readiness for post-quantum cryptography migration. + \end{enumerate} +\end{enumerate} + +\begin{tcolorbox}[colframe=EarthBrown!30!white,colback=EarthBrown!5!white] + \textbf{Bonus Challenge (20 extra points):} The transition to post-quantum cryptography will require replacing current elliptic curve systems with quantum-resistant alternatives. Research and analyze one of the following aspects of this transition: + \begin{enumerate} + \item \textbf{NIST Post-Quantum Standards}: Analyze the recently standardized ML-KEM and ML-DSA algorithms. How do their key sizes, performance characteristics, and security assumptions compare to current ECC systems? + \item \textbf{Hybrid Classical/Post-Quantum Systems}: Describe approaches for combining classical and post-quantum algorithms during the transition period. What are the benefits and challenges of hybrid systems? + \item \textbf{Migration Timeline and Challenges}: Analyze the practical challenges of migrating existing systems (browsers, mobile apps, IoT devices) from ECC to post-quantum cryptography. What factors determine the migration timeline? + \end{enumerate} + Your answer should include: current standardization status, performance comparisons with existing systems, deployment challenges, and recommendations for practitioners preparing for the post-quantum transition. Check the Optional Readings under the topic listing for the Post-Quantum Cryptography on the course website for helpful references! +\end{tcolorbox} + +\end{document} diff --git a/misc/fonts/InriaSans-Bold.ttf b/misc/fonts/InriaSans-Bold.ttf new file mode 100644 index 0000000..f68e290 --- /dev/null +++ b/misc/fonts/InriaSans-Bold.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f0dd87c86c2397262a3a869318b3f6df033478931e43e94671fbb198597b961e +size 82320 diff --git a/misc/fonts/InriaSans-BoldItalic.ttf b/misc/fonts/InriaSans-BoldItalic.ttf new file mode 100644 index 0000000..1ea9deb --- /dev/null +++ b/misc/fonts/InriaSans-BoldItalic.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1cc04ffa4aab37e4768a1ca119d37db5ef8a6c82f85a884eaa6cb522cab5a79f +size 83724 diff --git a/misc/fonts/InriaSans-Italic.ttf b/misc/fonts/InriaSans-Italic.ttf new file mode 100644 index 0000000..40c531e --- /dev/null +++ b/misc/fonts/InriaSans-Italic.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f6125d92b051aea0483e7399260ecd5bc61fe07443d9f94c18018831340ba00 +size 84308 diff --git a/misc/fonts/InriaSans-Regular.ttf b/misc/fonts/InriaSans-Regular.ttf new file mode 100644 index 0000000..6878fd8 --- /dev/null +++ b/misc/fonts/InriaSans-Regular.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb4cbb50113617b021dd292e91e061f1968777ec39b5c30f379fad28748f0fff +size 82452 diff --git a/misc/fonts/JetBrainsMono-Bold.ttf b/misc/fonts/JetBrainsMono-Bold.ttf new file mode 100644 index 0000000..1a82e73 --- /dev/null +++ b/misc/fonts/JetBrainsMono-Bold.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5590990c82e097397517f275f430af4546e1c45cff408bde4255dad142479dcb +size 277828 diff --git a/misc/fonts/JetBrainsMono-BoldItalic.ttf b/misc/fonts/JetBrainsMono-BoldItalic.ttf new file mode 100644 index 0000000..66ce7ca --- /dev/null +++ b/misc/fonts/JetBrainsMono-BoldItalic.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4039d5ce0ed225bf9c8b2c8c6436290ae2f356b7e90d70fa666227238324aa3b +size 279832 diff --git a/misc/fonts/JetBrainsMono-Italic.ttf b/misc/fonts/JetBrainsMono-Italic.ttf new file mode 100644 index 0000000..91dd4e0 --- /dev/null +++ b/misc/fonts/JetBrainsMono-Italic.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d0a1f7a708e6af183f1193b7e81d40da294f5c67682c085d8401c60aac8ded4 +size 276840 diff --git a/misc/fonts/JetBrainsMono-Regular.ttf b/misc/fonts/JetBrainsMono-Regular.ttf new file mode 100644 index 0000000..c8b5a92 --- /dev/null +++ b/misc/fonts/JetBrainsMono-Regular.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0bf60ef0f83c5ed4d7a75d45838548b1f6873372dfac88f71804491898d138f +size 273900 diff --git a/misc/fonts/STIXTwoMath-Regular.ttf b/misc/fonts/STIXTwoMath-Regular.ttf new file mode 100644 index 0000000..329da01 --- /dev/null +++ b/misc/fonts/STIXTwoMath-Regular.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49b22767985171bce579307b21d98f4d35012fa39e316acc4ffcab8644dfb69b +size 1518116 diff --git a/misc/fonts/STIXTwoText-Bold.ttf b/misc/fonts/STIXTwoText-Bold.ttf new file mode 100644 index 0000000..56194f8 --- /dev/null +++ b/misc/fonts/STIXTwoText-Bold.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:89adbb9907c40465e061f084598dbebd5a802e30c6e2d38612205b9c87281cae +size 395644 diff --git a/misc/fonts/STIXTwoText-BoldItalic.ttf b/misc/fonts/STIXTwoText-BoldItalic.ttf new file mode 100644 index 0000000..0c524b7 --- /dev/null +++ b/misc/fonts/STIXTwoText-BoldItalic.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f11eced04bcd8919ad92ccc0251878be9a46fa45fa76c514e3abfbf605a3160f +size 420164 diff --git a/misc/fonts/STIXTwoText-Italic.ttf b/misc/fonts/STIXTwoText-Italic.ttf new file mode 100644 index 0000000..bdd8467 --- /dev/null +++ b/misc/fonts/STIXTwoText-Italic.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a0ed1c0c1d3d4f83f2d00bcd4a0a991a7b0755beacee0a57b26762327a84c22 +size 424488 diff --git a/misc/fonts/STIXTwoText-Regular.ttf b/misc/fonts/STIXTwoText-Regular.ttf new file mode 100644 index 0000000..f87706a --- /dev/null +++ b/misc/fonts/STIXTwoText-Regular.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0566a1be411c0b2463fad8563b33f1c299442b8882c7fce9ef95e079f43233da +size 395068 diff --git a/misc/fonts/fonts.sty b/misc/fonts/fonts.sty new file mode 100644 index 0000000..67f4d0c --- /dev/null +++ b/misc/fonts/fonts.sty @@ -0,0 +1,8 @@ +\RequirePackage[T1]{fontenc} +\RequirePackage[utf8]{inputenc} +\RequirePackage{fontspec} +\RequirePackage{unicode-math} +\setsansfont[Scale=1.0]{Inria Sans} +\setmonofont[Scale=0.9]{JetBrains Mono} +\setromanfont[Scale=1.0]{STIX Two Text} +\setmathfont[Scale=1.0]{STIX Two Math} diff --git a/misc/macros/classhandout.sty b/misc/macros/classhandout.sty new file mode 100644 index 0000000..1886fa0 --- /dev/null +++ b/misc/macros/classhandout.sty @@ -0,0 +1,61 @@ +\usepackage[pdftitle=Applied Cryptography,pdflang=en-US,colorlinks=true,linkcolor=OliveGreen,urlcolor=OliveGreen,citecolor=OliveGreen,bookmarksopen=true]{hyperref} +\usepackage{xurl,hyperxmp,graphicx,array,fancyhdr,bbding,pmboxdraw,listings,acronym,amsthm,bookmark,zref-totpages,xcolor,tikz,titlesec,enumitem,amsmath} +\usepackage[inner=2.50cm,outer=2.50cm,top=2.50cm,bottom=2.50cm]{geometry} +\usepackage{microtype} +\renewcommand{\familydefault}{\sfdefault} +\definecolor{OliveGreen}{HTML}{3F7E31} +\definecolor{EarthBrown}{HTML}{7D4C31} +\definecolor{LightestGray}{HTML}{EEEEEE} +\definecolor{DarkGray}{HTML}{5F6368} +\titleformat{\section} +{\normalfont\Large\bfseries\color{OliveGreen}} +{\thesection}{1em}{} +\titleformat{\subsection} +{\normalfont\large\bfseries\color{EarthBrown}} +{\thesubsection}{1em}{} +\pagestyle{fancy} +\fancyhf{} +\renewcommand{\headrulewidth}{0.3pt} +\renewcommand{\footrulewidth}{0.3pt} +\lhead{\textcolor{OliveGreen}{Applied Cryptography}} +\rhead{\textcolor{DarkGray}{American University of Beirut}} +\lfoot{\textcolor{DarkGray}{CMPS 297AD/396AI, Fall 2025}} +\rfoot{\textcolor{DarkGray}{Page \thepage\ of \ztotpages}} +\tcbsetforeverylayer{colframe=OliveGreen!20!white,colback=LightestGray,boxrule=0.5pt,arc=2mm,boxsep=5pt,left=6pt,right=6pt,top=6pt,bottom=6pt} +\thispagestyle{empty} +\setlist{itemsep=0em} + +\newcommand{\classhandoutheader}{ + \begin{tikzpicture}[remember picture, overlay] + \fill[OliveGreen!10!white] (current page.north west) rectangle ([yshift=-5cm]current page.north east); + \end{tikzpicture} + + \vspace*{-1.5cm} + \noindent + \begin{minipage}[c]{0.35\textwidth} + \centering + \includegraphics[width=2.5in]{\aublogopath} + \end{minipage} + \begin{minipage}[c]{0.65\textwidth} + \begin{flushright} + \vspace{0.3cm} + {\fontsize{24}{28}\selectfont\textcolor{OliveGreen}{Applied Cryptography}} + + \vspace{0.2cm} + {\large\textcolor{DarkGray}{CMPS 297AD/396AI, Fall 2025}} + \vspace{0.2cm} + \end{flushright} + \end{minipage} + + \vspace{0.8cm} + \begin{tcolorbox}[colframe=OliveGreen!70!white,colback=white,arc=1mm] + \begin{center} + \begin{tabular}{ll} + \textbf{Instructor:} Nadim Kobeissi \quad\quad\quad\quad\quad \textbf{Website:} \url{https://appliedcryptography.page} + \end{tabular} + \end{center} + \end{tcolorbox} + + \setlength{\unitlength}{1in} + \renewcommand{\arraystretch}{1.5} +} diff --git a/misc/macros/joc.sty b/misc/macros/joc.sty new file mode 100644 index 0000000..f78a733 --- /dev/null +++ b/misc/macros/joc.sty @@ -0,0 +1,98 @@ +\ProvidesPackage{joc}[2025/05/04 v1.0 Nadim's Joy of Cryptography Style Macros] + +\RequirePackage{xcolor} +\RequirePackage[auto]{contour} +\RequirePackage{varwidth,tikz} +\RequirePackage[most]{tcolorbox} +\usetikzlibrary{shadows, arrows.meta, positioning, shapes, calc, fit, shapes.geometric} + +\definecolor{jocbitcolor}{HTML}{A91716} +\definecolor{joctitlecolor}{HTML}{E5E5E5} + +% Macro for state-separable proof style subroutines +\newcommand{\sssubroutine}[4]{ + \begin{center} + \begin{tikzpicture}[box/.style={rectangle, draw, align=left, fill=white, inner sep=7pt, scale=#4, execute at begin node=\setlength{\baselineskip}{1.5em}}] + \node[box]{ + \underline{\func{#1}{#2}}: \\ + #3 + }; + \end{tikzpicture} + \end{center} +} + +\newcommand{\sslibrarysubroutine}[4]{ + \begin{tikzpicture}[box/.style={rectangle, align=left, inner sep=0pt, outer sep=0pt, fill=white, scale=#4, execute at begin node=\setlength{\baselineskip}{1.5em}, inner sep=0pt, outer sep=0pt}] + \node[box]{ + \underline{\func{#1}{#2}}: \\ + #3 + }; + \end{tikzpicture} +} + +\newcommand{\prob}[1]{\ensuremath{\Pr\bigl[\ensuremath{#1}\bigr]}} +\newcommand{\lib}[2]{\ensuremath{\mathcal{L}^{#1}_\text{#2}}} +\newcommand{\prog}[1]{\ensuremath{\mathcal{A}_\text{#1}}} +\newcommand{\link}{\ensuremath{\diamond}} +\newcommand{\interchangeable}[1]{\ensuremath{\overset{\ensuremath{#1}}{\equiv}}} +\newcommand{\bit}[1]{\textcolor{jocbitcolor}{\texttt{#1}}} +\newcommand{\bits}{\ensuremath{\{\bit{0}, \bit{1}\}}} +\newcommand{\func}[2]{\ensuremath{\textrm{\textsc{#1}}\scalebox{1.05}{\ensuremath{(#2)}}}} + +\newtcolorbox{sslibrarybox}[2][]{ + colback=white, + colframe=black, + colbacktitle=joctitlecolor, + coltitle=black, + enhanced,hbox, + toptitle=1mm, + bottomtitle=1mm, + boxrule=0.5pt, + titlerule=0pt, + left=1mm, + right=1mm, + top=2mm, + bottom=2mm, + titlerule style=joctitlecolor, + sharp corners, + halign title=center, + title={#2}, + #1 +} + +\newcommand{\sslibrary}[4]{ + \begin{sslibrarybox}[scale=#4]{\lib{#1}{#2}} + \begin{varwidth}{\textwidth} + #3 + \end{varwidth} + \end{sslibrarybox} +} + +\newcommand{\ssprogram}[3]{ + \begin{sslibrarybox}[scale=#3]{\prog{#1}} + \begin{tikzpicture}[box/.style={rectangle, align=left, fill=white, inner sep=0pt, outer sep=0pt, execute at begin node=\setlength{\baselineskip}{1.5em}}] + \node[box]{ + #2 + }; + \end{tikzpicture} + \end{sslibrarybox} +} + +\newcommand{\sslinked}[3]{ + \begin{tikzpicture}[baseline] + \node[inner sep=0pt, outer sep=0pt] (left) {\begin{varwidth}{\textwidth}#1\end{varwidth}}; + \node[inner sep=0pt, outer sep=0pt, anchor=west] (middle) at (left.east) {\begin{varwidth}{\textwidth}{\large\ensuremath{\ #2\ }}\end{varwidth}}; + \node[inner sep=0pt, outer sep=0pt, anchor=west] (right) at (middle.east) {\begin{varwidth}{\textwidth}#3\end{varwidth}}; + \end{tikzpicture} +} + +\contourlength{1.2pt} +\newcommand{\hl}[1]{% + \relax\ifmmode% + {}% + \contour{hlbg}{\textcolor{hlfg}{${} #1 {}$}}% + {}% + \else% + \contour{hlbg}{\textcolor{hlfg}{#1}}% + \fi% +} diff --git a/misc/macros/msc5.sty b/misc/macros/msc5.sty new file mode 100644 index 0000000..0d7777f --- /dev/null +++ b/misc/macros/msc5.sty @@ -0,0 +1,4173 @@ +%% MSC Macro Package 5 +%% msc5.sty +%% Feb 2, 2014 +%% +%% Copyright 2014 A. Farmadin +% +% This derived work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3 +% of this license or (at your option) any later version. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% This work has the LPPL maintenance status `maintained'. +% +% The Current Maintainer of this work is A. Farmadin. +% +% This program consists of the files +% msc.sty +% manual.tex +% manual.pdf +% refman.tex +% refman.pdf +% biblio.bib +% maintenance.tex +% maintenance.pdf +% README +% COPYRIGHT +% + +% Contact address: +% Adrian Farmadin +% Masaryk University, Brno +% Email: a.farmadin@gmail.com +% Updates via: http://is.muni.cz/www/374320/msc5.sty +% +% Original work: http://satoss.uni.lu/software/mscpackage/ +% + +\def\mscdate{2011/05/22}% update this whenever this file changes +\def\mscversion{1.18}% update this whenever a new version is ready +\NeedsTeXFormat{LaTeX2e}% +\ProvidesPackage{msc}[\mscdate, v\mscversion] +\typeout{msc version \mscversion. (\mscdate)} +\RequirePackage{color,calc,ifthen,tikz,etoolbox} +\usetikzlibrary{decorations.markings}% to arrow scale +\usetikzlibrary{calc}%to compute hmsc relations +% +% mscunit: the unit of msc lengths +\def\mscunit{cm}% +\def\setmscunit#1{\gdef\mscunit{#1}} +% +% +% arrow style +\tikzstyle{arrowstyle}=[decoration={markings,mark=at position 1 with {\arrow[scale=1]% + {stealth}}},postaction={decorate},shorten >=0.4pt] +% +% msc lengths +% First the customizable lengths: + +\newlength{\actionheight}% height of action symbols +\newlength{\actionwidth}% width of action symbol +\newlength{\bottomfootdist}% distance between bottom of foot symbol and frame +\newlength{\msccommentdist}% distance of comment to its instance +\newlength{\conditionheight}% height of condition symbols +\newlength{\conditionoverlap}% overlap of condition symbol +\newlength{\envinstdist}% distance between environments and nearest instance line +\newlength{\firstlevelheight}% height of level just below head symbols +\newlength{\gatesymbolradius}% radius of the gate symbol +\newlength{\msccommentwidth}% width of bmsc comment symbol +\newlength{\hmscconditionheight}% height of hmsc condition symbol +\newlength{\hmscconditionwidth}% width of hmsc condition symbol +\newlength{\hmscconnectionradius}% radius of hmsc connection symbols +\newlength{\hmscreferenceheight}% height of hmsc reference symbol +\newlength{\hmscreferencewidth}% width of hmsc reference symbol +\newlength{\hmsccommentwidth}% width of hmsc comment symbol +\newlength{\hmsccommentheight}% height of hmsc comment symbol +\newlength{\mscglobalcommentwidth}% width of hmsc comment symbol +\newlength{\hmsccommenthem}% size of hmsc comment symbol hem +\newlength{\hmscstartsymbolwidth}% width of hmsc start symbol +\newlength{\inlineoverlap}% overlap of inline symbol +\newlength{\instbarwidth}% default width of vertical instance bars +\newlength{\instdist}% distance between (vertical) instance lines +\newlength{\instfootheight}% height of foot symbols +\newlength{\instheadheight}% height of head symbols +\newlength{\instwidth}% width of header and foot symbols +\newlength{\labeldist}% distance between labels and message lines or head symbol boxes +\newlength{\lastlevelheight}% height of level just above foot symbols +\newlength{\leftnamedist}% distance between left of frame and (top of) msc title +\newlength{\levelheight}% height of a level +\newlength{\lostsymbolradius}% radius of the lost and found symbols +\newlength{\markdist}% distance between mark and its instance +\newlength{\measuredist}% user definable length for horizontal measure distance +\newlength{\measuresymbolwidth}% width of measure symbols +\newlength{\mscdocreferenceheight}% minimal height of mscdoc reference +\newlength{\mscdocreferencewidth}% minimal width of mscdoc reference +\newlength{\referenceoverlap}% overlap of reference symbol +\newlength{\regionbarwidth}% the width of the coregion start and end symbol +\newlength{\regionwidth}% the width of the activation, suspension and coregion rectangle +\newlength{\selfmesswidth}% length of horizontal arms of self messages +\newlength{\stopwidth}% width of the stop symbol +\newlength{\timerwidth}% width of the timer symbols +\newlength{\topheaddist}% distance between top of head symbols and frame +\newlength{\topnamedist}% distance between top of frame and (top of) msc title +% +% Now the internal lengths +\newlength{\tmp@X} +\newlength{\tmp@Y} +\newlength{\tmp@Xa} +\newlength{\tmp@Ya} +\newlength{\tmp@Xb} +\newlength{\tmp@Yb} +\newlength{\tmp@Xc} +\newlength{\tmp@Yc} +\newlength{\tmp@Xd} +\newlength{\tmp@Yd} +\newlength{\msc@currentheight} +\newlength{\msc@currentwidth} +\newlength{\msc@totalwidth} +\newlength{\msc@totalheight} +\newlength{\msc@commentdist}% distance of comment to its instance +% +% +\newcommand{\msc@incrcounter}[1]{\addtocounter{#1}{1}}% +% +% internal box +\newsavebox{\tmp@box} +% +% some internal offsets +\def\msc@leveloffset{0}% +\def\mscscalefactor{1}% +\newcommand{\setmscscale}[1]{\def\mscscalefactor{#1}}% +% +% Command to change the footer color (legal values are black, gray, +% lightgray, and white) +\def\setfootcolor#1{\def\msc@footcolor{#1}} +% +\def\msc@color{black}% +% Command to change the elements color +\newcommand{\mscsetcolor}[1]{ + \edef\msc@color{#1}% + \pgfsetcolor{#1}% + \color{#1}% +} +% +% And some internal counters +\newcounter{mscinstcnt} +\newcounter{tmpcnt} +% +% \messlabelpos defines the position of message labels. +% The default value is "l" (left) other value(s) are "r" (right) +\def\timerpos{l} +% +% \msc@timerpos is the internal variant of \timerpos +% This internal variant is used by the actual drawing commands for self messages +\def\msc@timerpos{l} +% +% \msc@settimerpos sets the internal \mes@timerpos +\def\msc@settimerpos#1{ + \ifthenelse{\not\(\equal{#1}{l} \or \equal{#1}{r}\)}{% + \msc@unknowntimerposerr{#1}}{% else + \def\msc@timerpos{#1}% + }% +} +% +% \dummyinst{#1} (\dummyinst*{#1}) declares a dummy msc-instance and does not +% draws its head symbol nor its instance axis until an instance create/start is +% encountered. The starred version declares a fat instance. +% #1: nickname that can be used in \mess -like commands +% +\def\dummyinst{\@ifstar{\msc@dummyinststar}{\msc@dummyinstnostar}} +\def\msc@dummyinstnostar#1{% + %normal instance + \msc@makedummyinst{\the\instbarwidth}{#1}% +} +\def\msc@dummyinststar#1{% + %fat instance + \msc@makedummyinst{\the\instwidth}{#1}% +} +\def\msc@makedummyinst#1#2{% + \@ifundefined{mscinst#2}{% + \ifthenelse{\value{mscinstcnt}=2}{% Aha: this is the first msc instance, so, add the + \addtolength{\msc@currentwidth}{\envinstdist}% left \envinstdist to \msc@currentwidth + }{%not the first instance , so add the instdist to the \mec@currentwidth + \addtolength{\msc@currentwidth}{\instdist}% + }% and update x-pos of right environment + \setlength{\tmp@X}{\msc@currentwidth+\envinstdist}% + \msc@setinstxpos{envright}{\the\tmp@X}% + % make an instance with empty inside name and empty above name: + \msc@declinst{#2}{\relax}{\relax}{#1}% + % make y-pos undefined, to make sure that no instance line will be drawn + \msc@setinstypos{#2}{undefined}% --added sm + }{% else: nickname #2 already defined! + \msc@nicknamedefinederr{#2}% + }% +} +% +% \declinst[*] declares a new msc-instance and draws its head symbol +% the starred versions makes a fat instance. +% #1: instance width +% #2: nickname that can be used in \mess +% #3: instance head height +% #4: name of the instance (above instance head symbol) +% #5: instance foot height +% #6: name of the instance (inside instance head symbol) +% +% +\def\declinst{\@ifstar{\msc@declinststar}{\msc@declinstnostar}} +% +% +% \msc@declinstnostar +% [#1]: width of instance foot and head symbol +% {#2}: nickname of instance +% [#3]: height of instance head symbol +% [#4]: height of instance foot symbol +% {#5}: instance above name +% {#6}: instance inside name +% Some commands are defined as well (INSTNR is the arabic +% representation of the instance number): +% \instabname#1: `above name' of instance with nickname #1 +% \instinname#1: `inside name' of instance with nickname #1 +% \instnicknameINSTNR: returns the nickname of instance INSTNR +% \instxposINSTNR: returns the x-position of instance with nickname #1 +% \instyposINSTNR: returns the last y-position of instance with nickname #1 +% \instlinestyle#1: the line style (dashed or solid) of instance with nickname #1 +\newcommand{\msc@declinstnostar}[2][\instwidth]{% user command to declare instances + \msc@dummyinstnostar{#2}% + \def\instname{#2}% + \expandafter\def\csname instwidth#2\endcsname{#1}% `head foot width' + \msc@declinstnostarA% +} + +\newcommand{\msc@declinstnostarA}[1][\instheadheight]{ + \expandafter\def\csname instheadheight\instname\endcsname{#1}% `head height' + \msc@declinstnostarB% +} + +\newcommand{\msc@declinstnostarB}[2][\instfootheight]{ + \def\abovename{#2}% + \expandafter\def\csname instfootheight\instname\endcsname{#1}% `foot height' + \msc@declinstnostarC% +} + +\newcommand{\msc@declinstnostarC}[2][black]{ + % define above name and inside name + \expandafter\def\csname instabname\instname\endcsname{\abovename}% `above name' + \expandafter\def\csname instinname\instname\endcsname{#2}% `inside name' + \expandafter\def\csname instcolor\instname\endcsname{#1}% color + % draw the instance header symbol + \msc@drawinstanceheadsymbol{\instname}{\the\topheaddist}% + % redefine the instance's y position + \setlength{\tmp@Y}{\topheaddist+\msc@instheadheight{\instname}}% + % TvD: This fixes the problem that instheadhight, topheaddist and + % firstlevelheight are not taken into account. However, it is not a + % pretty solution. + \setlength{\msc@currentheight}{\msc@instheadheight{\instname}+\topheaddist+\firstlevelheight}% + \msc@setinstypos{\instname}{\the\tmp@Y}% +} +% +% \msc@declinststar +% [#1]: width of instance foot and head symbol +% {#2}: nickname of instance +% [#3]: height of instance head symbol +% [#4]: height of instance foot symbol +% {#5}: instance above name +% {#6}: instance inside name +\newcommand{\msc@declinststar}[2][\instwidth]{% user command to declare instances + \msc@dummyinststar{#2}% + \def\instname{#2}% + \expandafter\def\csname instwidth#2\endcsname{#1}% `head foot width' + \msc@declinststarA% +} + +\newcommand{\msc@declinststarA}[1][\instheadheight]{ + \expandafter\def\csname instheadheight\instname\endcsname{#1}% `head height' + \msc@declinststarB% +} + +\newcommand{\msc@declinststarB}[2][\instfootheight]{ + \def\abovename{#2}% + \expandafter\def\csname instfootheight\instname\endcsname{#1}% `foot height' + \msc@declinststarC% +} + +\newcommand{\msc@declinststarC}[2][black]{ + % define above name and inside name + \expandafter\def\csname instabname\instname\endcsname{\abovename}% `above name' + \expandafter\def\csname instinname\instname\endcsname{#2}% `inside name' + \expandafter\def\csname instcolor\instname\endcsname{#1}% color + % draw the instance header symbol + \msc@drawinstanceheadsymbol{\instname}{\the\topheaddist}% + % redefine the instance's y position + \setlength{\tmp@Y}{\topheaddist+\msc@instheadheight{\instname}}% + % TvD: This fixes the problem that instheadhight, topheaddist and + % firstlevelheight are not taken into account. However, it is not a + % pretty solution. + \setlength{\msc@currentheight}{\msc@instheadheight{\instname}+\topheaddist+\firstlevelheight}% + \msc@setinstypos{\instname}{\the\tmp@Y}% +} +% +% \msc@declinst: internal command to declare instances. +% Some commands are defined as well (INSTNR is the arabic +% representation of the instance number): +% \instabnameINSTNR: returns the instance above name of #1 +% \instnicknameINSTNR: returns the nickname of instance #1 +% \instxposINSTNR: returns the x-position of instance with nickname #1 +% \instyposINSTNR: returns the last y-position of instance with nickname #1 +% \instlinestyle#1: the line style (dashed or solid) of instance with nickname #1 +% \instregionstyle#1: the region style (normal, coregion, suspension, or activation) +\def\msc@declinst#1#2#3#4{% internal command to declare instances + \@ifundefined{mscinst#1}{% + \@namedef{mscinst#1}{\relax}% + \expandafter\def\csname instabname#1\endcsname{#2}% `above name' + \expandafter\def\csname instinname#1\endcsname{#3}% `inside name' + \expandafter\def\csname instbarwidth#1\endcsname{#4}% width of the vertical instance bar + % the x position of an instance, \instxpos#1, is stored as a string, not as + % a TeX-length, since that would use up too much of TeX limited number of + % length-registers. + % However, this means we first have to calculate the x-pos, and then + % assign the string representation of the result to \instxpos#1: + \setlength{\tmp@X}{\msc@currentwidth}% + \expandafter\edef\csname instxpos#1\endcsname{\the\tmp@X}% + \ifthenelse{\lengthtest{\instbarwidth < #4}}% + {% + \expandafter\def\csname instisfat#1\endcsname{true}% + \setlength{\tmp@Xa}{#4}% + \addtolength{\tmp@X}{-.5\tmp@Xa}% + \expandafter\edef\csname instlxpos#1\endcsname{\the\tmp@X}% + \addtolength{\tmp@X}{\tmp@Xa}% + \expandafter\edef\csname instrxpos#1\endcsname{\the\tmp@X}% + }% + {% + \expandafter\def\csname instisfat#1\endcsname{false}% + \expandafter\edef\csname instlxpos#1\endcsname{\the\tmp@X}% + \expandafter\edef\csname instrxpos#1\endcsname{\the\tmp@X}% + }% + \expandafter\def\csname instnickname\arabic{mscinstcnt}\endcsname{#1}% + \setlength{\tmp@Y}{\msc@currentheight}% + \expandafter\edef\csname instypos#1\endcsname{\the\tmp@Y}% + \expandafter\def\csname instlinestyle#1\endcsname{solid}% + \expandafter\def\csname instfootcolor#1\endcsname{\msc@footcolor}% + \expandafter\def\csname instregionstyle#1\endcsname{normal}% + \msc@incrcounter{mscinstcnt}% + }{% else, #1 already defined + \msc@nicknamedefinederr{#1}% + }% +} +% +% \msc@instnickname gets the nickname of msc instance with number #1 +% (This macro is used in \msc@drawinstancelevels) +\def\msc@instnickname#1{% + \csname instnickname\arabic{#1}\endcsname% +} +% +% \msc@instabname gets the above name of instance #1 +\def\msc@instabname#1{% + \csname instabname#1\endcsname% +} +% \msc@instinname gets the inside name of instance #1 +\def\msc@instinname#1{% + \csname instinname#1\endcsname% +} +% +% \msc@instxpos gets the x position (i.e., horizontal position) of the +% msc instance with nickname #1. +\def\msc@instxpos#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\csname instxpos#1\endcsname}% +} +% +% \msc@instlxpos gets the x position of left side of instance bar +\def\msc@instlxpos#1{ + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\csname instlxpos#1\endcsname}% +} +% +% \msc@instrxpos gets the x position of right side of instance bar +\def\msc@instrxpos#1{ + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\csname instrxpos#1\endcsname}% +} +% +% \msc@setinstxpos sets the (l/r) x position of instance with nickname #1 to +% the string #2 +\def\msc@setinstxpos#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\edef\csname instxpos#1\endcsname{#2}% + \expandafter\edef\csname instlxpos#1\endcsname{#2}% + \expandafter\edef\csname instrxpos#1\endcsname{#2}% + }% +} +% +% \msc@setinstlxpos sets the left x position of instance with nickname #1 to +% the string #2 +\def\msc@setinstlxpos#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\edef\csname instlxpos#1\endcsname{#2}% + }% +} +% +% \msc@setinstrxpos sets the right x position of instance with nickname #1 to +% the string #2 +\def\msc@setinstrxpos#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\edef\csname instrxpos#1\endcsname{#2}% + }% +} +% +% \msc@instypos gets the last y position (i.e., vertical position) of the +% msc instance with nickname #1. +\def\msc@instypos#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instypos#1\endcsname}% +} +% +% \msc@setinstypos sets the last y position of instance with nickname #1 to +% the string #2 +\def\msc@setinstypos#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\edef\csname instypos#1\endcsname{#2}% + }% +} +% +% Change \instlinestyle command of msc instance with nickname #1 into #2 +% #2 should be one of: solid, dashed, or dotted +\def\msc@setinstlinestyle#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \ifthenelse{\not\(\equal{#2}{solid} \or + \equal{#2}{dashed} \or + \equal{#2}{dotted}\)}{% unknown linestyle + \msc@unknownlinestyleerr{#2}}{% + \expandafter\def\csname instlinestyle#1\endcsname{#2}% + }% + }% +} +% +% \msc@instlinestyle returns the linestyle of instance with nickname #1 +\def\msc@instlinestyle#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instlinestyle#1\endcsname}% +} +% +% Change the color of instance with nickname #1 into #2 +\def\msc@setinstcolor#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\def\csname instcolor#1\endcsname{#2}% + }% +} +% +% \msc@instcolor returns the color of the instance with nicknam #1 +\def\msc@instcolor#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instcolor#1\endcsname}% +} +% +% Change the foot color for instance with nickname #1 into #2 +\def\msc@setinstfootcolor#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\def\csname instfootcolor#1\endcsname{#2}% + }% +} +% +% \msc@instfootcolor returns the color of the footer of instance with nicknam #1 +\def\msc@instfootcolor#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instfootcolor#1\endcsname}% +} +% +% \msc@instwidth returns width of the head and foot of instance with nicknam #1 +\def\msc@instwidth#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instwidth#1\endcsname}% +} +% +% \msc@setinstwidth set width of the head and foot of instance with nicknam #1 +\def\msc@setinstwidth#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\def\csname instwidth#1\endcsname{#2}% + }% +} +% +% \msc@instfootheight returns the height of the foot of instance with nicknam #1 +\def\msc@instfootheight#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instfootheight#1\endcsname}% +} +% +% \msc@setinstfootheight set the heigjt of the foot of instance with nicknam #1 +\def\msc@setinstfootheight#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\def\csname instfootheight#1\endcsname{#2}% + }% +} +% +% \msc@instheadheight returns the height of the head of instance with nicknam #1 +\def\msc@instheadheight#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instheadheight#1\endcsname}% +} +% +% \msc@setinstheadheight set the height of the head of instance with nicknam #1 +\def\msc@setinstheadheight#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\def\csname instheadheight#1\endcsname{#2}% + }% +} +% +% \msc@regionwidth returns the width of the region of instance with nicknam #1 +\def\msc@regionwidth#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname regionwidth#1\endcsname}% +} +% +% \msc@setregionwidth set the width of the region of instance with nicknam #1 +\def\msc@setregionwidth#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\def\csname regionwidth#1\endcsname{#2}% + }% +} +% +% \msc@regioncolor returns the color of the region of instance with nicknam #1 +\def\msc@regioncolor#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname regioncolor#1\endcsname}% +} +% +% \msc@setregioncolor set the color of the region of instance with nicknam #1 +\def\msc@setregioncolor#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\def\csname regioncolor#1\endcsname{#2}% + }% +} +% +% \msc@regionbarwidth returns the width of the regions tail of instance with nicknam #1 +\def\msc@regionbarwidth#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname regionbarwidth#1\endcsname}% +} +% +% \msc@setregionbarwidth set the width of the regions tail of instance with nicknam #1 +\def\msc@setregionbarwidth#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\def\csname regionbarwidth#1\endcsname{#2}% + }% +} +% +% Change \instregionstyle command of msc instance with nickname #1 into #2 +% #2 should be one of: normal, coregion, suspension, or activation +\def\msc@setinstregionstyle#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \ifthenelse{\not\(\equal{#2}{normal} \or + \equal{#2}{coregion} \or + \equal{#2}{suspension} \or + \equal{#2}{activation}\)} + {% unknown region style + \msc@unknownregionstyleerr{#2} + }{% + \expandafter\def\csname instregionstyle#1\endcsname{#2}% + }% + \ifthenelse{\equal{#2}{suspension} \or \equal{#2}{activation} \or \equal{#2}{coregion}} + {% + \ifthenelse{\equal{\msc@instisfat{#1}}{true}} + {\relax} + {% + \setlength{\tmp@X}{\msc@instxpos{#1}}% + \setlength{\tmp@Xa}{\msc@regionwidth{#1}} + \addtolength{\tmp@X}{-.5\tmp@Xa}% + \msc@setinstlxpos{#1}{\the\tmp@X}% + \addtolength{\tmp@X}{\tmp@Xa}% + \msc@setinstrxpos{#1}{\the\tmp@X}% + } + }{% new region style is normal + + \ifthenelse{\equal{\msc@instisfat{#1}}{true}}% + {\relax}% + {\msc@setinstbarwidth{#1}{\msc@instbarwidth{#1}}% + \msc@setinstlxpos{#1}{\msc@instxpos{#1}}% + \msc@setinstrxpos{#1}{\msc@instxpos{#1}}% + }% + }% + }% +} +% +% \msc@instregionstyle returns the region style of instance with nickname #1 +\def\msc@instregionstyle#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instregionstyle#1\endcsname}% +} +% +% \msc@instbarwidth returns the width of the bar of instance with nickname #1 +\def\msc@instbarwidth#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instbarwidth#1\endcsname}% +} +% +% \msc@setinstbarwidth sets the width of the bar of instance with nickname #1 +% to the string #2 +\def\msc@setinstbarwidth#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \expandafter\edef\csname instbarwidth#1\endcsname{#2}% + \ifthenelse{\lengthtest{\instbarwidth < #2}}% + {\expandafter\def\csname instisfat#1\endcsname{true}}% + {\expandafter\def\csname instisfat#1\endcsname{false}}% + }% +} +% +%\msc@isfateinst returns one of the strings `true' of `false', indicating if +% the instance with nickname #1 is a fat instance. +\def\msc@instisfat#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \csname instisfat#1\endcsname}% +} +% +% +% \changeinstbarwidth changes the instance width of instance with nickname #1 to +% the length #2 +\def\changeinstbarwidth#1#2{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}% + {% else, #1 is defined + \msc@drawinstanceline{#1}% + \setlength{\tmp@X}{\msc@instxpos{#1}}% + \setlength{\tmp@Y}{\msc@currentheight}% + \msc@setinstypos{#1}{\the\tmp@Y}% + \setlength{\tmp@Xb}{#2}% + \ifthenelse{\lengthtest{\tmp@Xb > \instbarwidth}}% + {% + \setlength{\tmp@Xb}{0.5\tmp@Xb}% + \addtolength{\tmp@Xb}{\tmp@X}}% + {% + \setlength{\tmp@Xb}{\tmp@X}}% + \ifthenelse{\equal{true}{\msc@instisfat{#1}}} + {% + \setlength{\tmp@Xa}{\msc@instbarwidth{#1}}% + \setlength{\tmp@Xa}{0.5\tmp@Xa}% + \addtolength{\tmp@Xa}{\tmp@X}% + }{% + \setlength{\tmp@Xa}{\tmp@X}% + }% + \draw (\tmp@Xa,-\tmp@Y) -- (\tmp@Xb,-\tmp@Y);% + \setlength{\tmp@Xb}{#2}% + \ifthenelse{\lengthtest{\tmp@Xb > \instbarwidth}}% + {% + \setlength{\tmp@Xb}{-0.5\tmp@Xb}% + \addtolength{\tmp@Xb}{\tmp@X}}% + {% + \setlength{\tmp@Xb}{\tmp@X}}% + \ifthenelse{\equal{true}{\msc@instisfat{#1}}} + {% + \setlength{\tmp@Xa}{\msc@instbarwidth{#1}}% + \setlength{\tmp@Xa}{-0.5\tmp@Xa}% + \addtolength{\tmp@Xa}{\tmp@X}% + }{% + \setlength{\tmp@Xa}{\tmp@X}% + }% + \draw (\tmp@Xa,-\tmp@Y) -- (\tmp@Xb,-\tmp@Y);% + \msc@setinstbarwidth{#1}{#2}% + }% +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DUMMY INSTANCES (start and stop) +% +% Start a dummy inst +% +% \inststart[#1]{#2}[#3]{#4}[#5]{#6} +% #1: width of instance head and foot symbol +% #2: nickname of stared instance +% #3: height of instance head symbol +% #4: name of the instance (above instance head symbol) +% #5: height of instance foot symbol +% #6: name of the instance (inside instance head symbol) +% +\newcommand{\inststart}[2][\instwidth]{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \def\instname{#2}% + \expandafter\def\csname instwidth\instname\endcsname{#1}% `instance head and foot symbol width' + \inststart@A + } +} + +\newcommand{\inststart@A}[2][\instheadheight]{% + \expandafter\def\csname instheadheight\instname\endcsname{#1}% `instance head symbol height' + \expandafter\def\csname instabname\instname\endcsname{#2}% `above name' + \inststart@B +} + +\newcommand{\inststart@B}[2][\instfootheight]{% + \expandafter\def\csname instfootheight\instname\endcsname{#1}% `instance foot symbol height' + \expandafter\def\csname instinname\instname\endcsname{#2}% `inside name' + % draw the instance header symbol + \msc@drawinstanceheadsymbol{\instname}{\the\msc@currentheight}% + % redefine the instance's y position + \setlength{\tmp@Y}{\msc@currentheight+\msc@instheadheight{\instname}}% + \msc@setinstypos{\instname}{\the\tmp@Y}% +} +% +% \inststop{#1} +% #1: nick name of instance +% +% Draws the footer of #1 at current level. +\def\inststop#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \addtolength{\msc@currentheight}{\lastlevelheight} + \msc@drawinstanceline{#1}% + \setlength{\tmp@Y}{\msc@currentheight}% + \msc@drawinstancefootsymbol{#1}{\the\tmp@Y}% + \addtolength{\msc@currentheight}{-\lastlevelheight} + \msc@setinstypos{#1}{undefined} + } +} +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5 +% +% CREATE +% +% \create(*) creates a new msc-instance and draws its head symbol +% {#1}: label above creation message +% [#2]: label position +% {#3}: nickname of creating instance +% [#4]: label placement +% {#5}: nickname of created instance +% [#6]: width of created instance head and foot symbol +% {#7}: name of the instance (above instance head symbol) +% [#8]: height of created instance head symbol +% [#9]: height of ceated instance foot symbol +% {#10}: name of the instance (inside instance head symbol) +% [#11]: color of instance +% +% Some commands are defined as well (INSTNR is the arabic +% representation of the instance number): +% \instabname#3: `above name' of instance with nickname #3 +% \instinname#3: `inside name' of instance with nickname #3 +% \instlinestyle#3: the line style (dashed or solid) of instance with nickname #3 +\newcommand{\create}{% + \@ifstar% + {\def\mess@style{mess}\def\mess@linestyle{dashed}\create@A}{\def\mess@style{mess}\def\mess@linestyle{solid}\create@A}% +}% +\newcommand{\create@A}[1]{% + \def\mess@labeltext{#1}% + \create@B% +} +\newcommand{\create@B}[2][t]{% + \def\mess@labelposition{#1}% + \def\mess@sender{#2}% + \create@C% +} +\newcommand{\create@C}[2][0.5]{% + \def\mess@labelplacement{#1}% + \def\mess@leveloffset{0}% + \def\mess@instanceoffset{\msc@instwidth{#2}*\real{0.5}}% + \def\mess@receiver{#2}% + \def\instname{#2}% + \create@D% +} + +\newcommand{\create@D}[2][\instwidth]{% + \expandafter\def\csname instwidth\instname\endcsname{#1}% `instance head and foot symbol width' + \expandafter\def\csname instabname\instname\endcsname{#2}% `above name' + \create@E% +} + +\newcommand{\create@E}[1][\instheadheight]{% + \expandafter\def\csname instheadheight\instname\endcsname{#1}% `instance head symbol height' + \create@F% +} + +\newcommand{\create@F}[2][\instfootheight]{% + \expandafter\def\csname instfootheight\instname\endcsname{#1}% `instance foot symbol height' + \expandafter\def\csname instinname\instname\endcsname{#2}% `inside name' + \create@G% +} + +\newcommand{\create@G}[1][black]{% +% + \expandafter\@ifundefined{mscinst\instname}{% + \msc@instundefinederr{\instname}}{% else, mess receiver is defined + \expandafter\def\csname instcolor\instname\endcsname{#1}% instance color + % draw the instance header symbol + \pgfsetcolor{#1}% + \color{#1}% + \setlength{\tmp@X}{\msc@instxpos{\instname}}% x-center head box + \setlength{\tmp@Y}{\msc@currentheight}% y-center head box + \setlength{\tmp@Xa}{\tmp@X + \msc@instwidth{\instname}*\real{-0.5}}% x-upperleft head box + \setlength{\tmp@Ya}{\msc@currentheight + \msc@instheadheight{\instname}*\real{-0.5}}% + \setlength{\tmp@Xb}{\tmp@Xa+\msc@instwidth{\instname}}% x-lowerright head box + \setlength{\tmp@Yb}{\tmp@Ya+\msc@instheadheight{\instname}}% y-lowerright head box + \draw (\tmp@Xa,-\tmp@Ya) rectangle (\tmp@Xb,-\tmp@Yb); + \node at (\tmp@X,-\tmp@Ya + 4pt) {\raisebox{\labeldist}{\makebox[0pt][c]{\msc@instabname{\instname}}}};% + \node at (\tmp@X,-\tmp@Y) {\raisebox{-.5ex}{\makebox[0pt][c]{\msc@instinname{\instname}}}};% + % redefine the instance's y position + \setlength{\tmp@Y}{\msc@currentheight}% + \addtolength{\tmp@Y}{\msc@instheadheight{\instname}*\real{0.5}} + \msc@setinstypos{\instname}{\the\tmp@Y}% + + + \expandafter\@ifundefined{mscinst\mess@sender}{}{% + % draw creation arrow + \msc@drawarrow% + }% + \pgfsetcolor{\msc@color}% + \color{\msc@color}% + }% +}% +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% INLINE EXPRESSIONS (inlines) +% +% +% \inlinestart creates an inline expression at the current level +% [#1]: left overlap +% [#2]: right overlap +% #3: nickname of the inline +% #4: text of the inline +% #5: first instance of the inline +% #6: final instance of the inline +\newcommand{\inlinestart}[1][\inlineoverlap]{% + \def\msc@leftoverlap{#1}\msc@inlinecont% +} +\newcommand{\msc@inlinecont}[5][\msc@leftoverlap]{\msc@declinline{\msc@leftoverlap}{#1}{#2}{#3}{#4}{#5}}% +% +% \inlineend draws and ends the inline expression with nickname #1 +% +\newcommand{\inlineend}{% + \@ifstar{\msc@inlineends}{\msc@inlineend}} +% +% \inlineseparator draws a ``separator'' (horizontal dashed line) through +% inline expression with nickname #1 +\newcommand{\inlineseparator}[1]{% + \expandafter\@ifundefined{mscinl#1}{% + \msc@inlundefinederr{#1}}{% else, #1 is defined + \setlength{\tmp@Y}{\msc@currentheight}% + \draw[style=dashed] (\msc@inlulx{#1},-\tmp@Y) -- (\msc@inllrx{#1},-\tmp@Y);% + }% +} +% +% internal commands to implement the inline expressions: +% #1: left overlap +% #2: right overlap +% #3: nickname of the inline +% #4: text of the inline +% #5: first instance of the inline +% #6: final instance of the inline +% +\def\msc@declinline#1#2#3#4#5#6{% + \@ifundefined{mscinl#3}{% + \@ifundefined{mscinst#5}{% #5 is not an instance nickname + \msc@instundefinederr{#5}}{% + \@ifundefined{mscinst#6}{% #6 is not an instance nickname + \msc@instundefinederr{#6}}{% + \ifthenelse{\lengthtest{\msc@instxpos{#5}>\msc@instxpos{#6}}}{% + \msc@inlfirstlasterror{#3}{#5}{#6}}{% + \@namedef{mscinl#3}{\relax}% + \expandafter\def\csname inltext#3\endcsname{\raisebox{\depth}[\totalheight][0pt]{#4}}% + \ifthenelse{\equal{true}{\msc@instisfat{#5}}}% + {% + \setlength{\tmp@X}{\msc@instlxpos{#5}-#1}% + }% + {% + \setlength{\tmp@X}{\msc@instxpos{#5}-#1}% + }% + \expandafter\edef\csname inlulx#3\endcsname{\the\tmp@X}% + \expandafter\edef\csname inluly#3\endcsname{\the\msc@currentheight}% + \ifthenelse{\equal{true}{\msc@instisfat{#6}}}% + {% + \setlength{\tmp@X}{\msc@instrxpos{#6}+#2}% + }% + {% + \setlength{\tmp@X}{\msc@instxpos{#6}+#2}% + }% + \expandafter\edef\csname inllrx#3\endcsname{\the\tmp@X}% + \expandafter\edef\csname inllry#3\endcsname{undefined}% + % two additional instances are defined + \msc@declinst{#3left}{\relax}{\relax}{\the\instbarwidth}% left of inline + \msc@setinstxpos{#3left}{\msc@inlulx{#3}}% + \msc@setinstlxpos{#3left}{\msc@inlulx{#3}}% + \msc@setinstrxpos{#3left}{\msc@inlulx{#3}}% + \msc@setinstypos{#3left}{undefined}% no instance line drawing + \msc@declinst{#3right}{\relax}{\relax}{\the\instbarwidth}% left of inline + \msc@setinstxpos{#3right}{\msc@inllrx{#3}}% + \msc@setinstlxpos{#3right}{\msc@inllrx{#3}}% + \msc@setinstrxpos{#3right}{\msc@inllrx{#3}}% + \msc@setinstypos{#3right}{undefined}% no instance line drawing + }% + }% + }% + }{% nickname #3 already defined + \msc@nicknamedefinederr{#3}% + }% +} +% +% \msc@inlulx gets the upper-left x-position of inline with nickname #1. +\def\msc@inlulx#1{% + \expandafter\@ifundefined{mscinl#1}{% + \msc@inlundefinederr{#1}}{% else, #1 is defined + \csname inlulx#1\endcsname% + }% +} +% +% \msc@inluly gets the upper-left y-position of inline with nickname #1. +\def\msc@inluly#1{% + \expandafter\@ifundefined{mscinl#1}{% + \msc@inlundefinederr{#1}}{% else, #1 is defined + \csname inluly#1\endcsname% + }% +} +% +% \msc@inllrx gets the lower-right x-position of inline with nickname #1. +\def\msc@inllrx#1{% + \expandafter\@ifundefined{mscinl#1}{% + \msc@inlundefinederr{#1}}{% else, #1 is defined + \csname inllrx#1\endcsname% + }% +} +% +% \msc@inllry gets the lower-right y-position of inline with nickname #1. +\def\msc@inllry#1{% + \expandafter\@ifundefined{mscinl#1}{% + \msc@inlundefinederr{#1}}{% else, #1 is defined + \csname inllry#1\endcsname% + }% +} +% +% \msc@inltext gets the text of inline with nickname #1 +\def\msc@inltext#1{% + \expandafter\@ifundefined{mscinl#1}{% + \msc@inlundefinederr{#1}}{% else, #1 is defined + \csname inltext#1\endcsname% + }% +} +% +% \msc@inlineend completes the inline with nickname #1 +% (the bottom line is solid) +\def\msc@inlineend#1{% + \expandafter\@ifundefined{mscinl#1}{% + \msc@inlundefinederr{#1}}{% else, #1 is defined + \expandafter\edef\csname inllry#1\endcsname{\the\msc@currentheight}% + \setlength{\tmp@Xa}{\msc@inlulx{#1}}% + \setlength{\tmp@Ya}{\msc@inluly{#1}}% + \setlength{\tmp@Xb}{\msc@inllrx{#1}}% + \setlength{\tmp@Yb}{\msc@inllry{#1}}% +%% Debug info: +% \typeout{(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)}% + \draw (\tmp@Xa,-\tmp@Ya) rectangle (\tmp@Xb,-\tmp@Yb);% + \node {\global\sbox{\tmp@box}{\msc@inltext{#1}}};% + \setlength{\tmp@X}{\wd\tmp@box}% + \setlength{\tmp@X}{1.1\tmp@X+\labeldist}% + \setlength{\tmp@Y}{\ht\tmp@box}% + \setlength{\tmp@Y}{1.1\tmp@Y+\labeldist}% + \setlength{\tmp@Xb}{\tmp@X+\labeldist}% + \setlength{\tmp@Yb}{\tmp@Y+\labeldist}% + \node[below right, inner sep = \labeldist] at (\tmp@Xa,-\tmp@Ya) {\msc@inltext{#1}};% + \draw (\tmp@Xa+0,-\tmp@Ya-\tmp@Yb) -- (\tmp@Xa+\tmp@X,-\tmp@Ya-\tmp@Yb) --% + (\tmp@Xa+\tmp@Xb,-\tmp@Ya-\tmp@Y) -- (\tmp@Xa+\tmp@Xb,-\tmp@Ya+0);% + + }% +} +% +% \msc@inlineends completes the inline with nickname #1 +% (the bottom line is dashed) +\def\msc@inlineends#1{% + \expandafter\@ifundefined{mscinl#1}{% + \msc@inlundefinederr{#1}}{% else, #1 is defined + \expandafter\edef\csname inllry#1\endcsname{\the\msc@currentheight}% + \setlength{\tmp@Xa}{\msc@inlulx{#1}}% + \setlength{\tmp@Ya}{\msc@inluly{#1}}% + \setlength{\tmp@Xb}{\msc@inllrx{#1}}% + \setlength{\tmp@Yb}{\msc@inllry{#1}}% +%% Debug info: +% \typeout{(\tmp@Xa,-\tmp@Ya)(\tmp@Xb,-\tmp@Yb)}% + % first the solid part of the inline expression: + \draw (\tmp@Xa,-\tmp@Yb) -- (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + % then the dashed bottom line: + \draw[style=dashed] (\tmp@Xa,-\tmp@Yb) -- (\tmp@Xb,-\tmp@Yb); + \node {\global\sbox{\tmp@box}{\msc@inltext{#1}}};% + \setlength{\tmp@X}{\wd\tmp@box}% + \setlength{\tmp@X}{1.1\tmp@X+\labeldist}% + \setlength{\tmp@Y}{\ht\tmp@box}% + \setlength{\tmp@Y}{1.1\tmp@Y+\labeldist}% + \setlength{\tmp@Xb}{\tmp@X+\labeldist}% + \setlength{\tmp@Yb}{\tmp@Y+\labeldist}% + \node[below right, inner sep = \labeldist] at (\tmp@Xa,-\tmp@Ya) {\msc@inltext{#1}};% + \draw (\tmp@Xa+0,-\tmp@Ya-\tmp@Yb) -- (\tmp@Xa+\tmp@X,-\tmp@Ya-\tmp@Yb) --% + (\tmp@Xa+\tmp@Xb,-\tmp@Ya-\tmp@Y) -- (\tmp@Xa+\tmp@Xb,-\tmp@Ya+0);% + }% +} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% REFERENCES +% +% +% \referencestart creates an msc reference at the current level +% [#1] : left overlap +% [#2] : right overlap +% #3: nickname of the reference +% #4: text of the reference +% #5: first instance of the reference +% #6: final instance of the reference +\newcommand{\referencestart}[1][\referenceoverlap]{% + \def\msc@leftoverlap{#1}\msc@referencecont% +} +\newcommand{\msc@referencecont}[5][\referenceoverlap]{% + \msc@declreference{\msc@leftoverlap}{#1}{#2}{#3}{#4}{#5}% + \setcounter{tmpcnt}{0}% + \msc@reffindfirst{#2}{\msc@drawtorefaux}% +} +% +% \referenceend draws and ends the reference with nickname #1 +\newcommand{\referenceend}[1]{% + \msc@drawreference{#1}% + \setcounter{tmpcnt}{0}% + \setlength{\tmp@Y}{\msc@currentheight}% + \msc@reffindfirst{#1}{\msc@refresetypos{\the\tmp@Y}}% +} +% +% internal commands to implement references: +% #1: left overlap +% #2: right overlap +% #3: nickname of the reference +% #4: text of the reference +% #5: first instance of the reference +% #6: final instance of the reference +% +\def\msc@declreference#1#2#3#4#5#6{% + \@ifundefined{mscref#3}{% + \@ifundefined{mscinst#5}{% #5 is not an instance nickname + \msc@instundefinederr{#5}}{% + \@ifundefined{mscinst#6}{% #6 is not an instance nickname + \msc@instundefinederr{#6}}{% + \ifthenelse{\lengthtest{\msc@instxpos{#5}>\msc@instxpos{#6}}}{% + \msc@reffirstlasterror{#3}{#5}{#6}}{% + \@namedef{mscref#3}{\relax}% + \expandafter\def\csname reftext#3\endcsname{#4}% + \ifthenelse{\equal{true}{\msc@instisfat{#5}}}% + {% + \setlength{\tmp@X}{\msc@instlxpos{#5}-#1}% + }% + {% + \setlength{\tmp@X}{\msc@instxpos{#5}-#1}% + }% + \expandafter\edef\csname refulx#3\endcsname{\the\tmp@X}% + \expandafter\edef\csname refuly#3\endcsname{\the\msc@currentheight}% + \ifthenelse{\equal{true}{\msc@instisfat{#6}}}% + {% + \setlength{\tmp@X}{\msc@instrxpos{#6}+#2}% + }% + {% + \setlength{\tmp@X}{\msc@instxpos{#6}+#2}% + }% + \expandafter\edef\csname reflrx#3\endcsname{\the\tmp@X}% + \expandafter\edef\csname reflry#3\endcsname{undefined}% + \expandafter\def\csname reffirst#3\endcsname{#5}% + \expandafter\def\csname reffinal#3\endcsname{#6}% + % two additional instances are defined + \msc@declinst{#3left}{\relax}{\relax}{\the\instbarwidth}% left of reference + \msc@setinstxpos{#3left}{\msc@refulx{#3}}% + \msc@setinstlxpos{#3left}{\msc@refulx{#3}}% + \msc@setinstrxpos{#3left}{\msc@refulx{#3}}% + \msc@setinstypos{#3left}{undefined}% no instance line drawing + \msc@declinst{#3right}{\relax}{\relax}{\the\instbarwidth}% left of reference + \msc@setinstxpos{#3right}{\msc@reflrx{#3}}% + \msc@setinstlxpos{#3right}{\msc@reflrx{#3}}% + \msc@setinstrxpos{#3right}{\msc@reflrx{#3}}% + \msc@setinstypos{#3right}{undefined}% no instance line drawing + }% + }% + }% + }{% nickname #3 already defined + \msc@nicknamedefinederr{#3}% + }% +} +% +% \msc@refulx gets the upper-left x-position of reference with nickname #1. +\def\msc@refulx#1{% + \expandafter\@ifundefined{mscref#1}{% + \msc@refundefinederr{#1}}{% else, #1 is defined + \csname refulx#1\endcsname% + }% +} +% +% \msc@refuly gets the upper-left y-position of reference with nickname #1. +\def\msc@refuly#1{% + \expandafter\@ifundefined{mscref#1}{% + \msc@refundefinederr{#1}}{% else, #1 is defined + \csname refuly#1\endcsname% + }% +} +% +% \msc@reflrx gets the lower-right x-position of reference with nickname #1. +\def\msc@reflrx#1{% + \expandafter\@ifundefined{mscref#1}{% + \msc@refundefinederr{#1}}{% else, #1 is defined + \csname reflrx#1\endcsname% + }% +} +% +% \msc@reflry gets the lower-right y-position of reference with nickname #1. +\def\msc@reflry#1{% + \expandafter\@ifundefined{mscref#1}{% + \msc@refundefinederr{#1}}{% else, #1 is defined + \csname reflry#1\endcsname% + }% +} +% +% \msc@reftext gets the text of reference with nickname #1 +\def\msc@reftext#1{% + \expandafter\@ifundefined{mscref#1}{% + \msc@refundefinederr{#1}}{% else, #1 is defined + \csname reftext#1\endcsname% + }% +} +% +% \msc@reftext gets the nickname of the first instance of the reference with nickname #1 +\def\msc@reffirst#1{% + \expandafter\@ifundefined{mscref#1}{% + \msc@refundefinederr{#1}}{% else, #1 is defined + \csname reffirst#1\endcsname% + }% +} +% +% \msc@reftext gets the nickname of the final instance of the reference with nickname #1 +\def\msc@reffinal#1{% + \expandafter\@ifundefined{mscref#1}{% + \msc@refundefinederr{#1}}{% else, #1 is defined + \csname reffinal#1\endcsname% + }% +} +% +% \msc@drawreference completes the reference with nickname #1 +\def\msc@drawreference#1{% + \expandafter\@ifundefined{mscref#1}{% + \msc@refundefinederr{#1}}{% else, #1 is defined + \expandafter\edef\csname reflry#1\endcsname{\the\msc@currentheight}% + \setlength{\tmp@Xa}{\msc@refulx{#1}}% + \setlength{\tmp@Ya}{\msc@refuly{#1}}% + \setlength{\tmp@Xb}{\msc@reflrx{#1}}% + \setlength{\tmp@Yb}{\msc@reflry{#1}}% +%% Debug info: + + \draw[rounded corners=0.25cm] (\tmp@Xa,-\tmp@Ya) rectangle (\tmp@Xb,-\tmp@Yb);% note: rounded corners + \setlength{\tmp@X}{\tmp@Xb-\tmp@Xa}% + \setlength{\tmp@Y}{\tmp@Yb-\tmp@Ya}% + \node[inner sep = 0] at (\tmp@Xa + .5\tmp@X, -\tmp@Ya - .5\tmp@Y)% + {\raisebox{-.5ex}{\makebox[0pt][c]{\msc@reftext{#1}}}};% + }% +} +% +\def\msc@reffindfirst#1#2{% + \ifthenelse{\value{tmpcnt} < \value{mscinstcnt}}{% +% Debug info: +% \typeout{(drawtoref) checking \msc@instnickname{tmpcnt}}% + \ifthenelse{\equal{\msc@instnickname{tmpcnt}}{\msc@reffirst{#1}}}{% first instance found +% Debug info: +% \typeout{first found: \msc@instnickname{tmpcnt}}% + #2{#1}}{% else, keep on looking + \msc@incrcounter{tmpcnt}% + \msc@reffindfirst{#1}{#2}}}{% done ! all instances checked + }% +} +% +\def\msc@drawtorefaux#1{% + \ifthenelse{\value{tmpcnt} < \value{mscinstcnt}}{% +% Debug info: +% \typeout{(drawtorefaux) checking \msc@instnickname{tmpcnt}}% + \msc@drawinstanceline{\msc@instnickname{tmpcnt}}% + \msc@setinstypos{\msc@instnickname{tmpcnt}}{undefined}% + \ifthenelse{\equal{\msc@instnickname{tmpcnt}}{\msc@reffinal{#1}}}{% final instance found +% Debug info: +% \typeout{final found: \msc@instnickname{tmpcnt}}% + }{% else, non-final + \msc@incrcounter{tmpcnt}% + \msc@drawtorefaux{#1}}% + }{% done ! all instances checked + }% +} +% +\def\msc@refresetypos#1#2{% + \ifthenelse{\value{tmpcnt} < \value{mscinstcnt}}{% +% Debug info: +% \typeout{(drawtorefaux) checking \msc@instnickname{tmpcnt}} + \msc@setinstypos{\msc@instnickname{tmpcnt}}{#1}% + \ifthenelse{\equal{\msc@instnickname{tmpcnt}}{\msc@reffinal{#2}}}{% final instance found +% Debug info: +% \typeout{final found: \msc@instnickname{tmpcnt}}% + }{% else, non-final + \msc@incrcounter{tmpcnt}% + \msc@refresetypos{#1}{#2}}% + }{% done ! all instances checked + }% +} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% CO-REGIONS +% +% \coregionstart starts a coregion on instance #1 (nickname) in the current level. +\def\coregionstart#1{\regionstart{coregion}{#1}} +% \coregionend ends a coregion on instance #1 (nickname) in the current level. +\def\coregionend#1{\regionend{#1}}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% REGIONS (normal, coregion, suspension, and activation) +% +% +% \regionstart{#1}[#2]{#3}[#4][#5] +% starts a region +% #1: region style: normal, coregion, suspension, or activation +% #2: region color +% #3: nickname: nick name of the instance +% #4: regionwidth: width of region rectangle +% #5: regionbarwidth: width of coregion ends +\def\regionstart#1{% + \def\regionstyle{#1}% + \regionstart@A% +} + +\newcommand{\regionstart@A}[2][black]{ + \expandafter\@ifundefined{mscinst#2}{% + \msc@instundefinederr{#2}} + {% else, #1 is defined + \def\instname{#2}% + \msc@setregioncolor{\instname}{#1}% + \regionstart@B% + } +} + +\newcommand{\regionstart@B}[1][\regionwidth]{ + \msc@setregionwidth{\instname}{#1}% + \regionstart@C% + } + +\newcommand{\regionstart@C}[1][\regionbarwidth]{ + \msc@setregionbarwidth{\instname}{#1}% + \msc@drawinstanceline{\instname}% + \ifthenelse{\equal{\regionstyle}{activation}}{\msc@setinstregionstyle{\instname}{activation}}{} + \ifthenelse{\equal{\regionstyle}{coregion}}{\msc@setinstregionstyle{\instname}{coregion}}{} + \ifthenelse{\equal{\regionstyle}{suspension}}{\msc@setinstregionstyle{\instname}{suspension}}{} + \msc@drawregionstart{\instname}% +}% +% +% \regionend{#1} +% ends the region of instance with nickname #1 +\def\regionend#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \msc@drawinstanceline{#1}% + \msc@drawregionend{#1}% + \msc@setinstregionstyle{#1}{normal}% + }% +} +% +% +\def\msc@drawregionstart#1{% + \setlength{\tmp@Y}{\msc@currentheight}% + \pgfsetcolor{\msc@regioncolor{#1}}% + \ifthenelse{\equal{\msc@instisfat{#1}}{true}} + {% + \setlength{\tmp@Xa}{\msc@instlxpos{#1}}% + \setlength{\tmp@Xb}{\msc@instrxpos{#1}}% + \draw (\tmp@Xa,-\tmp@Y) -- (\tmp@Xb,-\tmp@Y);% + } + {% + \ifthenelse{\equal{\msc@instregionstyle{#1}}{coregion}}{ + \setlength{\tmp@Xa}{-\msc@regionbarwidth{#1} + \msc@regionwidth{#1}*\real{-0.5} +\msc@instxpos{#1}}% + \setlength{\tmp@Xb}{\msc@regionbarwidth{#1} + \msc@regionwidth{#1}*\real{0.5} +\msc@instxpos{#1}}% + }{ + \setlength{\tmp@Xa}{\msc@regionwidth{#1}*\real{-0.5} +\msc@instxpos{#1}}% + \setlength{\tmp@Xb}{\msc@regionwidth{#1}*\real{0.5} +\msc@instxpos{#1}}% + } + \draw (\tmp@Xa,-\tmp@Y) -- (\tmp@Xb,-\tmp@Y);% + } + \msc@setinstypos{#1}{\the\tmp@Y}% + \pgfsetcolor{\msc@color}% +} +% +% +\def\msc@drawregionend#1{% + \setlength{\tmp@Y}{\msc@currentheight}% + \pgfsetcolor{\msc@regioncolor{#1}}% + \ifthenelse{\equal{\msc@instisfat{#1}}{true}} + {% + \setlength{\tmp@Xa}{\msc@instlxpos{#1}}% + \setlength{\tmp@Xb}{\msc@instrxpos{#1}}% + \draw (\tmp@Xa,-\tmp@Y) -- (\tmp@Xb,-\tmp@Y);% + } + { + \ifthenelse{\equal{\msc@instregionstyle{#1}}{coregion}}{ + \setlength{\tmp@Xa}{-\msc@regionbarwidth{#1} + \msc@regionwidth{#1}*\real{-0.5} +\msc@instxpos{#1}}% + \setlength{\tmp@Xb}{\msc@regionbarwidth{#1} + \msc@regionwidth{#1}*\real{0.5} +\msc@instxpos{#1}}% + }{ + \setlength{\tmp@Xa}{\msc@regionwidth{#1}*\real{-0.5} +\msc@instxpos{#1}}% + \setlength{\tmp@Xb}{\msc@regionwidth{#1}*\real{0.5} +\msc@instxpos{#1}}% + } + \draw (\tmp@Xa,-\tmp@Y) -- (\tmp@Xb,-\tmp@Y);% + } + \msc@setinstypos{#1}{\the\tmp@Y}% + \pgfsetcolor{\msc@color}% +} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% MESSAGE ARROWS +% +% \messarrowscale sets the arrow scale +\def\msc@drawarrowend{yes}% +\def\messarrowscale#1{ +\tikzstyle{arrowstyle}=[decoration={markings,mark=at position 1 with {\arrow[scale=#1]% + {stealth}}},postaction={decorate},shorten >=0.4pt]% +}% +% +% \msc@setleveloffset sets the internal level offset +\def\msc@setleveloffset#1{% + \def\msc@leveloffset{#1}% +} + +% \mess has one optional argument to define the position of +% the label of a self message. +% \mess*[#1]{#2}[#3]{#4}[#5]{#6}[#7][#8] +% *: if star line is dashed, solid otherwise +% #1: [l/r] self message position +% #2: message label +% #3: [t/b] label position +% #4: sender instance +% #5: label placement +% #6: receiver instance +% #7: level offset +% #8: instance offset +\newcommand{\mess}{% + \@ifstar% + {\def\mess@style{mess}\def\mess@linestyle{dashed}\mess@A}{\def\mess@style{mess}\def\mess@linestyle{solid}\mess@A}% +}% +% +\newcommand{\mess@A}[2][l]{% + \def\selfmess@position{#1}% + \def\mess@labeltext{#2}% + \mess@B% +}% +\newcommand{\mess@B}[2][\ifx\mess@sender\mess@receiver \selfmess@position\else t\fi]{% + \def\mess@labelposition{#1}% + \def\mess@sender{#2}% + \mess@C% +} +\newcommand{\mess@C}[2][0.5]{% + \def\mess@labelplacement{#1}% + \def\mess@receiver{#2}% + \mess@D% +} +\newcommand{\mess@D}[1][\ifx\mess@sender\mess@receiver 1\else 0\fi]{% + \edef\mess@leveloffset{#1}% + \mess@E% +} + +\newcommand{\mess@E}[1][0\mscunit]{% + \edef\mess@instanceoffset{#1}% + \msc@drawarrow% + \edef\mess@instanceoffset{0\mscunit}% +} +\newcommand{\msc@drawarrow}{% + \expandafter\@ifundefined{mscinst\mess@sender}{% + \msc@instundefinederr{\mess@sender}}{% else, sender is defined + \expandafter\@ifundefined{mscinst\mess@receiver}{% + \msc@instundefinederr{\mess@receiver}}{% else, receiver is defined + \ifx\mess@sender\mess@receiver\msc@drawselfarrow\else\msc@drawnonselfarrow\fi% + }% + }% +} +\newcommand{\msc@drawselfarrow}{% + \ifthenelse{\equal{\selfmess@position}{l} \or% + \equal{\selfmess@position}{r}% + }{% + \ifthenelse{\equal{\selfmess@position}{l}}% + {% + \setlength{\tmp@Xa}{\msc@instlxpos{\mess@sender} - \selfmesswidth}% + \setlength{\tmp@Xb}{\tmp@Xa}% + }{% ELSE + \setlength{\tmp@Xa}{\msc@instrxpos{\mess@sender} + \selfmesswidth }% + \setlength{\tmp@Xb}{\tmp@Xa}% + }% + \setlength{\tmp@Ya}{\msc@currentheight}% + \setlength{\tmp@Yb}{\msc@currentheight + (\levelheight * \real{\mess@leveloffset})}% + \msc@computelabelcoords% + \msc@computelabelspec% + \node[\msc@labelrefpoint] at (\tmp@X,-\tmp@Y){\msc@labelbox{\mess@labeltext}};% + \ifthenelse{\equal{\selfmess@position}{l}}% + {% + \setlength{\tmp@Xa}{\msc@instlxpos{\mess@sender} }% + \setlength{\tmp@Xc}{\msc@instlxpos{\mess@sender} - \mess@instanceoffset}% + }{% ELSE + \setlength{\tmp@Xa}{\msc@instrxpos{\mess@sender} }% + \setlength{\tmp@Xc}{\msc@instrxpos{\mess@sender} + \mess@instanceoffset}% + }% + \ifthenelse{\equal{\mess@style}{mess}}% + {% THEN message arrow + \draw[arrowstyle, style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb) -- (\tmp@Xc,-\tmp@Yb);% + }{% ELSE order arrow + \ifthenelse{\equal{\msc@instregionstyle{\mess@sender}}{coregion}} + {% + \ifthenelse{\equal{\order@direction}{no}}{ + \ifthenelse{\equal{\selfmess@position}{l}}% + {% + \addtolength{\tmp@Xb}{2\selfmesswidth}% + }{ + \addtolength{\tmp@Xb}{-2\selfmesswidth}% + } + \setlength{\tmp@Yd}{.5\tmp@Yb + .5\tmp@Ya}% + \ifthenelse{\equal{\msc@drawarrowend}{yes}}{ + \draw[arrowstyle, style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yd);% + }{ + \draw[style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yd);% + } + \draw[style=\mess@linestyle] (\tmp@Xb,-\tmp@Yd) -- (\tmp@Xb,-\tmp@Yb) -- (\tmp@Xc,-\tmp@Yb);% + }{ + \ifthenelse{\equal{\selfmess@position}{l}}% + {% + \setlength{\tmp@Xa}{\msc@instlxpos{\mess@sender}} + \setlength{\tmp@Xb}{\msc@instrxpos{\mess@sender}} + \setlength{\tmp@Xc}{\tmp@Xb - \tmp@Xa} + \setlength{\tmp@Xc}{.5\tmp@Xc + \tmp@Xa} + }{% + \setlength{\tmp@Xa}{\msc@instrxpos{\mess@sender}} + \setlength{\tmp@Xb}{\msc@instlxpos{\mess@sender}} + \setlength{\tmp@Xc}{\tmp@Xa - \tmp@Xb} + \setlength{\tmp@Xc}{-.5\tmp@Xc + \tmp@Xa} + } + \ifthenelse{\equal{\msc@drawarrowend}{yes}}{ + \setlength{\tmp@Yc}{\tmp@Yb - \tmp@Ya} + \setlength{\tmp@Yc}{.5\tmp@Yc + \tmp@Ya} + \draw[arrowstyle, style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xc,-\tmp@Yc);% + \draw[style=\mess@linestyle] (\tmp@Xc,-\tmp@Yc) -- (\tmp@Xb,-\tmp@Yb);% + }{ + \draw[style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + } + } + }{ + \setlength{\tmp@Yd}{.5\tmp@Yb + .5\tmp@Ya}% + \ifthenelse{\equal{\msc@drawarrowend}{yes}}{ + \draw[arrowstyle, style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yd);% + }{ + \draw[style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yd);% + } + \draw[style=\mess@linestyle] (\tmp@Xb,-\tmp@Yd) -- (\tmp@Xb,-\tmp@Yb) -- (\tmp@Xc,-\tmp@Yb);% + } + }% + }{% ELSE + \msc@illegalselfmesspositionerr{\selfmess@position}% + }% +} +\newcommand{\msc@drawnonselfarrow}{% + \ifthenelse{\lengthtest{\msc@instxpos{\mess@sender} < \msc@instxpos{\mess@receiver}}}% + {\setlength{\tmp@Xa}{\msc@instrxpos{\mess@sender}}% + \setlength{\tmp@Xb}{\msc@instlxpos{\mess@receiver}}% + \addtolength{\tmp@Xb}{-\mess@instanceoffset}}% + {\setlength{\tmp@Xa}{\msc@instlxpos{\mess@sender}}% + \setlength{\tmp@Xb}{\msc@instrxpos{\mess@receiver}}% + \addtolength{\tmp@Xb}{\mess@instanceoffset}}% + \setlength{\tmp@Ya}{\msc@currentheight}% + \setlength{\tmp@Yb}{\msc@currentheight + (\levelheight * \real{\mess@leveloffset})}% +% \setlength{\tmp@Yb}{\msc@currentheight + (\levelheight * \mess@leveloffset)}% + + \msc@computelabelcoords% + \msc@computelabelspec% + \ifthenelse{\equal{\mess@style}{mess}}% + {% THEN message arrow + \draw[arrowstyle, style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + }{%ELSE order arrow + \setlength{\tmp@Xd}{.5\tmp@Xb + .5\tmp@Xa}% + \setlength{\tmp@Yd}{.5\tmp@Yb + .5\tmp@Ya}% + \ifthenelse{\equal{\msc@drawarrowend}{yes}}{ + \draw[arrowstyle, style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xd,-\tmp@Yd);% + }{ + \draw[style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xd,-\tmp@Yd);% + } + \draw[style=\mess@linestyle] (\tmp@Xd,-\tmp@Yd) -- (\tmp@Xb,-\tmp@Yb);% + }% + \node[\msc@labelrefpoint] at (\tmp@X,-\tmp@Y){\msc@labelbox{\mess@labeltext}};% +}% + +\newcommand{\msc@computelabelcoords}{% + \ifthenelse{%\equal{t}{t}% + \(\equal{\mess@sender}{\mess@receiver} \and \(\equal{\mess@labelposition}{l} \or% + \equal{\mess@labelposition}{r}\)% + \)% + \or% + \(\not\(\equal{\mess@sender}{\mess@receiver}\) \and \(\equal{\mess@labelposition}{t} \or% + \equal{\mess@labelposition}{b}\)% + \)% + }{% THEN + \ifthenelse{\lengthtest{\tmp@Xa<\tmp@Xb}}% + {% THEN + \ifthenelse{\lengthtest{\tmp@Ya<\tmp@Yb}}% + {% THEN + \setlength{\tmp@X}{\tmp@Xa + (\tmp@Xb - \tmp@Xa)*\real{\mess@labelplacement}}% + \setlength{\tmp@Y}{\tmp@Ya + (\tmp@Yb - \tmp@Ya)*\real{\mess@labelplacement}}% + }{% ELSE + \setlength{\tmp@X}{\tmp@Xa + (\tmp@Xb - \tmp@Xa)*\real{\mess@labelplacement}}% + \setlength{\tmp@Y}{\tmp@Yb + (\tmp@Ya - \tmp@Yb) + (\tmp@Yb - \tmp@Ya)*\real{\mess@labelplacement}}% + }% + }{% ELSE + \ifthenelse{\lengthtest{\tmp@Xa>\tmp@Xb}}% + {% THEN + \ifthenelse{\lengthtest{\tmp@Ya<\tmp@Yb}}% + {% THEN + \setlength{\tmp@X}{\tmp@Xb + (\tmp@Xa - \tmp@Xb) + (\tmp@Xb - \tmp@Xa)*\real{\mess@labelplacement}}% + \setlength{\tmp@Y}{\tmp@Ya + (\tmp@Yb - \tmp@Ya)*\real{\mess@labelplacement}}% + }{% ELSE + \setlength{\tmp@X}{\tmp@Xb + (\tmp@Xa - \tmp@Xb) + (\tmp@Xb - \tmp@Xa)*\real{\mess@labelplacement}}% + \setlength{\tmp@Y}{\tmp@Yb + (\tmp@Ya - \tmp@Yb) + (\tmp@Yb - \tmp@Ya)*\real{\mess@labelplacement}}% + }% + }{% ELSE \tmpXa = \tmp@Xb (self message) + \setlength{\tmp@X}{\tmp@Xa}% + \ifthenelse{\lengthtest{\tmp@Ya<\tmp@Yb}}% + {% + \setlength{\tmp@Y}{\tmp@Ya + (\tmp@Yb - \tmp@Ya)*\real{\mess@labelplacement}}% + }{% + \setlength{\tmp@Y}{\tmp@Yb + (\tmp@Ya - \tmp@Yb) + (\tmp@Yb - \tmp@Ya)*\real{\mess@labelplacement}}}% + }% + }% + }{% ELSE + \msc@illegalmesslabelpositionerr{\mess@labelposition}% + } +} + +\newcommand{\msc@computelabelspec}{% + \ifthenelse{\lengthtest{\tmp@Xa < \tmp@Xb}}% + {% THEN W->E + \ifthenelse{\lengthtest{\tmp@Ya < \tmp@Yb}}% + {% THEN NW->SE + \ifthenelse{\equal{\mess@labelposition}{t}}% + {\def\msc@labelrefpoint{right} + \addtolength{\tmp@X}{\labeldist-4pt}% + \addtolength{\tmp@Y}{-\labeldist-4pt}% + }% + {\def\msc@labelrefpoint{below left} + \addtolength{\tmp@X}{-\labeldist+4pt}% + \addtolength{\tmp@Y}{\labeldist-4pt}% + }% + }{% ELSE + \ifthenelse{\lengthtest{\tmp@Ya > \tmp@Yb}}% + {% THEN SW -> NE + \ifthenelse{\equal{\mess@labelposition}{t}}% + {\def\msc@labelrefpoint{left} + \addtolength{\tmp@X}{-\labeldist+4pt}% + \addtolength{\tmp@Y}{-\labeldist-4pt}% + }% + {\def\msc@labelrefpoint{below right} + \addtolength{\tmp@X}{\labeldist-4pt}% + \addtolength{\tmp@Y}{\labeldist-4pt}% + }% + }{% ELSE W->E + \ifthenelse{\equal{\mess@labelposition}{t}}% + {\def\msc@labelrefpoint{} + \addtolength{\tmp@X}{0\labeldist}% + \addtolength{\tmp@Y}{-\labeldist-4pt}% + }% + {\def\msc@labelrefpoint{below} + \addtolength{\tmp@X}{0\labeldist}% + \addtolength{\tmp@Y}{\labeldist-4pt}% + }% + }% + }% + }{% ELSE + \ifthenelse{\lengthtest{\tmp@Xa > \tmp@Xb}}% + {% THEN E -> W + \ifthenelse{\lengthtest{\tmp@Ya < \tmp@Yb}}% + {% THEN NE -> SW + \ifthenelse{\equal{\mess@labelposition}{t}}% + {\def\msc@labelrefpoint{left} + \addtolength{\tmp@X}{-\labeldist+4pt}% + \addtolength{\tmp@Y}{-\labeldist-4pt}% + }% + {\def\msc@labelrefpoint{below right} + \addtolength{\tmp@X}{\labeldist-4pt}% + \addtolength{\tmp@Y}{\labeldist-4pt}% + }% + }{% ELSE + \ifthenelse{\lengthtest{\tmp@Ya > \tmp@Yb}}% + {% THEN SE -> NW + \ifthenelse{\equal{\mess@labelposition}{t}}% + {\def\msc@labelrefpoint{right} + \addtolength{\tmp@X}{\labeldist-4pt}% + \addtolength{\tmp@Y}{-\labeldist-4pt}% + }% + {\def\msc@labelrefpoint{below left} + \addtolength{\tmp@X}{-\labeldist+4pt}% + \addtolength{\tmp@Y}{\labeldist-4pt}% + }% + }{% ELSE E -> W + \ifthenelse{\equal{\mess@labelposition}{t}}% + {\def\msc@labelrefpoint{} + \addtolength{\tmp@X}{0\labeldist}% + \addtolength{\tmp@Y}{-\labeldist-4pt}% + }% + {\def\msc@labelrefpoint{below} + \addtolength{\tmp@X}{0\labeldist}% + \addtolength{\tmp@Y}{\labeldist-4pt}% + }% + } + } + }{% ELSE \tmp@Xa = \tmp@Xb (self message) + \ifthenelse{\equal{\mess@labelposition}{l}}% + {\def\msc@labelrefpoint{left} + \addtolength{\tmp@X}{-\labeldist+4pt}% + \addtolength{\tmp@Y}{0\labeldist}% + }% + {\def\msc@labelrefpoint{right} + \addtolength{\tmp@X}{\labeldist-4pt}% + \addtolength{\tmp@Y}{0\labeldist}% + }% + }% + }% +}% +\newcommand{\msc@labelbox}[1]{{#1}}% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Genralized orders +% \order*[pos][direction]{sender}[isSide]{receiver}[leveloffset][instanceoffset] +% if star no arrow is drawed +% +\newcommand{\order}{% + \@ifstar% + {\def\msc@drawarrowend{no}\order@A}{\def\msc@drawarrowend{yes}\order@A}% +} +\newcommand{\order@A}[1][l]{% + \def\mess@style{order}% + \def\mess@linestyle{dashed}% + \def\selfmess@position{#1}% + \order@B% +} + +%direction no(self order)/yes(directed order) +\newcommand{\order@B}[2][no]{% + \def\order@direction{#1}% + \def\mess@labelposition{\ifx\mess@sender\mess@receiver l\else t\fi}% + \def\mess@labeltext{\relax}% + \def\mess@labelplacement{0.5}% + \def\mess@sender{#2}% + \order@C% +} + +\newcommand{\order@C}[2][no]{% + \def\msc@isSideOrder{#1}% + \def\mess@receiver{#2}% + \order@D% +} + +\newcommand{\order@D}[1][\ifx\mess@sender\mess@receiver 1\else 0\fi]{% + \edef\mess@leveloffset{#1}% + \order@E% +} +\newcommand{\order@E}[1][0pt]{% + \def\mess@instanceoffset{#1}% + \ifthenelse{\equal{\msc@isSideOrder}{no}}{% + \msc@drawarrow% + }{% + \msc@drawsideorder% + }% + \def\msc@drawarrowend{yes} +} + +\newcommand{\msc@drawsideorder}{% + \ifthenelse{\lengthtest{\msc@instxpos{\mess@sender} < \msc@instxpos{\mess@receiver}}}% + {\setlength{\tmp@Xa}{\msc@instrxpos{\mess@sender}}% + \setlength{\tmp@Xb}{\msc@instxpos{\mess@receiver}-\msc@instxpos{\mess@sender}}% + \setlength{\tmp@Xb}{0.5\tmp@Xb}% + \addtolength{\tmp@Xb}{\msc@instxpos{\mess@sender}}% + \setlength{\tmp@Xc}{\msc@instlxpos{\mess@receiver}}% + \addtolength{\tmp@Xc}{-\mess@instanceoffset}}% + {\setlength{\tmp@Xa}{\msc@instlxpos{\mess@sender}}% + \setlength{\tmp@Xb}{\msc@instxpos{\mess@sender}-\msc@instxpos{\mess@receiver}}% + \setlength{\tmp@Xb}{0.5\tmp@Xb}% + \addtolength{\tmp@Xb}{\msc@instxpos{\mess@receiver}}% + \setlength{\tmp@Xc}{\msc@instrxpos{\mess@receiver}}% + \addtolength{\tmp@Xc}{\mess@instanceoffset}}% + \setlength{\tmp@Ya}{\msc@currentheight}% + \setlength{\tmp@Yb}{\msc@currentheight + (\levelheight * \real{\mess@leveloffset})*\real{0.5}}% + \setlength{\tmp@Yc}{\msc@currentheight + (\levelheight * \real{\mess@leveloffset})}% + \ifthenelse{\equal{\selfmess@position}{r}}{ + \setlength{\tmp@Xd}{\tmp@Xa} + \setlength{\tmp@Xa}{\tmp@Xc} + \setlength{\tmp@Xc}{\tmp@Xd} + }{} + \ifthenelse{\equal{\msc@drawarrowend}{yes}}{ + \draw[arrowstyle, style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + \draw[style=\mess@linestyle] (\tmp@Xb,-\tmp@Yb) -- (\tmp@Xb,-\tmp@Yc) -- (\tmp@Xc,-\tmp@Yc);% + }{ + \draw[style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yc) -- (\tmp@Xc,-\tmp@Yc);% + } +} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% LOST and FOUND messages +% +% \lost*[pos]{label}[labelpos]{gate}[slope]{sender}[placement] +% \found*[pos]{label}[labelpos]{gate}[slope]{sender}[placement] +% is star line is dashed +\newcommand{\lost}{% + \@ifstar{\def\mess@linestyle{dashed}\lost@A}{\def\mess@linestyle{solid}\lost@A}% +} +\newcommand{\lost@A}[1][l]{ + \def\lostfound@position{#1}% + %\def\msc@arrowdirection{->}% + \def\lostfound@type{lost}% + \def\msc@circlefillstyle{black}% + \lostfound@B% +} +\newcommand{\found}{% + \@ifstar{\def\mess@linestyle{dashed}\found@A}{\def\mess@linestyle{solid}\found@A}% +} +\newcommand{\found@A}[1][l]{% + \def\lostfound@position{#1}% + %\def\msc@arrowdirection{<-}% + \def\lostfound@type{found}% + \def\msc@circlefillstyle{white}% + \lostfound@B% +} +\newcommand{\lostfound@B}[1]{% + \def\mess@style{mess}% + \def\mess@labeltext{#1}% + \lostfound@C% +} +\newcommand{\lostfound@C}[2][t]{% + \def\mess@labelposition{#1}% + \def\mess@gate{#2}% + \lostfound@D% +} +\newcommand{\lostfound@D}[2][0mm]{% + \setlength{\tmp@Yd}{#1}% + \def\mess@sender{#2}% + \lostfound@E% +} +\newcommand{\lostfound@E}[1][0.5]{% + \def\mess@labelplacement{#1}% + \@lostfound% +} +% +% \@lostfound draws lost and found messages +\def\@lostfound{% + \expandafter\@ifundefined{mscinst\mess@sender}{% + \msc@instundefinederr{\mess@sender}}{% else, \mess@sender is defined + %\setlength{\tmp@Xa}{\msc@instxpos{\mess@sender}}% + \setlength{\tmp@Ya}{\msc@currentheight}% + \setlength{\tmp@Yb}{\msc@currentheight}% + \ifthenelse{\equal{\lostfound@type}{lost}}% + {% + \addtolength{\tmp@Yb}{\tmp@Yd}% + }{% + \addtolength{\tmp@Ya}{\tmp@Yd}% + }% + \ifthenelse{\equal{\lostfound@position}{l}} + {% THEN put lost/found message left + \ifthenelse{\equal{\lostfound@type}{lost}}% + {% THEN + \setlength{\tmp@Xa}% start of arrow + {\msc@instlxpos{\mess@sender}}% + \setlength{\tmp@Xb}% end of arrow + {\tmp@Xa-\selfmesswidth}% + \setlength{\tmp@X}% label position + {\tmp@Xb + (\tmp@Xa - \tmp@Xb) * \real{\mess@labelplacement}}% + \setlength{\tmp@Xc}% circle position + {\tmp@Xb-\lostsymbolradius}% + }{% ELSE + \setlength{\tmp@Xb}% end of arrow + {\msc@instlxpos{\mess@sender}}% + \setlength{\tmp@Xa}% start of arrow + {\tmp@Xb-\selfmesswidth}% + \setlength{\tmp@X}% label position + {\tmp@Xa + (\tmp@Xb - \tmp@Xa) * \real{\mess@labelplacement}}% + \setlength{\tmp@Xc}% circle position + {\tmp@Xa-\lostsymbolradius}% + }% + \setlength{\tmp@Xd}% gate position + {\tmp@Xc-\lostsymbolradius-\labeldist+4pt}% + \def\msc@gaterefpoint{left}% + }{% ELSE, lost/found message right + \ifthenelse{\equal{\lostfound@type}{lost}}% + {% THEN + \setlength{\tmp@Xa}% start of arrow + {\msc@instrxpos{\mess@sender}}% + \setlength{\tmp@Xb}% end of arrow + {\tmp@Xa+\selfmesswidth}% + \setlength{\tmp@X}% label position + {\tmp@Xa + (\tmp@Xb - \tmp@Xa) * \real{\mess@labelplacement}}% + \setlength{\tmp@Xc}% circle position + {\tmp@Xb+\lostsymbolradius}% + }{% ELSE + \setlength{\tmp@Xb}% end of arrow + {\msc@instrxpos{\mess@sender}}% + \setlength{\tmp@Xa}% start of arrow + {\tmp@Xb+\selfmesswidth}% + \setlength{\tmp@X}% label position + {\tmp@Xb + (\tmp@Xa - \tmp@Xb) * \real{\mess@labelplacement}}% + \setlength{\tmp@Xc}% circle position + {\tmp@Xa+\lostsymbolradius}% + }% + \setlength{\tmp@Xd}% gate position + {\tmp@Xc+\lostsymbolradius+\labeldist-4pt}% + \def\msc@gaterefpoint{right}% + }% + \draw[arrowstyle, style=\mess@linestyle] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + \ifthenelse{\equal{\mess@labelposition}{t}}% + {% THEN + \ifthenelse{\equal{\lostfound@type}{lost}}% + {% + \setlength{\tmp@Y}{\tmp@Yb-\lostsymbolradius-\labeldist-4pt}% + }{% + \setlength{\tmp@Y}{\tmp@Ya-\lostsymbolradius-\labeldist-4pt}% + }% + \def\msc@labelrefpoint{}% + }{% ELSE + \ifthenelse{\equal{\mess@labelposition}{b}}% + {% THEN + \ifthenelse{\equal{\lostfound@type}{lost}}% + {% + \setlength{\tmp@Y}{\tmp@Yb-\lostsymbolradius-\labeldist-4pt}% + }{% + \setlength{\tmp@Y}{\tmp@Ya-\lostsymbolradius-\labeldist-4pt}% + }% + \def\msc@labelrefpoint{below}% + }{% ELSE + \msc@illegallostfoundlabelpositionerr{\mess@labelposition}% + }% + }% + \node[\msc@labelrefpoint] at (\tmp@X,-\tmp@Y) {\mess@labeltext};% + \edef\msc@scratch{\msc@circlefillstyle}% + \addtolength{\tmp@Y}{\lostsymbolradius+\labeldist+4pt}% + \draw[fill=\msc@scratch] (\tmp@Xc,-\tmp@Y) circle (\lostsymbolradius); + \node[\msc@gaterefpoint] at (\tmp@Xd,-\tmp@Y) {\mess@gate};% + }% +} +% +% +% \settimer has one optional argument to define the position of +% the label of a self message. +\newcommand{\settimer}[1][l]{% + \msc@settimerpos{#1}% + \@timer{set}% +} +% +% +% \timeout has one optional argument to define the position of +% the label of a self message. +\newcommand{\timeout}[1][l]{% + \msc@settimerpos{#1}% + \@timer{timeout}% +} +% +% +% \stoptimer has one optional argument to define the position of +% the label of a self message. +\newcommand{\stoptimer}[1][l]{% + \msc@settimerpos{#1}% + \@timer{stop}% +} +% +% +% \settimeout has one optional argument to define the position of +% the label of a self message. +\newcommand{\settimeout}[1][l]{% + \msc@settimerpos{#1}% + \@timerdispatcher{settimeout}% +} +% +% +% \setstoptimer has one optional argument to define the position of +% the label of a self message. +\newcommand{\setstoptimer}[1][l]{% + \msc@settimerpos{#1}% + \@timerdispatcher{setstoptimer}% +} +\def\@timerdispatcher#1#2#3{% + \@ifnextchar[{\@oargtimerdispatcher{#1}{#2}{#3}}{\@nooargtimerdispatcher{#1}{#2}{#3}}} +% +\def\@oargtimerdispatcher#1#2#3[#4]{% + \msc@setleveloffset{#4}% + \@timer{#1}{#2}{#3}% +} +% +\def\@nooargtimerdispatcher#1#2#3{% + \msc@setleveloffset{2}% default level-offset value for combined timers + \@timer{#1}{#2}{#3}% +} +% +% +% \@timer draws timers +% #1: type of the timer (set/timeout/stop) +% #2: label +% #3: nickname of the instance +\def\@timer#1#2#3{% + \expandafter\@ifundefined{mscinst#3}{% + \msc@instundefinederr{#3}}{% else, #3 is defined + \setlength{\tmp@Xa}{\msc@instxpos{#3}}% + \setlength{\tmp@Ya}{\msc@currentheight}% + \ifthenelse{\equal{\msc@timerpos}{l}}{% point left of axis + \ifthenelse{\equal{\msc@instisfat{#3}}{true}}{% + \setlength{\tmp@Xa}{\msc@instlxpos{#3}}% + }{% + \relax% + }% + \setlength{\tmp@Xb}{\tmp@Xa-\selfmesswidth}% + }{ % else point right of axis + \ifthenelse{\equal{\msc@instisfat{#3}}{true}}{% + \setlength{\tmp@Xa}{\msc@instrxpos{#3}}% + }{% + \relax% + }% + \setlength{\tmp@Xb}{\tmp@Xa+\selfmesswidth}% + }% + \ifthenelse{\equal{#1}{timeout}}{% draw an arrow + \draw[arrowstyle] (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xa,-\tmp@Ya);% + }{ % else draw a line without arrow head + \draw (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya);% + }% + \setlength{\tmp@X}{\tmp@Xb}% This looks clumsy - sm + \setlength{\tmp@Y}{\tmp@Ya}% + \msc@drawtimer{#1}{\tmp@X}{\tmp@Y}{\msc@timerpos}{#2}% + \ifthenelse{\equal{#1}{settimeout}}{% draw second part of settimeout + \setlength{\tmp@Ya}{\tmp@Y+\levelheight*\real{\msc@leveloffset}} % + \setlength{\tmp@Y}{\tmp@Y+0.75\timerwidth}% + \setlength{\tmp@Xa}{\msc@instxpos{#3}}% + \ifthenelse{\equal{\msc@timerpos}{l}}{% point left of axis + \ifthenelse{\equal{\msc@instisfat{#3}}{true}}{% + \setlength{\tmp@Xa}{\msc@instlxpos{#3}}% + }{% + \relax% + }% + }{ % else point right of axis + \ifthenelse{\equal{\msc@instisfat{#3}}{true}}{% + \setlength{\tmp@Xa}{\msc@instrxpos{#3}}% + }{% + \relax% + }% + } + \draw[arrowstyle] (\tmp@X,-\tmp@Y) -- (\tmp@X,-\tmp@Ya) -- (\tmp@Xa,-\tmp@Ya);% + }{ % else not settimeout + \ifthenelse{\equal{#1}{setstoptimer}}{% draw second part of setstoptimer + \setlength{\tmp@Ya}{\tmp@Y+\levelheight*\real{\msc@leveloffset}}% + \setlength{\tmp@Y}{\tmp@Y+0.75\timerwidth}% + \setlength{\tmp@Xb}{\msc@instxpos{#3}}% + \ifthenelse{\equal{\msc@instisfat{#3}}{true}}{% + \ifthenelse{\equal{\msc@timerpos}{l}}{% point left of axis + \setlength{\tmp@Xb}{\msc@instlxpos{#3}}% + }{% point right of axis + \setlength{\tmp@Xb}{\msc@instrxpos{#3}}% + }% + }{% not a fat instance + \relax% + } + \draw (\tmp@X,-\tmp@Y) -- (\tmp@X,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya);% + \setlength{\tmp@Y}{\tmp@Ya}% + \msc@drawtimer{stop}{\tmp@X}{\tmp@Y}{\msc@timerpos}{}% + }{ % else no second part needed + }% + }% + }% +} +% +% \msc@drawtimer draws the timer symbols +% #1: type of the timer (set/timeout/stop) +% #2: x-coordinate of center of timer +% #3: y-coordinate of center of timer +% #4: place text left (l) or right (r) +% #5: text added to the timer +\def\msc@drawtimer#1#2#3#4#5{% + \setlength{\tmp@Xa}{#2-0.5\timerwidth}% + \setlength{\tmp@Xb}{#2+0.5\timerwidth}% + \ifthenelse{\equal{#1}{stop}}{% draw reset symbol + \setlength{\tmp@Ya}{-#3+0.5\timerwidth}% + \setlength{\tmp@Yb}{-#3-0.5\timerwidth}% + \draw (\tmp@Xa,\tmp@Ya) -- (\tmp@Xb,\tmp@Yb);% + \draw (\tmp@Xb,\tmp@Ya) -- (\tmp@Xa,\tmp@Yb);% + }{% else draw set/timeout symbol + \setlength{\tmp@Ya}{-#3+0.75\timerwidth}% + \setlength{\tmp@Yb}{-#3-0.75\timerwidth}% + \draw (\tmp@Xa,\tmp@Ya) -- (\tmp@Xb,\tmp@Yb) -- (\tmp@Xa,\tmp@Yb) -- (\tmp@Xb,\tmp@Ya) -- (\tmp@Xa,\tmp@Ya);% + }% + \ifthenelse{\equal{#4}{l}}{% place label left + \setlength{\tmp@Xa}{#2-\labeldist-0.3ex}% + \setlength{\tmp@Ya}{-#3-0.5ex}% + \node[above, inner sep=0] at (\tmp@Xa,\tmp@Ya) {\makebox[0pt][r]{#5}};% + }{% else place label right + \setlength{\tmp@Xa}{#2+\labeldist+0.3ex}% + \setlength{\tmp@Ya}{-#3-0.5ex}% + \node[above, inner sep=0] at (\tmp@Xa,\tmp@Ya) {\makebox[0pt][l]{#5}};% + }% +} +% +% +% \msc@drawinstancehead draws the head of the instance +% #1: nickname of the instance +\def\msc@drawinstancehead#1{% + \setlength{\tmp@Y}{\msc@currentheight}% + \msc@drawinstanceheadsymbol{#1}{\the\tmp@Y}% +} +% +% \msc@drawinstanceheadsymbol draw the head symbol of instance #1 at y-pos #2 +\def\msc@drawinstanceheadsymbol#1#2{% + \pgfsetcolor{\msc@instcolor{#1}}% + \color{\msc@instcolor{#1}}% + \setlength{\tmp@X}{\msc@instxpos{#1}}% x-center head box + \setlength{\tmp@Y}{#2 + \msc@instheadheight{#1}*\real{0.5}}% center of head symbol + \setlength{\tmp@Xa}{\msc@instwidth{#1}*\real{-0.5} + \tmp@X}% x-upperleft head box + \setlength{\tmp@Ya}{#2}% y-upperleft head box + \setlength{\tmp@Xb}{\tmp@Xa+\msc@instwidth{#1}}% x-lowerright head box + \setlength{\tmp@Yb}{#2 + \msc@instheadheight{#1}}% y-lowerright head box + \ifthenelse{\equal{\msc@insthead}{yes}}{% + \draw[style=solid] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb) -- (\tmp@Xa,-\tmp@Yb) -- (\tmp@Xa,-\tmp@Ya);% + \setlength{\tmp@Xb}{\msc@instwidth{#1}*\real{0.8}}% + \node [minimum height= \msc@instheadheight{#1}, minimum width = \msc@instwidth{#1}, text width = \tmp@Xb, text centered] at (\tmp@X,-\tmp@Y){\msc@instinname{#1}};% + }{% else, no head symbol drawing% + } + \node [above=-4pt] at (\tmp@X,-\tmp@Ya){\raisebox{\labeldist}{\makebox[0pt][c]{\msc@instabname{#1}}}};% + \pgfsetcolor{\msc@color}% + \color{\msc@color}% +} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\def\msc@drawinstanceline#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + \ifthenelse{\equal{\msc@instypos{#1}}{undefined}}{% y-pos undefined: no line needed + }{% else + \pgfsetcolor{\msc@instcolor{#1}}% + \setlength{\tmp@Ya}{\msc@instypos{#1}}% + \setlength{\tmp@Yb}{\msc@currentheight}% + \ifthenelse{\equal{true}{\msc@instisfat{#1}}}% + {% fat instance + \setlength{\tmp@Xa}{\msc@instlxpos{#1}}% + \setlength{\tmp@Xb}{\msc@instrxpos{#1}}% + \ifthenelse{\equal{\msc@instregionstyle{#1}}{coregion}} + {% + \pgfsetcolor{\msc@regioncolor{#1}} + \draw[style=dashed] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xa,-\tmp@Yb); + \draw[style=dashed] (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb); + } + { + \ifthenelse{\equal{\msc@instregionstyle{#1}}{suspension}} + {% + \draw[style=loosely dashed] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xa,-\tmp@Yb); + \draw[style=loosely dashed] (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb); + } + {\ifthenelse{\equal{\msc@instregionstyle{#1}}{activation}} + {% + \draw[fill=lightgray] (\tmp@Xa,-\tmp@Ya) rectangle (\tmp@Xb,-\tmp@Yb); + } + {% normal region: + \draw[style=solid] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xa,-\tmp@Yb);% + \draw[style=solid] (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + } + } + } + } + {% normal instance (not fat) + \setlength{\tmp@X}{\msc@instxpos{#1}}% + \ifthenelse{\equal{\msc@instregionstyle{#1}}{suspension} \or \equal{\msc@instregionstyle{#1}}{coregion}} + {% + \pgfsetcolor{\msc@regioncolor{#1}} + \setlength{\tmp@X}{\msc@regionwidth{#1}} + \setlength{\tmp@Xa}{\msc@instxpos{#1} - 0.5\tmp@X}% + \setlength{\tmp@Xb}{\msc@instxpos{#1} + 0.5\tmp@X}% + \draw[style = loosely dashed] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xa,-\tmp@Yb);% + \draw[style = loosely dashed] (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + } + {\ifthenelse{\equal{\msc@instregionstyle{#1}}{activation}} + {% + \pgfsetcolor{\msc@regioncolor{#1}} + \setlength{\tmp@X}{\msc@regionwidth{#1}} + \setlength{\tmp@Xa}{\msc@instxpos{#1} - 0.5\tmp@X}% + \setlength{\tmp@Xb}{\msc@instxpos{#1} + 0.5\tmp@X}% + \draw[fill=lightgray] (\tmp@Xa,-\tmp@Ya) rectangle (\tmp@Xb,-\tmp@Yb); + } + {% normal region + \draw[style=\msc@instlinestyle{#1}] (\tmp@X,-\tmp@Ya) -- (\tmp@X,-\tmp@Yb); + } + } + }% + \pgfsetcolor{\msc@color}% + }% + }% +}% +% +% \msc@drawinstancefoot draws the last level and foot of the instance +% #1: nickname of the instance +\def\msc@drawinstancefoot#1{% + \setlength{\tmp@Y}{\msc@currentheight}% + \pgfsetcolor{\msc@instcolor{#1}}% + \msc@drawinstancefootsymbol{#1}{\the\tmp@Y}% + \pgfsetcolor{\msc@color}% +} +% +% \msc@drawinstancefootsymbol draws a footer symbol for instance #1 at y-pos #2. +\def\msc@drawinstancefootsymbol#1#2{% + \setlength{\tmp@Xa}{\msc@instwidth{#1}*\real{-0.5} + \msc@instxpos{#1}}% + \setlength{\tmp@Ya}{\msc@currentheight}% + \setlength{\tmp@Xb}{\tmp@Xa+\msc@instwidth{#1}}% + \setlength{\tmp@Yb}{#2 + \msc@instfootheight{#1}}% + \ifthenelse{\equal{\msc@instfoot}{yes}}{ + \edef\msc@scratch{\msc@instfootcolor{#1}}% + \draw[fill=\msc@scratch, style=\msc@instlinestyle{#1}] (\tmp@Xa,-\tmp@Ya) rectangle (\tmp@Xb,-\tmp@Yb); + }{% else, no foot symbol drawing% + } +} +% +% \nextlevel incresaes \msc@currentheight by #1 * \levelheight +% (optional) #1: a nonnegative integer number (defaults to 1) +% +\newcommand{\nextlevel}[1][1]{% + \addtolength{\msc@currentheight}{#1\levelheight}% +} +% +\def\msc@drawinstancefooters{% + \ifthenelse{\value{tmpcnt} < \value{mscinstcnt}}{% + % Only draw the instancefoot if the instypos is defined (not ``undefined'') + % This signals a previous instance stop. + \ifthenelse{\equal{\msc@instypos{\msc@instnickname{tmpcnt}}}{undefined}}{\relax}{% + \msc@drawinstanceline{\msc@instnickname{tmpcnt}}% + \msc@drawinstancefoot{\msc@instnickname{tmpcnt}}% + }% + \msc@incrcounter{tmpcnt}% + \msc@drawinstancefooters}{% else nothing + }% +}% +% +% \action puts an action symbol on the instance with nickname #2. +% The action symbol will be placed on the current level and the text #1 +% is centered inside the action symbol. The starred version adjusts the width +% and height of the action symbol +\def\action{\@ifstar{\msc@actionstar}{\msc@actionnostar}} + +\def\msc@actionstar#1#2{ + \node {\global\sbox{\tmp@box}{#1}}; + + % save values for actionwidth and actionheight + \setlength{\tmp@Xd}{\actionwidth} + \setlength{\tmp@Yd}{\actionheight} + + \setlength{\tmp@Xc}{\wd\tmp@box+\labeldist}% + \setlength{\tmp@Yc}{\ht\tmp@box + \dp\tmp@box +2\labeldist}% + + % Increase the actionwidth if necessary + \ifthenelse{\lengthtest{\actionwidth < \tmp@Xc}}{ + \setlength{\actionwidth}{\tmp@Xc} + }{} + % Increase the action height if necessary + \ifthenelse{\lengthtest{\actionheight < \tmp@Yc}}{ + \setlength{\actionheight}{\tmp@Yc} + }{} + + \msc@actionnostar{\usebox{\tmp@box}}{#2}% + + % restore values for actionwidth and actionheight + \setlength{\actionwidth}{\tmp@Xd}% + \setlength{\actionheight}{\tmp@Yd}% +} + +\def\msc@actionnostar#1#2{% + \expandafter\@ifundefined{mscinst#2}{% + \msc@instundefinederr{#2}}{% else, #2 is defined + % first, draw the instance line as far as possible + \msc@drawinstanceline{#2}% + % then, draw the action symbol + % if #2's bar width is greater than the action width, the width of this + % action will be the instnce bar width. + \ifthenelse{\lengthtest{\msc@instbarwidth{#2}<\actionwidth}}% + {\setlength{\tmp@X}{\actionwidth}}% + {\setlength{\tmp@X}{\msc@instbarwidth{#2}}}% + \setlength{\tmp@Xa}{\msc@instxpos{#2}-0.5\tmp@X}% + \setlength{\tmp@Xb}{\tmp@Xa+\tmp@X}% + \setlength{\tmp@Ya}{\msc@currentheight}% + \setlength{\tmp@Yb}{\tmp@Ya+\actionheight}% + \draw (\tmp@Xa,-\tmp@Ya) rectangle (\tmp@Xb,-\tmp@Yb);% + \setlength{\tmp@X}{\msc@instxpos{#2}}% + \setlength{\tmp@Y}{\tmp@Ya+0.5\actionheight}% + \node at (\tmp@X,-\tmp@Y){\raisebox{-.5ex}{\makebox[0pt][c]{#1}}};% + % redefine the instance's y position + \setlength{\tmp@Y}{\msc@currentheight+\actionheight}% + \msc@setinstypos{#2}{\the\tmp@Y}% + }% +} + +% \naction offers the same functionality as \action, with the +% difference that the action symbol is crossed out. + +\def\naction{\@ifstar{\msc@nactionstar}{\msc@nactionnostar}} + +\def\msc@nactionstar#1#2{ + \msc@actionstar{#1}{#2} + \draw (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + \draw (\tmp@Xa,-\tmp@Yb) -- (\tmp@Xb,-\tmp@Ya);% +} + +\def\msc@nactionnostar#1#2{ + \msc@actionnostar{#1}{#2} + \draw (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + \draw (\tmp@Xa,-\tmp@Yb) -- (\tmp@Xb,-\tmp@Ya);% +} + +% +% \stop ends the instance with nickname #1. +\def\stop{\@ifstar{\stopstar}{\stopnostar}} + +\def\stopstar#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + % first, draw the instance line as far as possible + \msc@drawinstanceline{#1}% + \setlength{\tmp@Yb}{\msc@currentheight}% + % close the instance axis if it is a fat instance + \ifthenelse{\equal{true}{\msc@instisfat{#1}}}% + {% + \setlength{\tmp@Xa}{\msc@instlxpos{#1}}% + \setlength{\tmp@Xb}{\msc@instrxpos{#1}}% + \draw (\tmp@Xa,-\tmp@Yb) -- (\tmp@Xb,-\tmp@Yb);% + }% + {% else it is not fat + }% + % then, draw instance foot symbol + \msc@drawinstancefoot{#1}% + % redefine the instance's y position + % ``undefined'' means that the instance axis will not be drawn any further + \msc@setinstypos{#1}{undefined}% + }% +} + +\def\stopnostar#1{% + \expandafter\@ifundefined{mscinst#1}{% + \msc@instundefinederr{#1}}{% else, #1 is defined + % first, draw the instance line as far as possible + \msc@drawinstanceline{#1}% + \setlength{\tmp@Yb}{\msc@currentheight}% + % close the instance axis if it is a fat instance + \ifthenelse{\equal{true}{\msc@instisfat{#1}}}% + {% + \setlength{\tmp@Xa}{\msc@instlxpos{#1}}% + \setlength{\tmp@Xb}{\msc@instrxpos{#1}}% + \draw (\tmp@Xa,-\tmp@Yb) -- (\tmp@Xb,-\tmp@Yb);% + }% + {% else it is not fat + }% + % then, draw the stop symbol + \setlength{\tmp@X}{\msc@instxpos{#1}}% + \setlength{\tmp@Xa}{\tmp@X-0.5\stopwidth}% + \setlength{\tmp@Xb}{\tmp@X+0.5\stopwidth}% + \setlength{\tmp@Ya}{\tmp@Yb+0.5\stopwidth}% + \setlength{\tmp@Yb}{\tmp@Yb-0.5\stopwidth}% + \draw (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + \draw (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xa,-\tmp@Yb);% + % redefine the instance's y position + % ``undefined'' means that the instance axis will not be drawn any further + \msc@setinstypos{#1}{undefined}% + }% +} +% +% +% \condition puts a condition symbol over the given instances. The +% starred version adjusts the width and the height of the condition symbol. +% #1: name to be put inside the condition symbol +% #2: comma-separated list of instance nicknames, such that: +% - The first instance nickname is supposed to be the leftmost +% instance of the condition +% - The last instance nickname is supposed to be the rightmost +% instance of the condition + +\def\condition{\@ifstar{\msc@conditionstar}{\msc@conditionnostar}} + +\def\msc@conditionstar#1#2{ + \node{\global\sbox{\tmp@box}{#1}}; + + % Save original values of conditionoverlap and conditionheight + \setlength{\tmp@Xc}{\conditionoverlap}% + \setlength{\tmp@Yc}{\conditionheight}% + + % Compute dynamic conditionheight + \setlength{\tmp@Yd}{\ht\tmp@box + \dp\tmp@box + 2\labeldist}% + + % Increase condition height if necessary + \ifthenelse{\lengthtest{\conditionheight < \tmp@Yd}}{ + \setlength{\conditionheight}{\tmp@Yd} + }{} + + % parse condition statement and compute new lengths + \def\msc@conditiontext{#1}% + \def\msc@firstconditioninst{undefined}% + \def\msc@lastconditioninst{undefined}% + \msc@condition{#2}% + + % Compute width of the box + \setlength{\tmp@Xa}{\msc@instxpos{\msc@firstconditioninst}} + \setlength{\tmp@Xb}{\msc@instxpos{\msc@lastconditioninst}} + \setlength{\tmp@Xb}{\tmp@Xb-\tmp@Xa} + + % Compute dynamic conditionoverlap + \setlength{\tmp@Xd}{.5\wd\tmp@box-.5\tmp@Xb} + + % Increase condition overlap if necessary + \ifthenelse{\lengthtest{\conditionoverlap < \tmp@Xd}}{ + \setlength{\conditionoverlap}{\tmp@Xd} + }{} + + \ifthenelse{\equal{\msc@instisfat{\msc@firstconditioninst}}{true}}{% + \setlength{\tmp@Xa}{\msc@instlxpos{\msc@firstconditioninst}-\conditionoverlap}% + }{% + \setlength{\tmp@Xa}{\msc@instxpos{\msc@firstconditioninst}-\conditionoverlap}% + }% + \setlength{\tmp@Ya}{\msc@currentheight}% + \ifthenelse{\equal{\msc@instisfat{\msc@lastconditioninst}}{true}}{% + \setlength{\tmp@Xb}{\msc@instrxpos{\msc@lastconditioninst}+\conditionoverlap}% + }{% + \setlength{\tmp@Xb}{\msc@instxpos{\msc@lastconditioninst}+\conditionoverlap}% + }% + \setlength{\tmp@Yb}{\tmp@Ya+\conditionheight}% + + \msc@drawcondition{\usebox{\tmp@box}}{\tmp@Xa}{\tmp@Ya}{\tmp@Xb}{\tmp@Yb}% + + % restore conditionoverlap and conditionheight + \setlength{\conditionoverlap}{\tmp@Xd}% + \setlength{\conditionheight}{\tmp@Yd}% +} + +\def\msc@conditionnostar#1#2{ + \def\msc@conditiontext{#1}% + \def\msc@firstconditioninst{undefined}% + \def\msc@lastconditioninst{undefined}% + \msc@condition{#2}% +% debugging info: +% \message{(msc: condition: \msc@firstconditioninst...\msc@lastconditioninst)}% + \ifthenelse{\equal{\msc@instisfat{\msc@firstconditioninst}}{true}}{% + \setlength{\tmp@Xa}{\msc@instlxpos{\msc@firstconditioninst}-\conditionoverlap}% + }{% + \setlength{\tmp@Xa}{\msc@instxpos{\msc@firstconditioninst}-\conditionoverlap}% + }% + \setlength{\tmp@Ya}{\msc@currentheight}% + \ifthenelse{\equal{\msc@instisfat{\msc@lastconditioninst}}{true}}{% + \setlength{\tmp@Xb}{\msc@instrxpos{\msc@lastconditioninst}+\conditionoverlap}% + }{% + \setlength{\tmp@Xb}{\msc@instxpos{\msc@lastconditioninst}+\conditionoverlap}% + }% + \setlength{\tmp@Yb}{\tmp@Ya+\conditionheight}% + \msc@drawcondition{#1}{\tmp@Xa}{\tmp@Ya}{\tmp@Xb}{\tmp@Yb}% +} +% +\def\msc@condition#1{% + \@for\msccondition@rg:=#1\do{% + \expandafter\@ifundefined{mscinst\msccondition@rg}{% + \msc@instundefinederr{\msccondition@rg}}{% else, \msccondition@rg is defined +% debugging info: +% \message{(msc: condition instance "\msccondition@rg")}% + \ifthenelse{\equal{\msc@firstconditioninst}{undefined}}{% + \edef\msc@firstconditioninst{\msccondition@rg}% + }{\ifthenelse{\lengthtest{\msc@instxpos{\msc@firstconditioninst} > \msc@instxpos{\msccondition@rg}}}{% + \edef\msc@firstconditioninst{\msccondition@rg}}{}% + }% + \ifthenelse{\equal{\msc@lastconditioninst}{undefined}}{% + \edef\msc@lastconditioninst{\msccondition@rg}% + }{\ifthenelse{\lengthtest{\msc@instxpos{\msc@lastconditioninst} < \msc@instxpos{\msccondition@rg}}}{% + \edef\msc@lastconditioninst{\msccondition@rg}}{}% + } + % now, draw the instance line as far as possible + \msc@drawinstanceline{\msccondition@rg}% + % \setlength{\tmp@X}{\msc@instxpos{\msccondition@rg}}% + % \setlength{\tmp@Ya}{\msc@instypos{\msccondition@rg}}% + % \setlength{\tmp@Yb}{\msc@currentheight+\msc@headoffset}% + % \psline[linestyle=\msc@instlinestyle{\msccondition@rg}](\tmp@X,-\tmp@Ya)(\tmp@X,-\tmp@Yb)% + % and redefine the instance's y position + \setlength{\tmp@Y}{\msc@currentheight+\conditionheight}% + \msc@setinstypos{\msccondition@rg}{\the\tmp@Y}% + }% + }% +} +% +% \msc@drawcondition draw the condition symbol +% #1: condition-text +\def\msc@drawcondition#1#2#3#4#5{% + \setlength{\tmp@Xc}{#4+ .6#5 - .6#3}% + \setlength{\tmp@Yc}{.5#3 + .5#5}% + \draw (#2,-#3) -- (#4,-#3) -- (\tmp@Xc,-\tmp@Yc) -- (#4,-#5);% + \setlength{\tmp@Xc}{#2- .6#5 + .6#3}% + \draw (#4,-#5) -- (#2,-#5) -- (\tmp@Xc,-\tmp@Yc) -- (#2,-#3);% + \setlength{\tmp@Xc}{.5#2 + .5#4}% + \setlength{\tmp@Yc}{.5#3 + .5#5}% + \node at (\tmp@Xc,-\tmp@Yc) {\raisebox{-.5ex}{\makebox[0pt][c]{#1}}};% +} + +% \ncondition offers the same functionality as +% \condition, with the difference that the condition symbol is crossed +% out. + +\def\ncondition{\@ifstar{\msc@nconditionstar}{\msc@nconditionnostar}} + +\def\msc@nconditionstar#1#2{ + \msc@conditionstar{#1}{#2} + \draw (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + \draw (\tmp@Xa,-\tmp@Yb) -- (\tmp@Xb,-\tmp@Ya);% +} + +\def\msc@nconditionnostar#1#2{ + \msc@conditionnostar{#1}{#2} + \draw (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + \draw (\tmp@Xa,-\tmp@Yb) -- (\tmp@Xb,-\tmp@Ya);% +} + +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% GATES +% \gate[hpos][vpos]{text}{nickname}[h-offset] +% \gate*[hpos][vpos]{text}{nickname}[h-offset] +% (starred version puts a dot at the position of the gate on the instance line) +% +% hpos: optional horizontal position argument l(eft) or r(ight). default: l +% vpos: optional vertical position argument t(op), c(enter) or b(ottom). default: t +% text: text to be placed at the gate +% nickname: nickname of the instance to which the gate belongs +% +\def\gate{\@ifstar{\def\msc@gatestar{defined}\msc@gateh}{\def\msc@gatestar{undefined}\msc@gateh}} +\newcommand{\msc@gateh}[1][l]{% + \def\msc@gatehpos{#1}% + \msc@gatev% +} +% +\newcommand{\msc@gatev}[3][t]{% + \msc@gate{#1}{#2}{#3}% +} +% +\def\msc@gate#1#2#3{% + \expandafter\@ifundefined{mscinst#3}{% + \msc@instundefinederr{#3}}{% else, #3 is defined + \ifthenelse{\equal{\msc@instisfat{#3}}{true}} + {\ifthenelse{\equal{\msc@gatehpos}{l}} + {\setlength{\tmp@X}{\msc@instlxpos{#3}}} + {\setlength{\tmp@X}{\msc@instrxpos{#3}}} + }% + {\setlength{\tmp@X}{\msc@instxpos{#3}}} + \ifthenelse{\equal{\msc@gatestar}{defined}}{% + \setlength{\tmp@Y}{\msc@currentheight}% + \draw[fill] (\tmp@X,-\tmp@Y) circle (\gatesymbolradius);}{}% + \ifthenelse{\equal{t}{#1}}{ + \setlength{\tmp@Y}{\msc@currentheight - \labeldist - 3pt}% + \def\msc@gatetext{{#2}}% + }{% + \ifthenelse{\equal{c}{#1}}{% + \setlength{\tmp@Y}{\msc@currentheight}% + \def\msc@gatetext{\raisebox{-.5\totalheight}{#2}}% + }{% + \setlength{\tmp@Y}{\msc@currentheight + \labeldist + 3pt}% + \def\msc@gatetext{\raisebox{-\totalheight}{#2}}% + }}% + \ifthenelse{\equal{l}{\msc@gatehpos}}{% + \addtolength{\tmp@X}{-\labeldist}% + \node at (\tmp@X,-\tmp@Y) {\makebox[0pt][r]{\msc@gatetext}};}% + {% + \addtolength{\tmp@X}{\labeldist}% + \node at (\tmp@X,-\tmp@Y) {\makebox[0pt][l]{\msc@gatetext}};% + }% + } +} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% MSC COMMENTS +% +% +% \msccomment[#1]{#2}{#3}[#4] +% #1: position l/r or a distance +% #2: text +% #3: instance nick name +% #4: leveloffset +\newcommand{\msccomment}{% + \msccomment@A% +}% +% +\newcommand{\msccomment@A}[3][l]{% + \def\commentA{#1}% position + \def\commentB{#2}% text + \def\commentC{#3}% instance + \msccomment@B% +}% +% +\newcommand{\msccomment@B}[1][0]{% + \edef\mess@leveloffset{#1}% leveloffset + \expandafter\@ifundefined{mscinst\commentC}{% check if given instance is defined + \msc@instundefinederr{\commentC}} % display undefined error + {% else, given instance ( \commentC ) is defined + \ifthenelse{\equal{\commentA}{l}}% comment is left from instance + {\setlength{\msc@commentdist}{-\msccommentdist}}% + {\ifthenelse{\equal{\commentA}{r}}% right from instance + {\setlength{\msc@commentdist}{\msccommentdist}}% + {\setlength{\msc@commentdist}{\commentA}}% instead of l/r was given distance ( in right ) from instance + } + \setlength{\tmp@Yc}{\msc@currentheight}% y-coordinate on given instance + \setlength{\tmp@Yd}{\msc@currentheight + (\levelheight * \real{\mess@leveloffset})}% y-coordinate of the middle of comment + \ifthenelse{\lengthtest{\msc@commentdist = 0pt}}% if user sets 0pt we must know on which side of instance draw the comment (default is right) + {% + \ifthenelse{\equal{\commentA}{l}}% + {% comment left from instance + \setlength{\tmp@X}{\msc@instlxpos{\commentC}} % get leftmost point on instance + \setlength{\tmp@Xa}{\tmp@X + \msc@commentdist} % set rightmost point on comment + \ifthenelse{\lengthtest{\msccommentwidth = 0pt}} + {% set comment width automatic + \node (c) [rectangle,anchor = east, align=right] at (\tmp@Xa,-\tmp@Yd) {\commentB}; % create comment body with text + }% + {% comment width is given + \node (c) [rectangle,anchor = east, align=right, text width=\msccommentwidth] at (\tmp@Xa,-\tmp@Yd) {\commentB}; % create comment body with text + }% + \draw[style=dashed] (\tmp@X,-\tmp@Yc) -- (c.east); % attach comment to instance + %\draw (c.north west) -- (c.north east) -- (c.south east) -- (c.south west); % draw box around comment body with one side open + }% + {% comment right from instance + \setlength{\tmp@X}{\msc@instrxpos{\commentC}} + \setlength{\tmp@Xa}{\tmp@X + \msc@commentdist} + \ifthenelse{\lengthtest{\msccommentwidth = 0pt}} + {% set comment width automatic + \node (c) [rectangle,anchor = west, align=left] at (\tmp@Xa,-\tmp@Yd) {\commentB}; % create comment body with text + }% + {% comment width is given + \node (c) [rectangle,anchor = west, align=left, text width=\msccommentwidth] at (\tmp@Xa,-\tmp@Yd) {\commentB}; % create comment body with text + }% + \draw[style=dashed] (\tmp@X,-\tmp@Yc) -- (c.west); + % \draw (c.south east) -- (c.south west) -- (c.north west) -- (c.north east); + }% + }% + {% + \ifthenelse{\lengthtest{\msc@commentdist < 0pt}}% + {% comment left from instance + \setlength{\tmp@X}{\msc@instlxpos{\commentC}} + \setlength{\tmp@Xa}{\tmp@X + \msc@commentdist} + \ifthenelse{\lengthtest{\msccommentwidth = 0pt}} + {% set comment width automatic + \node (c) [rectangle,anchor = east, align=right] at (\tmp@Xa,-\tmp@Yd) {\commentB}; % create comment body with text + }% + {% comment width is given + \node (c) [rectangle,anchor = east, align=right, text width=\msccommentwidth] at (\tmp@Xa,-\tmp@Yd) {\commentB}; % create comment body with text + }% + \draw[style=dashed] (\tmp@X,-\tmp@Yc) -- (c.east); + %\draw (c.north west) -- (c.north east) -- (c.south east) -- (c.south west); + }% + {% comment right from instance + \setlength{\tmp@X}{\msc@instrxpos{\commentC}} + \setlength{\tmp@Xa}{\tmp@X + \msc@commentdist} + \ifthenelse{\lengthtest{\msccommentwidth = 0pt}} + {% set comment width automatic + \node (c) [rectangle,anchor = west, align=left] at (\tmp@Xa,-\tmp@Yd) {\commentB}; % create comment body with text + }% + {% comment width is given + \node (c) [rectangle,anchor = west, align=left, text width=\msccommentwidth] at (\tmp@Xa,-\tmp@Yd) {\commentB}; % create comment body with text + }% + \draw[style=dashed] (\tmp@X,-\tmp@Yc) -- (c.west); + %\draw (c.south east) -- (c.south west) -- (c.north west) -- (c.north east); + }% + }% + + }% +} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% MSC MARKS +% +% \mark[#1]{#2}{#3} +% #1: placement: tl,bl,tr,br +% #2: text +% #3: instance nick name +% +\newcommand{\mscmark}[3][tl]{% + \expandafter\@ifundefined{mscinst#3}{% + \msc@instundefinederr{#3}} + {% else, #3 is defined + \node{\global\sbox{\tmp@box}{\raisebox{\depth}[\totalheight][0pt]{#2}}};% + \ifthenelse{\equal{#1}{tl}} + {%tl: + \setlength{\tmp@X}{\msc@instlxpos{#3}} + \setlength{\tmp@Xa}{\tmp@X - \selfmesswidth} + \setlength{\tmp@Xb}{\tmp@Xa - \wd\tmp@box - 2\labeldist} + \setlength{\tmp@Y}{\msc@currentheight} + \setlength{\tmp@Ya}{\msc@currentheight - \markdist} + \draw[style=dashed] (\tmp@X,-\tmp@Y) -- (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya);% + \setlength{\tmp@Xb}{\tmp@Xa - \labeldist - .5\wd\tmp@box} + \addtolength{\tmp@Ya}{-\labeldist} + \node[above, inner sep=0] at (\tmp@Xb,-\tmp@Ya) {\usebox{\tmp@box}};% + }{ + \ifthenelse{\equal{#1}{bl}} + {%bl: + \setlength{\tmp@X}{\msc@instlxpos{#3}} + \setlength{\tmp@Xa}{\tmp@X - \selfmesswidth} + \setlength{\tmp@Xb}{\tmp@Xa - \wd\tmp@box - 2\labeldist} + \setlength{\tmp@Y}{\msc@currentheight} + \setlength{\tmp@Ya}{\msc@currentheight + \markdist} + \draw[style=dashed] (\tmp@X,-\tmp@Y) -- (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya);% + \setlength{\tmp@Xb}{\tmp@Xa - \labeldist - .5\wd\tmp@box} + \addtolength{\tmp@Ya}{-\labeldist} + \node[above, inner sep=0] at (\tmp@Xb,-\tmp@Ya) {\usebox{\tmp@box}};% + }{ + \ifthenelse{\equal{#1}{tr}} + {%tr: + \setlength{\tmp@X}{\msc@instrxpos{#3}} + \setlength{\tmp@Xa}{\tmp@X + \selfmesswidth} + \setlength{\tmp@Xb}{\tmp@Xa + \wd\tmp@box + 2\labeldist} + \setlength{\tmp@Y}{\msc@currentheight} + \setlength{\tmp@Ya}{\msc@currentheight - \markdist} + \draw[style=dashed] (\tmp@X,-\tmp@Y) -- (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya);% + \setlength{\tmp@Xb}{\tmp@Xa + \labeldist + .5\wd\tmp@box} + \addtolength{\tmp@Ya}{-\labeldist} + \node[above, inner sep=0] at (\tmp@Xb,-\tmp@Ya) {\usebox{\tmp@box}};% + }{ + \ifthenelse{\equal{#1}{br}} + {%br: + \setlength{\tmp@X}{\msc@instrxpos{#3}} + \setlength{\tmp@Xa}{\tmp@X + \selfmesswidth} + \setlength{\tmp@Xb}{\tmp@Xa + \wd\tmp@box + 2\labeldist} + \setlength{\tmp@Y}{\msc@currentheight} + \setlength{\tmp@Ya}{\msc@currentheight + \markdist} + \draw[style=dashed] (\tmp@X,-\tmp@Y) -- (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya);% + \setlength{\tmp@Xb}{\tmp@Xa + \labeldist + .5\wd\tmp@box} + \addtolength{\tmp@Ya}{-\labeldist} + \node[above, inner sep=0] at (\tmp@Xb,-\tmp@Ya) {\usebox{\tmp@box}};% + }{ + \msc@illegalmarkplacement{#1} + }}}}} +} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% MSC MEASURES +% +% +\newlength{\msc@measuredist}% internal length for horizontal measure distance +% \measure[*][#1]{#2}{#3}[#4]{#5}[#6][#7] +% *: the starred version puts the top measure mark above and the bottom measure mark +% below the measure position. +% #1: placement: l (left) r (right), or distance (negative or positive) to closest of #3 or #4 +% #2: name +% #3: instance nick name +% #4: if is direted +% #5: instance nick name +% #6: (vertical) offset +% #7: instance offset +\newcommand{\measure}{% + \@ifstar{\def\msc@innermeasure{false}\msc@measureargs} + {\def\msc@innermeasure{true}\msc@measureargs}% +} +% +\newcommand{\msc@measureargs}[3][l]{% + \def\msc@i{#1}% + \def\msc@ii{#2}% + \def\msc@iii{#3}% + \msc@measuredirected% +} + +\newcommand{\msc@measuredirected}[2][no]{% + \def\msc@isDirected{#1}% + \def\msc@iv{#2}% + \msc@measureoffset% +} + +\newcommand{\msc@measureoffset}[1][1]{% + \def\msc@mscv{#1}% + \msc@measurepadding% +} + +\newcommand{\msc@measurepadding}[1][0mm]{% + \def\mess@instanceoffset{#1}% + \ifthenelse{\equal{\msc@isDirected}{no}}% + {%normal measure + \msc@measure{\msc@i}{\msc@ii}{\msc@iii}{\msc@iv}{\msc@mscv}% + }{%directed measure + \msc@directedmeasure{\msc@i}{\msc@ii}{\msc@iii}{\msc@iv}{\msc@mscv}% + } +} + +\newcommand{\msc@measure}[5]{% + \ifthenelse{\equal{#1}{l}} + {\setlength{\msc@measuredist}{-\selfmesswidth}} + {\ifthenelse{\equal{#1}{r}} + {\setlength{\msc@measuredist}{\selfmesswidth}} + {\setlength{\msc@measuredist}{#1}}} + % + \setlength{\tmp@Ya}{\msc@currentheight} + \setlength{\tmp@Yb}{\tmp@Ya + #5\levelheight} + \setlength{\tmp@Y}{.5\tmp@Ya + .5\tmp@Yb} + \ifthenelse{\lengthtest{\msc@instxpos{#3} < \msc@instxpos{#4}}} + {% + \ifthenelse{\lengthtest{\msc@measuredist < 0pt}} + {% left from instances + \setlength{\tmp@Xa}{\msc@instlxpos{#3}} + \setlength{\tmp@Xb}{\msc@instlxpos{#4}-\mess@instanceoffset} + \setlength{\tmp@X}{\tmp@Xa + \msc@measuredist} + } + {% right from instances + \setlength{\tmp@Xa}{\msc@instrxpos{#3}} + \setlength{\tmp@Xb}{\msc@instrxpos{#4}+\mess@instanceoffset} + \setlength{\tmp@X}{\tmp@Xb + \msc@measuredist} + } + } + {% + \ifthenelse{\lengthtest{\msc@measuredist < 0pt}} + {% left from instances + \setlength{\tmp@Xa}{\msc@instlxpos{#3}} + \setlength{\tmp@Xb}{\msc@instlxpos{#4}+\mess@instanceoffset} + \setlength{\tmp@X}{\tmp@Xb + \msc@measuredist} + } + {% right from instances + \setlength{\tmp@Xa}{\msc@instrxpos{#3}} + \setlength{\tmp@Xb}{\msc@instrxpos{#4}-\mess@instanceoffset} + \setlength{\tmp@X}{\tmp@Xa + \msc@measuredist} + } + } + \draw[style=dashed] (\tmp@Xa,-\tmp@Ya)--(\tmp@X,-\tmp@Ya)--(\tmp@X,-\tmp@Yb)--(\tmp@Xb,-\tmp@Yb);% + \ifthenelse{\lengthtest{\msc@measuredist < 0pt}} + {% left from instances + \addtolength{\tmp@X}{-\labeldist} + \node[left, inner sep=0] at (\tmp@X,-\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}};% + \addtolength{\tmp@X}{\labeldist} + } + {% right from instances + \addtolength{\tmp@X}{\labeldist} + \node[right, inner sep=0] at (\tmp@X,-\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}};% + \addtolength{\tmp@X}{-\labeldist} + } + \ifthenelse{\equal{\msc@innermeasure}{true}} + {% + \msc@measuresymbolup{\tmp@X}{\tmp@Ya} + \msc@measuresymboldown{\tmp@X}{\tmp@Yb} + } + {% + \msc@measuresymboldown{\tmp@X}{\tmp@Ya} + \msc@measuresymbolup{\tmp@X}{\tmp@Yb} + } +} + +\newcommand{\msc@directedmeasure}[5]{% + \ifthenelse{\equal{#1}{l}} + {\setlength{\msc@measuredist}{-\selfmesswidth}} + {\ifthenelse{\equal{#1}{r}} + {\setlength{\msc@measuredist}{\selfmesswidth}} + {\setlength{\msc@measuredist}{#1}}} + % + \setlength{\tmp@Ya}{\msc@currentheight} + \setlength{\tmp@Yb}{\tmp@Ya + #5\levelheight} + \setlength{\tmp@Y}{.5\tmp@Ya + .5\tmp@Yb} + \ifthenelse{\lengthtest{\msc@instxpos{#3} < \msc@instxpos{#4}}} + {% + \ifthenelse{\lengthtest{\msc@measuredist < 0pt}} + {% left from instances + \setlength{\tmp@Xa}{\msc@instlxpos{#3}} + \setlength{\tmp@Xb}{\msc@instlxpos{#4}-\mess@instanceoffset} + \setlength{\tmp@X}{\tmp@Xa + \msc@measuredist} + } + {% right from instances + \setlength{\tmp@Xa}{\msc@instrxpos{#3}} + \setlength{\tmp@Xb}{\msc@instrxpos{#4}+\mess@instanceoffset} + \setlength{\tmp@X}{\tmp@Xb + \msc@measuredist} + } + } + {% + \ifthenelse{\lengthtest{\msc@measuredist < 0pt}} + {% left from instances + \setlength{\tmp@Xa}{\msc@instlxpos{#3}} + \setlength{\tmp@Xb}{\msc@instlxpos{#4}-\mess@instanceoffset} + \setlength{\tmp@X}{\tmp@Xb + \msc@measuredist} + } + {% right from instances + \setlength{\tmp@Xa}{\msc@instrxpos{#3}} + \setlength{\tmp@Xb}{\msc@instrxpos{#4}+\mess@instanceoffset} + \setlength{\tmp@X}{\tmp@Xa + \msc@measuredist} + } + } + \draw[style=dashed] (\tmp@Xa,-\tmp@Ya)--(\tmp@X,-\tmp@Ya)--(\tmp@X,-\tmp@Yb)--(\tmp@Xb,-\tmp@Yb);% + \ifthenelse{\lengthtest{\msc@measuredist < 0pt}} + {% left from instances + \addtolength{\tmp@X}{-\labeldist} + \node[left, inner sep=0] at (\tmp@X,-\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}};% + \addtolength{\tmp@X}{\labeldist} + } + {% right from instances + \addtolength{\tmp@X}{\labeldist} + \node[right, inner sep=0] at (\tmp@X,-\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}};% + \addtolength{\tmp@X}{-\labeldist} + } + \ifthenelse{\lengthtest{\tmp@Ya > \tmp@Yb}} + { + \msc@measuresymbolup{\tmp@X}{\tmp@Yb} + }{ + \msc@measuresymboldown{\tmp@X}{\tmp@Yb} + } +} +% +% +% \measurestart[*][#1]{#2}{#3}{#4} +% *: unstarred/starred version draws downward/upward triangle +% #1: placement: l (left) r (right), or distance (negative or positive) to #3 +% #2: name +% #3: instance nick name +% #4: gate name +\newcommand{\measurestart}{% + \@ifstar{\def\msc@innermeasure{false}\msc@measurestartargs} + {\def\msc@innermeasure{true}\msc@measurestartargs} +} +% +% +\newcommand{\msc@measurestartargs}[4][l]{% + \def\msc@i{#1}% + \def\msc@ii{#2}% + \def\msc@iii{#3}% + \def\msc@iv{#4}% + \msc@measurestartoffset% +} + +\newcommand{\msc@measurestartoffset}[1][2]{% + \msc@measurestart{\msc@i}{\msc@ii}{\msc@iii}{\msc@iv}{#1}% +} +% +\newcommand{\msc@measurestart}[5]{% + \ifthenelse{\equal{#1}{l}} + {\setlength{\msc@measuredist}{-\measuredist}} + {\ifthenelse{\equal{#1}{r}} + {\setlength{\msc@measuredist}{\measuredist}} + {\setlength{\msc@measuredist}{#1}}} + \setlength{\tmp@Ya}{\msc@currentheight} + \ifthenelse{\lengthtest{\msc@measuredist < 0pt}} + {% left from instance + \setlength{\tmp@Xa}{\msc@instlxpos{#3}} + \setlength{\tmp@Xb}{\tmp@Xa + \msc@measuredist} + \setlength{\tmp@Yb}{\tmp@Ya + #5\levelheight} + \setlength{\tmp@X}{\tmp@Xb - \labeldist - 0.5\measuresymbolwidth} + \setlength{\tmp@Y}{.5\tmp@Ya + .5\tmp@Yb} + \node[left, inner sep=0] at (\tmp@X,-\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}};% + \setlength{\tmp@Y}{\tmp@Yb + \labeldist} + \node[left, inner sep=0] at (\tmp@X,-\tmp@Yb) {\raisebox{\depth}[\totalheight][0pt]{#4}};% + } + {% right from instance + \setlength{\tmp@Xa}{\msc@instrxpos{#3}} + \setlength{\tmp@Xb}{\tmp@Xa + \msc@measuredist} + \setlength{\tmp@Yb}{\tmp@Ya + #5\levelheight} + \setlength{\tmp@X}{\tmp@Xb + \labeldist + 0.5\measuresymbolwidth} + \setlength{\tmp@Y}{.5\tmp@Ya + .5\tmp@Yb} + \node[right, inner sep=0] at (\tmp@X,-\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}};% + \setlength{\tmp@Y}{\tmp@Yb + \labeldist} + \node[right, inner sep=0] at (\tmp@X,-\tmp@Yb) {\raisebox{\depth}[\totalheight][0pt]{#4}};% + } + \draw[style=dashed] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + \ifthenelse{\equal{\msc@innermeasure}{true}} + {\msc@measuresymbolup{\tmp@Xb}{\tmp@Ya}} + {\msc@measuresymboldown{\tmp@Xb}{\tmp@Ya}} + \draw[fill=white] (\tmp@Xb,-\tmp@Yb) circle (.5\measuresymbolwidth); + } +% +% \measureend[*][#1]{#2}{#3}{#4} +% *: unstarred/starred version draws upward/downward triangle +% #1: placement: l (left) r (right), or distance (negative or positive) to #3 +% #2: name +% #3: instance nick name +% #4: gate name +\newcommand{\measureend}{% + \@ifstar{\def\msc@innermeasure{false}\msc@measureendargs}% + {\def\msc@innermeasure{true}\msc@measureendargs}% +} +% +\newcommand{\msc@measureendargs}[4][l]{% + \def\msc@i{#1}% + \def\msc@ii{#2}% + \def\msc@iii{#3}% + \def\msc@iv{#4}% + \msc@measureendoffset% +} +% +\newcommand{\msc@measureendoffset}[1][2]{% + \msc@measureend{\msc@i}{\msc@ii}{\msc@iii}{\msc@iv}{#1}% +} +% +\newcommand{\msc@measureend}[5]{% + \ifthenelse{\equal{#1}{l}} + {\setlength{\msc@measuredist}{-\measuredist}} + {\ifthenelse{\equal{#1}{r}} + {\setlength{\msc@measuredist}{\measuredist}} + {\setlength{\msc@measuredist}{#1}}} + \setlength{\tmp@Ya}{\msc@currentheight} + \ifthenelse{\lengthtest{\msc@measuredist < 0pt}} + {% left from instance + \setlength{\tmp@Xa}{\msc@instlxpos{#3}} + \setlength{\tmp@Xb}{\tmp@Xa + \msc@measuredist} + \setlength{\tmp@Yb}{\tmp@Ya - #5\levelheight} + \setlength{\tmp@X}{\tmp@Xb - \labeldist - 0.5\measuresymbolwidth} + \setlength{\tmp@Y}{.5\tmp@Ya + .5\tmp@Yb} + \node[left, inner sep=0] at (\tmp@X,-\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}}; + \setlength{\tmp@Y}{\tmp@Yb - \labeldist} + \node[left, inner sep=0] at (\tmp@X,-\tmp@Yb) {\raisebox{\depth}[\totalheight][0pt]{#4}}; + } + {% right from instance + \setlength{\tmp@Xa}{\msc@instrxpos{#3}} + \setlength{\tmp@Xb}{\tmp@Xa + \msc@measuredist} + \setlength{\tmp@Yb}{\tmp@Ya - #5\levelheight} + \setlength{\tmp@X}{\tmp@Xb + \labeldist + 0.5\measuresymbolwidth} + \setlength{\tmp@Y}{.5\tmp@Ya + .5\tmp@Yb} + \node[right, inner sep=0] at (\tmp@X,-\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}};% + \setlength{\tmp@Y}{\tmp@Yb - \labeldist} + \node[right, inner sep=0] at (\tmp@X,-\tmp@Yb) {\raisebox{\depth}[\totalheight][0pt]{#4}};% + } + \draw[style=dashed] (\tmp@Xa,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Ya) -- (\tmp@Xb,-\tmp@Yb);% + \ifthenelse{\equal{\msc@innermeasure}{true}} + {\msc@measuresymboldown{\tmp@Xb}{\tmp@Ya}} + {\msc@measuresymbolup{\tmp@Xb}{\tmp@Ya}} + \draw[fill=white] (\tmp@Xb,-\tmp@Yb) circle (.5\measuresymbolwidth);% + } +% +% measure symbols +% +\def\msc@measuresymbolup#1#2{% + % sin(pi/3) =~ 0.866025403784 + % draw an upward triangle with 60-degree (pi/3) angles and base at (#1,#2) + \draw[fill=white] (#1, -#2) -- (#1 + .5\measuresymbolwidth, -#2 - .866025403784\measuresymbolwidth) -- (#1 - .5\measuresymbolwidth, -#2 - .866025403784\measuresymbolwidth) -- cycle;% +} +% +\def\msc@measuresymboldown#1#2{% + % sin(pi/3) =~ 0.866025403784 + % draw a downward triangle with 60-degree (pi/3) angles and base at (#1,#2) + \draw[fill=white] (#1, -#2) -- (#1 + .5\measuresymbolwidth, -#2 + .866025403784\measuresymbolwidth) -- (#1 - .5\measuresymbolwidth, -#2 + .866025403784\measuresymbolwidth) -- cycle;% +} + +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% \drawmscframe draws a frame of the right size around the msc +% This command also set the value of \msc@totalsizebox +\def\msc@drawframe{% + \ifthenelse{\equal{\msc@frame}{yes}}{% + \draw (0,0) rectangle (\msc@currentwidth,-\msc@currentheight); + }{% no frame drawing + }% +} +% +% \msckeyword is the keyword representation of msc +\def\msckeyword{} +\def\msckeywordstyle#1{\textbf{#1}} +% +% This keyword can be changed by the \setmsckeyword command (or by \renewcommand{\msckeyword}{...}): +\newcommand{\setmsckeyword}[1]{\def\msckeyword{#1}} +\newcommand{\setmsckeywordstyle}[1]{\def\msckeywordstyle{#1}}% +% +% Commands to switch internal options that control the drawing of header and footer symbols +\newcommand{\drawinsthead}[1]{\def\msc@insthead{#1}}% +\drawinsthead{yes}% +\newcommand{\drawinstfoot}[1]{\def\msc@instfoot{#1}}% +\drawinstfoot{yes}% +% A similar command to control drawing of the msc-frame +\newcommand{\drawframe}[1]{\def\msc@frame{#1}}% +\drawframe{yes}% +% +% +\def\msc@grid{no}% +\newcommand{\showgrid}{\def\msc@grid{yes}} +\newcommand{\nogrid}{\def\msc@grid{no}} + + +\def\msc@settitle{% +\MSC@settitle{msc}% + {0\mscunit}% + {-\msc@totalheight}% + {\msc@totalwidth}% + {0\mscunit}% + {\msc@titlejustification}% + {\msckeywordstyle{\msckeyword}{} \msc@title}% +} + +% +% \msc@title stores the title given in \begin{msc}{title} +\def\msc@title{}% +% +% \msc@titlejustification says how the title should be justified +% Justification is relative to the total width of the msc +% l: left (default) +% c: centered +% r: right +% +\newsavebox{\mscbox}% +% +% the msc-environment +\newenvironment{msc}[2][l]{% +%\message{(\msckeyword: '#2'}% +\def\msc@titlejustification{#1}% +\def\msc@title{#2}% +\setcounter{mscinstcnt}{0}% +\setlength{\msc@currentheight}{\topheaddist}% +\addtolength{\msc@currentheight}{\instheadheight}% +\addtolength{\msc@currentheight}{\firstlevelheight}% +\setlength{\msc@currentwidth}{0pt}% +% define the artificial left and right environment instances +\msc@declinst{envleft}{}{}{\the\instbarwidth}% +\msc@setinstxpos{envleft}{0pt}% +\msc@declinst{envright}{}{}{\the\instbarwidth}% +\msc@setinstxpos{envright}{\envinstdist}% +\begin{tikzpicture}[transform shape, scale = \mscscalefactor] +}{% + \addtolength{\msc@currentheight}{\lastlevelheight}% + \setcounter{tmpcnt}{2}% + \msc@drawinstancefooters% +% If there is at least one instance, the current width is +% set to the xpos of the NEXT msc instance. There is at least one instance, +% if mscinstcnt >= 2. So, in that case, we have to +% substract one \instdist from the current width. +% +%\ifthenelse{\value{mscinstcnt}<2}{% no user defined instances, so, relax +% \relax% +%}{% mscinstcnt >= 2 +% \addtolength{\msc@currentwidth}{-\instdist}% +%}% +% Now we compute the final current width: one extra \envinstdist: +\setlength{\msc@currentwidth}{\msc@instxpos{envright}}% +\addtolength{\msc@currentheight}{\instfootheight+\bottomfootdist}% +\msc@drawframe% +\global\msc@totalwidth=\msc@currentwidth% +\global\msc@totalheight=\msc@currentheight% +\ifthenelse{\equal{\msc@grid}{yes}}{% +\draw[style=dotted, step=1cm] (0,-\msc@currentheight) grid (\msc@currentwidth,0);% + +% xticks and yticks +\newcount\tmpcnt% + +\tmpcnt = \msc@currentwidth% +\divide \tmpcnt by 1864679%from sp to cm +\foreach \x in {0,...,\tmpcnt} {% + \node at (\x, 0) [above right] {\x}; +}% + +\tmpcnt = \msc@currentheight% +\divide \tmpcnt by 1864679%from sp to cm +\foreach \y in {0,...,\tmpcnt} {% + \node at (0,-\y) [below left] {\y}; +}% + +}{\relax}% +\msc@settitle% +\end{tikzpicture}% +% Debug info: +%\typeout{msc size: \the\msc@totalwidth x\the\msc@totalheight}% +% the \mscbox now contains a box of 0x0, however the actual width and +% height are stored in \msc@total{width,height}. We use these lengths +% to adjust the width and height of the \mscbox +\wd\mscbox=\msc@totalwidth% +\ht\mscbox=\msc@totalheight% +\dp\mscbox=0pt% +% Now the \mscbox can be scaled (by \mscscalefactor) and `printed': +{% DEBUG: use this \fbox stuf to check the bounding box + \setlength{\fboxrule}{0.01pt}% + \setlength{\fboxsep}{1pt}% +}% +\message{)}% +}% +% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\newcommand{\MSC@settitle}[7]{% + % #1: diagram type (msc, mscdoc, hmsc) + % #2: llx + % #3: lly + % #4: urx + % #5: ury + % #6: justification (l, c, r) + % #7: typeset title + \setlength{\tmp@X}{#4 - #2 - 2\leftnamedist}% + \ifthenelse{\equal{#6}{l}}% + {% + \def\MSC@dosettitle{\parbox[t]{\tmp@X}{\raggedright #7}}% + }% + {\ifthenelse{\equal{#6}{c}}% + {% + \def\MSC@dosettitle{\parbox[t]{\tmp@X}{\centering #7}}% + }% + {\ifthenelse{\equal{#6}{r}}% + {% + \def\MSC@dosettitle{\parbox[t]{\tmp@X}{\raggedleft #7}}% + }% + {\msc@illegaltitleplacement{#6}}% + }% + }% + \setlength{\tmp@Y}{#5 - \topnamedist}% + \setlength{\tmp@Xb}{#2 + \leftnamedist}% + \node [below right=-4pt] at (\tmp@Xb,\tmp@Y) {\MSC@dosettitle};% +} + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% MSC documents +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \mscdockeyword is the keyword representation of msc +\def\mscdockeyword{mscdoc} +\def\mscdockeywordstyle#1{\textbf{#1}} +% +% This keyword can be changed by the \setmscdockeyword command (or by \renewcommand{\mscdockeyword}{...}): +\newcommand{\setmscdockeyword}[1]{\def\mscdockeyword{#1}} +\newcommand{\setmscdockeywordstyle}[1]{\def\mscdockeywordstyle{#1}}% + +\newcommand{\mscdoc@settitle}{% + \MSC@settitle{mscdoc}% + {\mscdoc@llx}% + {\mscdoc@lly}% + {\mscdoc@urx}% + {\mscdoc@ury}% + {\mscdoc@titlejustification}% + {\mscdockeywordstyle{\mscdockeyword}{} \mscdoc@title}% +} + +\newenvironment{mscdoc}[2][l]% +{% + \message{( \mscdockeyword: '#2'}% + \def\mscdoc@titlejustification{#1}% + \def\mscdoc@title{#2}% + \def\reference##1(##2,##3){% + \setlength{\tmp@X}{\mscdocreferencewidth}% + \setlength{\tmp@Y}{\mscdocreferenceheight}% + \def\txt{\vbox to \tmp@Y{\vss\hbox to \tmp@X{\hss{}##1\hss}\vss}}% +% \rput(##2\mscunit,##3\mscunit){\psframebox[% +% framearc=0.25,% +% framesep=0pt,% +% border=0pt% +% ]{\txt}}}% + \node[draw, inner sep=0, rounded corners=3pt] at (##2\mscunit,##3\mscunit) {\txt};}% + \def\separator##1{% + \draw[style=dashed] (\mscdoc@llx,##1) -- (\mscdoc@urx,##1);% + }% + \def\mscdoc@sizespec(##1,##2)(##3,##4)% + {% + \def\mscdoc@llx{##1\mscunit}% + \def\mscdoc@lly{##2\mscunit}% + \def\mscdoc@urx{##3\mscunit}% + \def\mscdoc@ury{##4\mscunit}% +\begin{lrbox}{\mscbox}% + \begin{tikzpicture}(\mscdoc@llx,\mscdoc@lly)(\mscdoc@urx,\mscdoc@ury) + \ifthenelse{\equal{\msc@grid}{yes}}{% +\draw[style=dotted, step=1cm] (\mscdoc@llx,\mscdoc@lly) grid (\mscdoc@urx,\mscdoc@ury);% + +\newlength{\mscdoc@width}% +\newlength{\mscdoc@height}% +\setlength{\mscdoc@width}{\mscdoc@urx-\mscdoc@llx}% +\setlength{\mscdoc@height}{\mscdoc@ury-\mscdoc@lly}% + +% xticks and yticks +\newcount\tmpcnt% + +\tmpcnt = \mscdoc@width% +\divide \tmpcnt by 1864679%from sp to cm +\foreach \x in {0,...,\tmpcnt} {% + \node at (\x, 0) [below right] {\x}; +}% + +\tmpcnt = \mscdoc@height% +\divide \tmpcnt by 1864679%from sp to cm +\foreach \y in {0,...,\tmpcnt} {% + \node at (0,\y) [above left] {\y}; +}% + }{\relax}% + \ifthenelse{\equal{\msc@frame}{yes}}{% + \draw (\mscdoc@llx,\mscdoc@lly) rectangle (\mscdoc@urx,\mscdoc@ury);% + }{\relax}% + \mscdoc@settitle% + }% + \mscdoc@sizespec% +}% +{% + \end{tikzpicture} +\end{lrbox}% +{% DEBUG: use this \fbox stuf to check the bounding box + \setlength{\fboxrule}{0.01pt}% + \setlength{\fboxsep}{1pt}% + \color{white}\fbox{% + \usebox{\mscbox}% + }% +}% + \message{)}% +} + +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% HMSC +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\newcommand{\hmsckeyword}{hmsc} +\newcommand{\hmsckeywordstyle}[1]{\textbf{#1}} + +% This keyword can be changed by the \sethmsckeyword command (or by \renewcommand{\hmsckeyword}{...}): +\newcommand{\sethmsckeyword}[1]{\def\hmsckeyword{#1}} +\newcommand{\sethmsckeywordstyle}[1]{\def\hmsckeywordstyle{#1}}% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\newif\if@ncsegline + + +% +% User command to draw a segmented line between two nodes (buggy). +% +% NOTE: this implementation is not complete yet. The optional arrows argument +% only makes sense for forward arrows (and even then in a limited way). +% usage: \ncsegline[settings]{arrows}{#1}[(x0,y0)...(xn,xy)]{#2} +% settings (optional): pstricks settings for lines +% arrows(optional): pstricks-style arrow defintions +% #1: start node +% (x0,y0)...(xn,yn) (optional): sequence of intermediate points +% #2: end node +\def\ncsegline{% + \@ifstar{\def\@nclinecommand{\ncline*}\@ncseglinei}{\def\@nclinecommand{\ncline}\@ncseglinei}% +} + +\def\ncseglinecheck@arrow#1#2{% + \ncseglinecheck@@arrow#2-\@nil + \if@ncsegline% +% \message{(arrow: `#2')}% + \edef\@ncseglinearrow{{#2}}% + \def\next{#1}% + \else% +% \message{(no arrow `#2')}% + \edef\@ncseglinearrow{{-}}% + \def\next{#1{#2}}% + \fi% + \next% +} + +\def\ncseglinecheck@@arrow#1-#2\@nil{% +\ifx\@nil#2\@nil\@ncseglinefalse\else\@ncseglinetrue\fi} + +\def\@ncseglinei{% + \@ifnextchar[{\@ncseglineReadSettings}{\def\@nclinesettings{[]}\ncseglinecheck@arrow{\@ncseglineii}}%] +} + +\def\@ncseglineReadSettings[#1]{% + \def\@nclinesettings{[#1]}% + \ncseglinecheck@arrow{\@ncseglineii}% +} + +\def\@ncseglineii#1{% + \def\@ncsegargA{#1}% + \@ifnextchar[{\@ncseglineiii}{\@ncseglineiv}% +} + +\def\@ncseglineiii[#1]#2{% + \@ncseglineA#1(\relax,\relax)% + \def\@ncsegargB{#2}% + \@ncseglinedraw% +} + +\def\@ncseglineiv#1{% + \def\@ncsegargB{#1}% + \@ncseglinedraw% +} + +\def\@ncseglinedraw{% + \edef\@ncseglineattrs{\@nclinesettings\@ncseglinearrow}% + \expandafter\@nclinecommand\@ncseglineattrs{\@ncsegargA}{\@ncsegargB}% +} + +\def\@ncseglineA(#1,#2){% + \ifx#1\relax% + \def\next{\relax}% + \else% +% \message{(line seg)}% + \pnode(#1,#2){#1#2}% + \expandafter\@nclinecommand\@nclinesettings{-}{\@ncsegargA}{#1#2}% + \edef\@ncsegargA{#1#2}% + \def\next{\@ncseglineA}% + \fi + \next% +} + +% User command to draw hmsc start symbols +% usage: \hmscstartsymbol{#1}(#2,#3) +% #1: nickname +% #2: x-coordinate +% #3: y-coordinate +% +% +% sin(pi/3) =~ 0.866025403784 +% +\def\hmscstartsymbol#1(#2,#3){% + %\message{(hmsc start symbol: #1)}% + \setlength{\tmp@Xa}{#2\mscunit}% + \setlength{\tmp@Ya}{#3\mscunit}% + \setlength{\tmp@Xb}{\tmp@Xa}\addtolength{\tmp@Xb}{-.5\hmscstartsymbolwidth}% + \setlength{\tmp@Xc}{\tmp@Xa}\addtolength{\tmp@Xc}{.5\hmscstartsymbolwidth}% + \setlength{\tmp@Yb}{\tmp@Ya}\addtolength{\tmp@Yb}{0.866025403784\hmscstartsymbolwidth}% + \draw (\tmp@Xa,\tmp@Ya) -- (\tmp@Xb,\tmp@Yb) -- (\tmp@Xc,\tmp@Yb) -- cycle;% + \node[inner sep=0] (#1) at (#2,#3) {};% +} + + +% User command to draw hmsc end symbols +% usage: \hmscendsymbol{#1}(#2,#3) +% #1: nickname +% #2: x-coordinate +% #3: y-coordinate +% +% +% sin(pi/3) =~ 0.866025403784 +% +\def\hmscendsymbol#1(#2,#3){% + %\message{(hmsc end symbol: #1)}% + \setlength{\tmp@Xa}{#2\mscunit}% + \setlength{\tmp@Ya}{#3\mscunit}% + \setlength{\tmp@Xb}{\tmp@Xa}\addtolength{\tmp@Xb}{-.5\hmscstartsymbolwidth}% + \setlength{\tmp@Xc}{\tmp@Xa}\addtolength{\tmp@Xc}{.5\hmscstartsymbolwidth}% + \setlength{\tmp@Yb}{\tmp@Ya}\addtolength{\tmp@Yb}{-0.866025403784\hmscstartsymbolwidth}% + \draw (\tmp@Xa,\tmp@Ya) -- (\tmp@Xb,\tmp@Yb) -- (\tmp@Xc,\tmp@Yb) -- cycle;% + \node[inner sep=0] (#1) at (#2,#3) {};% +} + +% User command to draw a hmsc condition +% usage: \hmsccondition{#1}{#2}(#3,#4) +% #1: nickname +% #2: text +% #3: x-coordinate +% #4: y-coordinate +\def\hmsccondition#1#2(#3,#4){% + \setlength{\tmp@X}{.5\hmscconditionwidth}% + \setlength{\tmp@Y}{.5\hmscconditionheight}% + \setlength{\tmp@Xa}{\tmp@X}\addtolength{\tmp@Xa}{.6\tmp@Y}% + \node[minimum height=\tmp@Y,text centered, text width=2\tmp@X] (#1) at (#3\mscunit,#4\mscunit) {#2}; + \draw[xshift=#3\mscunit, yshift=#4\mscunit] (#1.north west) -- (#1.north east) -- (\tmp@Xa,0) --% + (#1.south east) -- (#1.south west) -- (-\tmp@Xa,0) --% + cycle;% + \setlength{\tmp@X}{\hmscconditionwidth}% + \setlength{\tmp@Y}{\hmscconditionheight}% +} + +% User command to draw a hmsc reference +% usage: \hmscreference{#1}{#2}(#3,#4) +% #1: nickname +% #2: text +% #3: x-coordinate +% #4: y-coordinate +\def\hmscreference#1#2(#3,#4){% + \setlength{\tmp@X}{\hmscreferencewidth}% + \setlength{\tmp@Y}{\hmscreferenceheight}% + \def\rtxt{\vbox to \tmp@Y{\vss\hbox to \tmp@X{\hss{}#2\hss}\vss}}% + \node[minimum height=\tmp@Y,draw, rounded corners=3pt,text centered, text width=\tmp@X] (#1) at (#3\mscunit,#4\mscunit) {#2}; +} + +% User command to draw a hmsc time intervalhmsccommentwidth +% usage: \hmscmeasure[isDirected]{text}[width]{nodeA}[top/bottom]{nodeB}[top/bottom] +% #1: if is directed +% #2: text +% #3: width +% #4: nodeA +% #5: top/bottom +% #6: nodeB +% #7: top/bottom +\newcommand{\hmscmeasure}[2][no]{ + \def\msc@isDirected{#1}% + \def\mess@labeltext{#2}% + \hmsctimeinterval@A% +} + +\newcommand{\hmsctimeinterval@A}[2][\msc@measuredist]{% + \setlength{\msc@measuredist}{#1}% + \def\msc@nodeA{#2}% + \hmsctimeinterval@B% +} + +\newcommand{\hmsctimeinterval@B}[2][bottom]{% + \def\msc@nodeApos{#1}% + \def\msc@nodeB{#2}% + \hmsctimeinterval@C% +} + +\newcommand{\hmsctimeinterval@C}[1][\ifx\msc@nodeA\msc@nodeB bottom\else top\fi]{% + \hmscdrawtimeinterval{\msc@isDirected}{\mess@labeltext}{\msc@measuredist}{\msc@nodeA}{\msc@nodeApos}{\msc@nodeB}{#1}% +} + +% usage: \hmscdrawtimeintervall{isDirected}{text}{width}{nodeA}{top/bottom}{nodeB}{top/bottom} +% #1: if is directed +% #2: text +% #3: width +% #4: nodeA +% #5: top/bottom +% #6: nodeB +% #7: top/bottom +\def\hmscdrawtimeinterval#1#2#3#4#5#6#7{ + \pgfextractx{\tmp@Xa}{\pgfpointanchor{#4}{center}}% + \ifthenelse{\equal{#5}{bottom}}{ + \pgfextracty{\tmp@Ya}{\pgfpointanchor{#4}{south}}% + }{ + \pgfextracty{\tmp@Ya}{\pgfpointanchor{#4}{north}}% + } + \setlength{\tmp@X}{\tmp@Xa}% + \addtolength{\tmp@X}{#3}% + \pgfextractx{\tmp@Xb}{\pgfpointanchor{#6}{center}}% + \ifthenelse{\equal{#7}{bottom}}{ + \pgfextracty{\tmp@Yb}{\pgfpointanchor{#6}{south}}% + }{ + \pgfextracty{\tmp@Yb}{\pgfpointanchor{#6}{north}}% + } + \draw[style=dashed] (\tmp@Xa,\tmp@Ya)--(\tmp@X,\tmp@Ya)--(\tmp@X,\tmp@Yb)--(\tmp@Xb,\tmp@Yb);%;% + + %label + \setlength{\tmp@Y}{.5\tmp@Ya + .5\tmp@Yb} + \ifthenelse{\lengthtest{\tmp@X < \tmp@Xa}} + {% left from node + \addtolength{\tmp@X}{-\labeldist} + \node[left, inner sep=0] at (\tmp@X,\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}};% + \addtolength{\tmp@X}{\labeldist} + } + {% right from node + \addtolength{\tmp@X}{\labeldist} + \node[right, inner sep=0] at (\tmp@X,\tmp@Y) {\raisebox{\depth}[\totalheight][0pt]{#2}};% + \addtolength{\tmp@X}{-\labeldist} + } + + %arrows + \ifthenelse{\equal{#1}{no}}{ + \msc@measuresymbolup{\tmp@X}{-\tmp@Ya} + \msc@measuresymboldown{\tmp@X}{-\tmp@Yb} + }{ + \ifthenelse{\lengthtest{ \tmp@Ya > \tmp@Yb } }% + {%normal direction + \msc@measuresymboldown{\tmp@X}{-\tmp@Yb}% + }{%oposite direction + \msc@measuresymbolup{\tmp@X}{-\tmp@Yb}% + } + } +} + +% User command to draw a hmsc absolute time +% usage: \hmsmark{#1}(#2,#3){#4} +% #1: text +% #2: x-coordinate +% #3: y-coordinate +% #4: to-nickname +\def\hmscmark#1(#2,#3)#4{% + \pgfextractx{\tmp@X}{\pgfpointanchor{#4}{center}}%get node x-coordinate + \setlength{\tmp@Xb}{#2\mscunit} + \node {\global\sbox{\tmp@box}{\raisebox{\depth}[\totalheight][0pt]{#1}}};% + \setlength{\tmp@Yd}{#3\mscunit}%y-coordinate of bottom of mark box + \setlength{\tmp@Ya}{\tmp@Yd + .5\ht\tmp@box}%comment top + \addtolength{\tmp@Ya}{\labeldist}% + \ifthenelse{\lengthtest{ \tmp@Xb < \tmp@X } }% + {% comment left from node + \setlength{\tmp@Xa}{#2\mscunit}%comment box right most side + \draw[style=dashed] (#4) -- (\tmp@Xa,\tmp@Yd);%draw dashed line from node to mark box + \setlength{\tmp@Xb}{\wd\tmp@box} + \setlength{\tmp@Xb}{\tmp@Xa - \tmp@Xb} + \addtolength{\tmp@Xb}{-\labeldist} + \draw[style=dashed] (\tmp@Xa,\tmp@Yd) -- (\tmp@Xb,\tmp@Yd);% + \addtolength{\tmp@Xa}{-\labeldist} + \node[left=-4pt] at (\tmp@Xa,\tmp@Ya) {\usebox{\tmp@box}}; + }% + {% comment right from node + \setlength{\tmp@Xa}{#2\mscunit} + \draw[style=dashed] (#4) -- (\tmp@Xa,\tmp@Yd);%draw dashed line from node to mark box + \setlength{\tmp@Xb}{\wd\tmp@box} + \setlength{\tmp@Xb}{\tmp@Xa + \tmp@Xb} + \addtolength{\tmp@Xb}{\labeldist} + \draw[style=dashed] (\tmp@Xa,\tmp@Yd) -- (\tmp@Xb,\tmp@Yd);% + \addtolength{\tmp@Xa}{\labeldist} + \node[right=-4pt] at (\tmp@Xa,\tmp@Ya) {\usebox{\tmp@box}}; + }% + +} + +% User command to draw a hmsc comment +% usage: \hmsccomment{#1}(#2,#3){#4} +% #1: text +% #2: x-coordinate +% #3: y-coordinate +% #4: to-nickname +\def\hmsccomment#1(#2,#3)#4{% + \pgfextractx{\tmp@X}{\pgfpointanchor{#4}{center}}% get x-coordinate of node to which attach comment + \setlength{\tmp@Xa}{#2\mscunit} % comment x-coordinate + \setlength{\tmp@Ya}{#3\mscunit}% y-coordinate of middle of comment box + \ifthenelse{\lengthtest{ \tmp@Xa < \tmp@X } }% + {% comment left from node + \ifthenelse{\lengthtest{\hmsccommentwidth = 0pt}} + {% set comment width automatic + \node (c) [rectangle,anchor = east, align=right] at (\tmp@Xa,\tmp@Ya) {#1}; % create comment body with text + }% + {% comment width is given + \node (c) [rectangle,anchor = east, align=right, text width=\hmsccommentwidth] at (\tmp@Xa,\tmp@Ya) {#1}; % create comment body with text + }% + \draw[style=dashed] (#4) -- (c.east);% draw dashed line from node to comment box + \draw (c.north west) -- (c.north east) -- (c.south east) -- (c.south west);% draw comment box with one side open + }% + {% comment right from node + \ifthenelse{\lengthtest{\hmsccommentwidth = 0pt}} + {% set comment width automatic + \node (c) [rectangle,anchor = west, align=left] at (\tmp@Xa,\tmp@Ya) {#1}; % create comment body with text + }% + {% comment width is given + \node (c) [rectangle,anchor = west, align=left, text width=\hmsccommentwidth] at (\tmp@Xa,\tmp@Ya) {#1}; % create comment body with text + }% + \draw[style=dashed] (#4) -- (c.west);% draw dashed line from node to comment box + \draw (c.north east) -- (c.north west) -- (c.south west) -- (c.south east);% draw comment box with one side open + }% +} + +% User command to draw a global comment +% usage: \mscglobalcomment{#1}(#2,#3) +% #1: text +% #2: x-coordinate +% #3: y-coordinate +\def\mscglobalcomment#1(#2,#3){% + \setlength{\tmp@X}{\mscglobalcommentwidth}% + \setlength{\tmp@Y}{\hmsccommentheight}% + %comment text + \node (c) [rectangle,anchor = north west, minimum height = \tmp@Y,text width=\tmp@X] at (#2\mscunit,#3\mscunit) {#1}; + %tmp@Xa = right side X + \node (h) [rectangle,anchor = north east, minimum size = \hmsccommenthem] at (c.north east) {}; + \draw (h.north west) -- (c.north west) -- (c.south west) -- (c.south east) -- (h.south east) -- (h.north west) -- (h.south west) -- (h.south east); + + \setlength{\tmp@Xa}{#2\mscunit}% + \addtolength{\tmp@Xa}{\tmp@X}% + %tmp@Xb = right upper corner hem point X + \setlength{\tmp@Xb}{\tmp@Xa}% + \addtolength{\tmp@Xb}{-\hmsccommenthem}% + %tmp@Ya = down side Y + \setlength{\tmp@Ya}{#3\mscunit}% + \addtolength{\tmp@Ya}{-\tmp@Y}% + %tmp@Yb = right upper corner hem point Y + \setlength{\tmp@Yb}{#3\mscunit}% + \addtolength{\tmp@Yb}{-\hmsccommenthem}% + %draw hmsccomment box + %\draw (#2,#3) -- (\tmp@Xb,#3) -- (\tmp@Xa,\tmp@Yb) -- (\tmp@Xa,\tmp@Ya) -- (#2,\tmp@Ya) -- (#2,#3);% + %draw hmsccomment hem + %\draw (\tmp@Xb,#3) -- (\tmp@Xb,\tmp@Yb) -- (\tmp@Xa,\tmp@Yb);% +} + +% User command to draw hmsc connections +% usage: \hmscconnection{#1}(#2,#3) +% #1: nickname +% #2: x-coordinate +% #3: y-coordinate +\def\hmscconnection#1(#2,#3){% + \draw (#2,#3) circle (2\hmscconnectionradius);% + \node[inner sep=2\hmscconnectionradius] (#1) at (#2,#3) {};% +} + +% User command to draw hmsc inline expressions +% usage: \hmscinline[#1]{#2}[#3]{#4}(#5,#6)(#7,#8) +% #1: list of vertical separators +% #2: nickname +% #3: list of horizontal separators +% #4: text +% #5: x-start coordinate +% #6: y-start coordinate +% #7: x-end coordinate +% #8: y-end coordinate +%\def\hmscinline[vertical separators]#1[horizontal separators]#2(#3,#4)(#5,#6){% + +\newcount\verticalnodecount +\newcount\horizontalnodecount + +\newcommand{\hmscinline}[2][]{ + \def\nickname{#2}% + \verticalnodecount0 + \horizontalnodecount0 + \renewcommand{\do}[1]{\verticalnode ##1}% Update how the list items will be processed + \docsvlist{#1}% Process items + \hmscinline@A% +} + +\newcommand{\hmscinline@A}[2][]{ + \renewcommand{\do}[1]{\horizontalnode ##1}% Update how the list items will be processed + \docsvlist{#1}% Process items + \def\hmscinlinetext{#2}% + \hmscinline@B% +} + +\newcommand{\verticalnode}[1]{\advance\verticalnodecount1 + \expandafter\newcount\csname x\the\verticalnodecount\endcsname% + \csname x\the\verticalnodecount\endcsname#1 + %\expandafter\def\csname x\the\verticalnodecount\endcsname{#1}% +} + +\newcommand{\horizontalnode}[1]{\advance\horizontalnodecount1 + \expandafter\newcount\csname y\the\horizontalnodecount\endcsname% + \csname y\the\horizontalnodecount\endcsname#1 + %\expandafter\def\csname y\the\horizontalnodecount\endcsname{#1}% +} + +\def\hmscinline@B(#1,#2)(#3,#4){% + \def\inktext{\raisebox{\depth}[\totalheight][0pt]{\hmscinlinetext}} + % first the solid part of the inline expression: + \setlength{\tmp@Xa}{#1\mscunit}% + \setlength{\tmp@Ya}{#2\mscunit}% + \setlength{\tmp@Xb}{#3\mscunit}% + \setlength{\tmp@Yb}{#4\mscunit}% + \setlength{\tmp@X}{\tmp@Xb-\tmp@Xa}% + \setlength{\tmp@Y}{\tmp@Ya-\tmp@Yb}% + \node[draw,anchor=north west,rectangle,minimum width=\tmp@X,minimum height=\tmp@Y] (\nickname) at (\tmp@Xa,\tmp@Ya) {}; + \ifnum\verticalnodecount>0 + \loop\ifnum\verticalnodecount>0 + \draw [dashed] (\the\csname x\the\verticalnodecount\endcsname,\tmp@Ya) --% + (\the\csname x\the\verticalnodecount\endcsname,\tmp@Yb); + \advance\verticalnodecount-1 + \repeat + \fi + \ifnum\horizontalnodecount>0 + \loop\ifnum\horizontalnodecount>0 + \draw [dashed] (\tmp@Xa,\the\csname y\the\horizontalnodecount\endcsname) --% + (\tmp@Xb,\the\csname y\the\horizontalnodecount\endcsname); + \advance\horizontalnodecount-1 + \repeat + \fi + \node {\global\sbox{\tmp@box}{\inktext}};% + \setlength{\tmp@X}{\wd\tmp@box}% + \setlength{\tmp@X}{1.1\tmp@X+\labeldist}% + \setlength{\tmp@Y}{\ht\tmp@box}% + \setlength{\tmp@Y}{1.1\tmp@Y+\labeldist}% + \setlength{\tmp@Xb}{\tmp@X+\labeldist}% + \setlength{\tmp@Yb}{\tmp@Y+\labeldist}% + \node[below right, inner sep = \labeldist] at (\tmp@Xa,\tmp@Ya) {\inktext};% + \draw (\tmp@Xa,\tmp@Ya-\tmp@Yb) -- (\tmp@Xa+\tmp@X,\tmp@Ya-\tmp@Yb) --% + (\tmp@Xa+\tmp@Xb,\tmp@Ya-\tmp@Y) -- (\tmp@Xa+\tmp@Xb,\tmp@Ya+0);% +} + +% User command to draw arrows between hmsc-objects +% Usage: \arrow(*){#1}[(x0,y0)...(xn,yn)]{#2} +% if * no arrow is drawn +% #1: start hmsc object +% (x0,y0)...(xn,yn) (optional): sequence of intermediate points +% #2: end hmsc object + +\newcount\tmpbegin +\newcount\tmpend +\newcount\nodecount + +\def\arrow{ + \@ifstar{\def\arrow@style{line}\arrow@A}% + {\def\arrow@style{arrow}\arrow@A}% +} + +\def\arrow@A#1{ + \def\firstnode{(#1)}% + \nodecount0 + \nextcharA +} + +\def\nextcharA{ + \futurelet\character\testA +} + +\def\testA{ + \ifx\character[\let\nxt\removebrackets\else\let\nxt\test\fi\nxt +} + +\def\removebrackets[#1]{ + \nextchar#1 +} + +\def\nextchar{ + \futurelet\character\test +} + +\def\test{ + \ifx\character(\let\nxt\nextnode\else\let\nxt\arrowend\fi\nxt +} + +\def\nextnode(#1,#2){\advance\nodecount1 + \expandafter\def\csname x\the\nodecount\endcsname{#1}% + \expandafter\def\csname y\the\nodecount\endcsname{#2}% + \nextchar +} + +\def\arrowend#1{ + \def\lastnode{(#1)}% + + \ifnum\nodecount=0 + \ifthenelse{\equal{\arrow@style}{arrow}} + {\draw[-stealth] \firstnode -- \lastnode;} + {\draw \firstnode -- \lastnode;} + \fi + + \ifnum\nodecount>0 + \tmpbegin0 + \tmpend1 + \advance\nodecount-1 + \draw \firstnode -- (\csname x\the\tmpend\endcsname,\csname y\the\tmpend\endcsname); + \loop\ifnum\tmpbegin<\nodecount \advance\tmpbegin1 \advance \tmpend1 + \draw (\csname x\the\tmpbegin\endcsname,\csname y\the\tmpbegin\endcsname) --% + (\csname x\the\tmpend\endcsname,\csname y\the\tmpend\endcsname); + \repeat + \ifthenelse{\equal{\arrow@style}{arrow}} + {\draw[-stealth] (\csname x\the\tmpend\endcsname,\csname y\the\tmpend\endcsname) -- \lastnode;} + {\draw (\csname x\the\tmpend\endcsname,\csname y\the\tmpend\endcsname) -- \lastnode;} + \fi + \unskip +} + + +% User environment to draw hmsc's +% Usage: \begin{hmsc}{#1}(llx,lly((urx,ury)...\end{hmsc} +% + + +\def\hmsc@settitle{% + \MSC@settitle{hmsc}% + {\hmsc@llx}% + {\hmsc@lly}% + {\hmsc@urx}% + {\hmsc@ury}% + {\hmsc@titlejustification}% + {\hmsckeywordstyle{\hmsckeyword}{} \hmsc@title}% +% \setlength{\tmp@X}{\hmsc@llx + \leftnamedist}% +% \setlength{\tmp@Y}{\hmsc@ury - \topnamedist}% +% \rput[tl](\tmp@X,\tmp@Y){% +% \hmsckeywordstyle{\hmsckeyword}{} \hmsc@title% +% }% +} + +\newenvironment{hmsc}[2][l] + {\message{( \hmsckeyword: '#2'}% + \def\hmsc@titlejustification{#1}% + \def\hmsc@title{#2}% + \hmsc@startenv}% + {%\setlength{\tmp@X}{\hmsc@llx}\addtolength{\tmp@X}{\leftnamedist}% + %\setlength{\tmp@Y}{\hmsc@ury}\addtolength{\tmp@Y}{-\topnamedist}% + %\rput[tl](\tmp@X,\tmp@Y){\raisebox{\depth}[\totalheight][0pt]{\hmsckeywordstyle{\hmsckeyword} \hmsc@name}}% + \hmsc@settitle% + \ifthenelse{\equal{\msc@frame}{yes}}{% + \draw (\hmsc@llx,\hmsc@lly) rectangle (\hmsc@urx,\hmsc@ury);% + }{\relax}% + \end{tikzpicture} +\end{lrbox}% +{% DEBUG: use this \fbox stuf to check the bounding box + \setlength{\fboxrule}{0.01pt}% + \setlength{\fboxsep}{1pt}% + \color{white}\fbox{% + \usebox{\mscbox}% + }% +}% + \message{)}}% +\def\hmsc@startenv(#1,#2)(#3,#4){% + \newcommand{\hmsc@llx}{#1\mscunit}% + \newcommand{\hmsc@lly}{#2\mscunit}% + \newcommand{\hmsc@urx}{#3\mscunit}% + \newcommand{\hmsc@ury}{#4\mscunit}% +\begin{lrbox}{\mscbox}% + \begin{tikzpicture}(\hmsc@llx,\hmsc@lly)(\hmsc@urx,\hmsc@ury) + \ifthenelse{\equal{\msc@grid}{yes}}{% +\draw[style=dotted, step=1cm] (\hmsc@llx,\hmsc@lly) grid (\hmsc@urx,\hmsc@ury);% + +\newlength{\hmsc@width}% +\newlength{\hmsc@height}% +\setlength{\hmsc@width}{\hmsc@urx-\hmsc@llx}% +\setlength{\hmsc@height}{\hmsc@ury-\hmsc@lly}% + +% xticks and yticks +\newcount\tmpcnt% + +\tmpcnt = \hmsc@width% +\divide \tmpcnt by 1864679%from sp to cm +\foreach \x in {0,...,\tmpcnt} {% + \node at (\x, 0) [below right] {\x}; +}% + +\tmpcnt = \hmsc@height% +\divide \tmpcnt by 1864679%from sp to cm +\foreach \y in {0,...,\tmpcnt} {% + \node at (0,\y) [above left] {\y}; +}% + }{\relax}% +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Initialisation of the msc package +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% \set@mscvalueslarge +\def\set@mscvalueslarge{% + % the lengths + \setlength{\actionheight}{0.75\mscunit} + \setlength{\actionwidth}{1.25\mscunit} + \setlength{\bottomfootdist}{1\mscunit} + \setlength{\msccommentdist}{1.5\mscunit} + \setlength{\conditionheight}{0.75\mscunit} + \setlength{\conditionoverlap}{0.6\mscunit} + \setlength{\envinstdist}{2.5\mscunit} + \setlength{\firstlevelheight}{0.75\mscunit} + \setlength{\gatesymbolradius}{.5mm} + \setlength{\msccommentwidth}{0\mscunit} % let comment change size automatic + \setlength{\hmscconditionheight}{0.8\mscunit} + \setlength{\hmscconditionwidth}{1.6\mscunit} + \setlength{\hmscconnectionradius}{0.06\mscunit} + \setlength{\hmscreferenceheight}{0.8\mscunit} + \setlength{\hmscreferencewidth}{1.6\mscunit} + \setlength{\hmsccommentwidth}{0\mscunit} % let comment change size automatic + \setlength{\hmsccommentheight}{0.8\mscunit} + \setlength{\mscglobalcommentwidth}{2.4\mscunit} + \setlength{\hmsccommenthem}{0.3\mscunit} + \setlength{\hmscstartsymbolwidth}{0.85\mscunit} + \setlength{\inlineoverlap}{1.5\mscunit} + \setlength{\instbarwidth}{0pt} + \setlength{\instdist}{3\mscunit} + \setlength{\instfootheight}{0.25\mscunit} + \setlength{\instheadheight}{.6\mscunit} + \setlength{\instwidth}{1.75\mscunit} + \setlength{\labeldist}{1ex} + \setlength{\lastlevelheight}{0.5\mscunit} + \setlength{\leftnamedist}{0.3\mscunit} + \setlength{\levelheight}{.75\mscunit} + \setlength{\lostsymbolradius}{.15\mscunit} + \setlength{\markdist}{0.75\mscunit} + \setlength{\measuredist}{0.75\mscunit} + \setlength{\measuresymbolwidth}{.15\mscunit} + \setlength{\mscdocreferenceheight}{0.8\mscunit} + \setlength{\mscdocreferencewidth}{1.6\mscunit} + \setlength{\referenceoverlap}{1.5\mscunit} + \setlength{\regionbarwidth}{.2\mscunit} + \setlength{\regionwidth}{.5\mscunit} + \setlength{\selfmesswidth}{.75\mscunit} + \setlength{\stopwidth}{0.6\mscunit} + \setlength{\timerwidth}{0.4\mscunit} + \setlength{\topheaddist}{1.5\mscunit} + \setlength{\topnamedist}{.3\mscunit} + % some numeric parameters + \messarrowscale{2} +} +% +% +% \set@mscvaluesnormal +\def\set@mscvaluesnormal{% + % switch to a smaller font + \small% + % the lengths + \setlength{\actionheight}{0.6\mscunit} + \setlength{\actionwidth}{1.25\mscunit} + \setlength{\bottomfootdist}{0.7\mscunit} + \setlength{\msccommentdist}{1.1\mscunit} + \setlength{\conditionheight}{0.6\mscunit} + \setlength{\conditionoverlap}{0.5\mscunit} + \setlength{\envinstdist}{2\mscunit} + \setlength{\firstlevelheight}{0.6\mscunit} + \setlength{\gatesymbolradius}{.5mm} + \setlength{\msccommentwidth}{0\mscunit} % let comment change size automatic + \setlength{\hmscconditionheight}{0.7\mscunit} + \setlength{\hmscconditionwidth}{1.4\mscunit} + \setlength{\hmscconnectionradius}{0.05\mscunit} + \setlength{\hmscreferenceheight}{0.7\mscunit} + \setlength{\hmscreferencewidth}{1.4\mscunit} + \setlength{\hmsccommentwidth}{0\mscunit} % let comment change size automatic + \setlength{\hmsccommentheight}{0.7\mscunit} + \setlength{\mscglobalcommentwidth}{2\mscunit} + \setlength{\hmsccommenthem}{0.2\mscunit} + \setlength{\hmscstartsymbolwidth}{0.7\mscunit} + \setlength{\inlineoverlap}{1\mscunit} + \setlength{\instbarwidth}{0pt} + \setlength{\instdist}{2.2\mscunit} + \setlength{\instfootheight}{0.2\mscunit} + \setlength{\instheadheight}{.55\mscunit} + \setlength{\instwidth}{1.6\mscunit} + \setlength{\labeldist}{1ex} + \setlength{\lastlevelheight}{0.4\mscunit} + \setlength{\leftnamedist}{0.2\mscunit} + \setlength{\levelheight}{.5\mscunit} + \setlength{\lostsymbolradius}{.12\mscunit} + \setlength{\markdist}{.5\mscunit} + \setlength{\measuredist}{0.6\mscunit} + \setlength{\measuresymbolwidth}{.2\mscunit} + \setlength{\mscdocreferenceheight}{0.7\mscunit} + \setlength{\mscdocreferencewidth}{1.4\mscunit} + \setlength{\referenceoverlap}{1\mscunit} + \setlength{\regionbarwidth}{.15\mscunit} + \setlength{\regionwidth}{.4\mscunit} + \setlength{\selfmesswidth}{.6\mscunit} + \setlength{\stopwidth}{0.5\mscunit} + \setlength{\timerwidth}{0.3\mscunit} + \setlength{\topheaddist}{1.3\mscunit} + \setlength{\topnamedist}{.2\mscunit} + % some numeric parameters + \messarrowscale{1.5} +} +% +% \set@mscvaluessmall +\def\set@mscvaluessmall{% + % switch to a smaller font + \small% + % the lengths + \setlength{\actionheight}{0.5\mscunit} + \setlength{\actionwidth}{1.2\mscunit} + \setlength{\bottomfootdist}{0.5\mscunit} + \setlength{\msccommentdist}{0.75\mscunit} + \setlength{\conditionheight}{0.5\mscunit} + \setlength{\conditionoverlap}{0.4\mscunit} + \setlength{\envinstdist}{1.2\mscunit} + \setlength{\firstlevelheight}{0.4\mscunit} + \setlength{\gatesymbolradius}{.5mm} + \setlength{\msccommentwidth}{0\mscunit} % let comment change size automatic + \setlength{\hmscconditionheight}{0.6\mscunit} + \setlength{\hmscconditionwidth}{1.2\mscunit} + \setlength{\hmscconnectionradius}{0.04\mscunit} + \setlength{\hmscreferenceheight}{0.6\mscunit} + \setlength{\hmscreferencewidth}{1.2\mscunit} + \setlength{\hmsccommentwidth}{0\mscunit} % let comment change size automatic + \setlength{\hmsccommentheight}{0.6\mscunit} + \setlength{\mscglobalcommentwidth}{1.6\mscunit} + \setlength{\hmsccommenthem}{0.1\mscunit} + \setlength{\hmscstartsymbolwidth}{0.4\mscunit} + \setlength{\inlineoverlap}{.75\mscunit} + \setlength{\instbarwidth}{0pt} + \setlength{\instdist}{1.5\mscunit} + \setlength{\instfootheight}{0.15\mscunit} + \setlength{\instheadheight}{0.5\mscunit} + \setlength{\instwidth}{1.2\mscunit} + \setlength{\labeldist}{0.8ex} + \setlength{\lastlevelheight}{0.3\mscunit} + \setlength{\leftnamedist}{0.1\mscunit} + \setlength{\levelheight}{0.4\mscunit} + \setlength{\lostsymbolradius}{.08\mscunit} + \setlength{\markdist}{0.4\mscunit} + \setlength{\measuredist}{0.4\mscunit} + \setlength{\measuresymbolwidth}{.25\mscunit} + \setlength{\mscdocreferenceheight}{0.6\mscunit} + \setlength{\mscdocreferencewidth}{1.2\mscunit} + \setlength{\referenceoverlap}{.75\mscunit} + \setlength{\regionbarwidth}{.1\mscunit} + \setlength{\regionwidth}{.2\mscunit} + \setlength{\selfmesswidth}{.4\mscunit} + \setlength{\stopwidth}{0.3\mscunit} + \setlength{\timerwidth}{0.2\mscunit} + \setlength{\topheaddist}{1.2\mscunit} + \setlength{\topnamedist}{.1\mscunit} + % some numeric parameters + \messarrowscale{1.2} +} +% \setmscvalues assigns compatible values to all msc-parameters +% Currently, three sets of values are supported: large, normal +% and small. +\def\setmscvalues#1{% + \ifthenelse{\equal{#1}{large}}{% + \set@mscvalueslarge}{% + \ifthenelse{\equal{#1}{normal}}{% + \set@mscvaluesnormal}{% + \ifthenelse{\equal{#1}{small}}{% + \set@mscvaluessmall}{% + \ifthenelse{\equal{#1}{measure}}{% + \set@mscvaluesmeasure}{% + \msc@unknownmscvalueserr{#1}}}}}% +} +% +% initialisation of the msc-parameters +\setmscvalues{normal} +\setfootcolor{black} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Error and help messages +% We use the standard LaTeX2e facilities to generate error and help +% messages (for more info, see file lterror.dtx of LaTeX2e distribution). +% +% +% nickname already defined +\gdef\msc@nicknamedefinederr#1{% + \PackageError{msc}{% error message + nickname #1 already defined}{% help text + You tried to use the nickname '#1' for a new\MessageBreak + msc object (instance, reference, inline expression, etc.),\MessageBreak + but the nickname is already assigned to another msc object.\MessageBreak + press to continue (the new msc object will be ignored).}% +} +% +% no such msc instance error +\gdef\msc@instundefinederr#1{% + \PackageError{msc}{% error message + undefined msc instance: #1}{% help text + You used '#1' as an msc instance nickname, but\MessageBreak + there is no msc instance with that nickname.}% +} +% +% unknown linestyle error +\gdef\msc@unknownlinestyleerr#1{% + \PackageError{msc}{% error message + unknown linestyle: #1}{% help text + Known msc linestyles are "solid", "dashed", and "dotted".\MessageBreak + You used '#1'.}% +} +% +% unknown region style error +\gdef\msc@unknownregionstyleerr#1{% + \PackageError{msc}{% error message + unknown region style: #1}{% help text + Known msc region styles are "normal", "coregion", "suspension", and "activation".\MessageBreak + You used '#1'.}% +} +% +% unknown self message label position error +\gdef\msc@unknownselfmessposerr#1{% + \PackageError{msc}{% error message + unknown position for self message: #1}{% help text + Known positions are "l" (left), "r" (right).\MessageBreak + You used '#1'.}% +} +% +% unknown self message label position error +\gdef\msc@unknowntimerposerr#1{% + \PackageError{msc}{% error message + unknown timer position: #1}{% help text + Known timer positions are "l" (left), "r" (right).\MessageBreak + You used '#1'.}% +} +% +% unknown self message label position error +\gdef\msc@unknownmscvalueserr#1{% + \PackageError{msc}{% error message + unknown set of msc-values: #1}{% help text + Known sets of msc-values are "normal" and "small".\MessageBreak + You used '#1'.}% +} +% +% no such msc reference error +\gdef\msc@refundefinederr#1{% + \PackageError{msc}{% error message + undefined reference: #1}{% help text + You used '#1' as a reference nickname, but\MessageBreak + there is no reference with that nickname.}% +} +% +% no such msc inline error +\gdef\msc@inlundefinederr#1{% + \PackageError{msc}{% error message + undefined inline expression: #1}{% help text + You used '#1' as a inline expression nickname, but\MessageBreak + there is no inline expression with that nickname.}% +} +% +% inline first right from last error +\gdef\msc@inlfirstlasterror#1#2#3{% + \PackageError{msc}{% error message + first instance right from final instance\MessageBreak in inline expression #1}{% help text + In the definition of inline expression '#1', you probably switched\MessageBreak + the first msc instance, '#2', and the final msc instance, '#3',\MessageBreak + since the first is located right from the final.}% +} +% +% reference first rightt from last error +\gdef\msc@reffirstlasterror#1#2#3{% + \PackageError{msc}{% error message + first instance right from final instance\MessageBreak in reference #1}{% help text + In the definition of msc reference '#1', you probably switched\MessageBreak + the first msc instance, '#2', and the final msc instance, '#3',\MessageBreak + since the first is located right from the final.}% +} +% +\gdef\msc@illegalmarkplacement#1{% + \PackageError{msc}{% + illegal mark placement specifier: #1}{% help text + The four mark placement specifiers are:\MessageBreak + tl (top-left)\MessageBreak + bl (bottom-left)\MessageBreak + tr (top-right)\MessageBreak + br (bottom-right)} +} +\gdef\msc@illegalmesslabelpositionerr#1{% + \PackageError{msc}{% + illegal label position specifier: #1}{% help text + Valid label position specifiers are:\MessageBreak + t (top)\MessageBreak + b (bottom)} +} +\gdef\msc@illegalselfmesspositionerr#1{% + \PackageError{msc}{% + illegal label position: #1}{% help text + Valid label positions are:\MessageBreak + t (top)\MessageBreak + b (bottom)\MessageBreak + l (left)\MessageBreak + r (right)} +} +\gdef\msc@illegallostfoundlabelpositionerr#1{% + \PackageError{msc}{% + in lost/found message: illegal label position: #1}{% help text + Valid label position are:\MessageBreak + t (top)\MessageBreak + b (bottom)} +} +%################################################################################ +% +\gdef\msc@illegaltitleplacement#1{% + \PackageError{msc}{% + illegal title placement specifier: #1}{% help text + Valid title placement specifiers are:\MessageBreak + l (left)\MessageBreak + c (center)\MessageBreak + r (right)} +} +%################################################################################ +\gdef\hmsc@nicknamedefinederr#1{% + \PackageError{msc}{% error message + nickname #1 already defined}{% help text + You tried to use the nickname '#1' for a new\MessageBreak + hmsc object (startsymbol, endsymbol, reference, etc.),\MessageBreak + but the nickname is already assigned to another hmsc object.\MessageBreak + press to continue (the new hmsc object will be ignored).}% +} +% no such msc hmsc object error +\gdef\hmsc@objectundefinederr#1{% + \PackageError{msc}{% error message + undefined hmsc object: #1}{% help text + You used '#1' as an hmsc object nickname, but\MessageBreak + there is no hmsc object with that nickname.}% +}% +% hmsc unknown connection type +\gdef\hmsc@unknownconnectiontypeerror#1{% + \PackageError{msc}{% error message + Unknown HMSC connection type: #1}{% help text + Known HMSC connection types are straight, rounded, and curved.}% +} +% +% hmsc missing y coordinate in arrow specification +\gdef\hmsc@missingycoord#1#2{% + \PackageError{msc}{% error message + Missing Y coordinate in arrow specification. You typed:\MessageBreak + [#2]\MessageBreak + which is parsed as the incomplete list of points:\MessageBreak + #1\MessageBreak + Remove the final X coordinate or add an Y coordinate}{% + The points specifying an HMSC arrow should be given as a comma separated\MessageBreak + list of X, Y coordinates. Furthermore, each X coordinate should\MessageBreak + be followed by a Y coordinate.}% +} +% remarks +% +% Issuing pstricks drawing-commands inside a TeX-group in a pspicture environment +% can result in ill-positioned objects. +% +% messages from/to the right environment should be defined after the last +% instance is declared with \declinst + diff --git a/slides/1-1.tex b/slides/1-1.tex new file mode 100644 index 0000000..edb996d --- /dev/null +++ b/slides/1-1.tex @@ -0,0 +1,806 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 1: Provable Security} +\covertopicname{1.1: Introduction} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Defining cryptography} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{What is Cryptography?}{\textit{``The science of enabling secure and private computation, communication, verification, and delegation in the presence of untrusted parties, adversarial behavior, and mutually distrustful participants.''}} + \end{column} + + \begin{column}{0.5\textwidth} + \imagewithcaption{caesar.png}{Source: Serious Cryptography, 2nd Edition} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Defining cryptography} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{What is Cryptography?}{\textit{``The science of enabling secure and private computation, communication, verification, and delegation in the presence of untrusted parties, adversarial behavior, and mutually distrustful participants.''}} + \end{column} + + \begin{column}{0.5\textwidth} + \imagewithcaption{vigenere.png}{Source: Serious Cryptography, 2nd Edition} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Cryptography is everywhere} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Banking + \item Buying stuff from the store + \item Any digital payment system + \item Messaging (WhatsApp, Signal, iMessage, Telegram) + \item Voice calls + \item Government and military systems + \item SSH + \item VPN access + \item Visiting most websites (HTTPS) + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Disk encryption + \item Cloud storage + \item Video conferencing + \item Unlocking your (newer) car + \item Identity card systems + \item Ticketing systems + \item DRM solutions + \item Private contact discovery + \item Cryptocurrencies + \item That iPhotos feature that detects similar photos + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{How it's made} + \bigimagewithcaption{fischer.png}{Fischer et al., The Challenges of Bringing Cryptography from Research Papers to Products: Results from an Interview Study with Experts, USENIX Security 2024} +\end{frame} + +\begin{frame}{How it's made} + \begin{center} + \bigimagewithcaption{fischer_sectioned.png}{Fischer et al., The Challenges of Bringing Cryptography from Research Papers to Products: Results from an Interview Study with Experts, USENIX Security 2024} + \end{center} +\end{frame} + +\begin{frame}{Cryptographic building blocks} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Components} + \begin{itemize}[<+->] + \item Cryptography manifests as a set of primitives, from which we + build protocols intended to accomplish well-defined security goals. + \item \textbf{Primitives}: AES, RSA, SHA-2, DH\ldots + \item \textbf{Protocols}: TLS, Signal, SSH, FileVault 2, BitLocker\ldots + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \textbf{Examples} + \begin{itemize}[<+->] + \item \textbf{AES}: Symmetric encryption + \begin{itemize} + \item $\mathsf{Enc}(k, m) = c$, $\mathsf{Dec}(k, c) = m$. + \end{itemize} + \item \textbf{SHA-2}: Hash function + \begin{itemize} + \item $\mathsf{H}(m) = h$. + \end{itemize} + \item \textbf{Diffie-Hellman}: Public key agreement + \begin{itemize} + \item Allows two parties to agree on a secret key $k$. + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Cryptographic building blocks} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Security goals} + \begin{itemize}[<+->] + \item \textbf{Confidentiality}: Data exchanged between Client and Server + is only known to those parties. + \item \textbf{Authentication}: If Server receives data from Client, + then Client sent it to Server. + \item \textbf{Integrity}: If Server modifies data owned by Client, + Client can find out. + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \textbf{Examples} + \begin{itemize}[<+->] + \item \textbf{Confidentiality}: When you send a private message on Signal, + only you and the recipient can read the content. + \item \textbf{Authentication}: When you receive an email from your boss, + you can verify it actually came from them. + \item \textbf{Integrity}: Your computer can verify that software update + downloads haven't been tampered with during transmission. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Security goals: more examples} + \begin{itemize}[<+->] + \item \textbf{TLS (HTTPS)} ensures that data exchanged between the client + and the server is confidential and that parties are authenticated. + \begin{itemize} + \item Allows you to log into gmail.com without your ISP learning your password. + \end{itemize} + \item \textbf{FileVault 2} ensures data confidentiality and integrity on + your MacBook. + \begin{itemize} + \item Prevents thieves from accessing your data if your MacBook is stolen. + \end{itemize} + \item \textbf{Signal} implements post-compromise security, an advanced security + goal. + \begin{itemize} + \item Allows a conversation to ``heal'' in the event of a temporary key + compromise. + \item More on that later in the course. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Why bother?} + \begin{itemize}[<+->] + \item Can't we just use access control? + \item Strictly speaking, usernames and passwords can be implemented + without cryptography\ldots + \item Server checks if the password matches, or if the IP address matches, + etc. before granting access. + \item What's so bad about that? + \end{itemize} + \definitionbox{The Problem with Traditional Access Control}{ + \begin{itemize}[<+->] + \item Requires trusting the server completely + \item No protection during transmission + \item No way to verify integrity + \item No way to establish trust between strangers + \end{itemize} + } +\end{frame} + +\begin{frame}[c]{The magic of cryptography} + \begin{center} + \Large\textbf{Cryptography lets us achieve what seems impossible} + \vspace{1cm} + \begin{itemize}[<+->] + \item Secure communication over insecure channels + \item Verification without revealing secrets + \item Proof of computation without redoing it + \end{itemize} + \end{center} +\end{frame} + +\begin{frame}{Hard problems} + \begin{itemize}[<+->] + \item Cryptography is largely about equating the security of a system to the + difficulty of solving a math problem that is thought to be computationally + very expensive. + \item With cryptography, we get security systems that we can literally + mathematically prove as secure (under assumptions). + \item Also, this allows for actual magic. + \begin{itemize}[<+->] + \item Alice and Bob meet for the first time in the same room as you. + \item You are listening to everything they are saying. + \item Can they exchange a secret without you learning it? + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Time for actual magic} + \bigimagewithcaption{dh.png}{} +\end{frame} + +\begin{frame}{No known feasible computation} + \begin{itemize}[<+->] + \item The discrete logarithm problem: + \begin{itemize} + \item Given a finite cyclic group $G$, a generator $g \in G$, and an element + $h \in G$, find the integer $x$ such that $g^{x}=h$ + \end{itemize} + \item In more concrete terms: + \begin{itemize} + \item Let $p$ be a large prime and let $g$ be a generator of the multiplicative + group $\mathbb{Z}_{p}^{*}$ (all nonzero integers modulo $p$). + + \item Given: + \begin{itemize} + \item $g \in \mathbb{Z}_{p}^{*}$, $h \in \mathbb{Z}_{p}^{*}$ + + \item Find $x \in \{0, 1, \ldots, p-2\}$ such that $g^{x} \equiv h \pmod + {p}$ + \end{itemize} + + \item This problem is believed to be computationally hard when $p$ is large + and $g$ is a primitive root modulo $p$. + \begin{itemize} + \item ``Believed to be'' = we don't know of any way to do it that doesn't + take forever, unless we have a strong, stable quantum computer (Shor's + algorithm) + \end{itemize} + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Hard problems} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Asymmetric Primitives} + \begin{itemize}[<+->] + \item Diffie-Hellman, RSA, ML-KEM, etc. + \item ``Asymmetric'' because there is a ``public key'' and a ``private + key'' for each party. + \item Algebraic, assume the hardness of mathematical problems (as seen + just now.) + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \textbf{Symmetric Primitives} + \begin{itemize}[<+->] + \item AES, SHA-2, ChaCha20, HMAC\ldots + \item ``Symmetric'' because there is one secret key. + \item Not algebraic but unstructured, but on their understood + resistance to $n$ years of cryptanalysis. + \item Can act as substitutes for assumptions in security proofs! + \begin{itemize} + \item Example: hash function assumed to be a ``random oracle'' + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Kerckhoff's principle} + \begin{itemize}[<+->] + \item \textit{``A cryptosystem should be secure even if everything about + the system, except the key, is public knowledge.''} — Auguste Kerckhoffs, + 1883 + \item \textbf{Why it matters}: + \begin{itemize}[<+->] + \item No ``security through obscurity'' + \item The key is the only secret: the rest can be audited, tested, + trusted + \item Encourages open standards and peer review + \item If your system's security depends on nobody knowing how it works, + it's not secure. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Symmetric primitive example: hash functions} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \definitionbox{Hash Function Properties}{ + \begin{itemize}\item Takes input of \textbf{any size}[<+->] + \item Produces output of \textbf{fixed size} + \item Is \textbf{deterministic} (same input $\rightarrow$ same output) + \item Even a \textbf{tiny change} in input creates completely different output + \item Is \textbf{efficient} to compute\end{itemize} + } + \end{column} + \begin{column}{0.45\textwidth} + \begin{tcolorbox} + [colback=black!5!white,colframe=ciphergray] $\mathsf{SHA256}(\texttt{hello}) =$ \\ \texttt{2cf24dba5fb0a30e26e83b2ac5}\\ \texttt{b9e29e1b161e5c1fa7425e7304}\\ + \texttt{3362938b9824} + + $\mathsf{SHA256}(\texttt{hullo}) =$ \\ \texttt{7835066a1457504217688c8f5d}\\ + \texttt{06909c6591e0ca78c254ccf174}\\ \texttt{50d0d999cab0} + \end{tcolorbox} + \textcolor{cipherprimary}{\textbf{Note:} \small One character change $\rightarrow$ + completely different hash!} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Expected properties of a hash function} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Collision resistance}: computationally infeasible to find + two different inputs producing the same hash. + \item \textbf{Preimage resistance}: given the output of a hash function, + it is computationally infeasible to reconstruct the original input. + \item \textbf{Second preimage resistance}: given an input and an output, + it's computationally infeasible to find another different input + producing the same output. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{sha2.png}{SHA-2 compression function. Source: Wikipedia} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Hash functions: what are they good for?} + \begin{itemize}[<+->] + \item \textbf{Password storage}: Store the hash of the password on the server, + not the password itself. Then check candidate passwords against the hash. + \item \textbf{Data integrity verification}: Hash a file. Later hash it + again and compare hashes to check if the file has changed, suffered storage + degradation, etc. + \item \textbf{Proof of work}: Server asks client to hash something a lot of + times before they can access some resource. Useful for anti-spam, Bitcoin + mining, etc. + \item \textbf{Zero knowledge proofs}: time for more actual magic + \end{itemize} +\end{frame} + +\begin{frame}{Time for more actual magic} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Zero-knowledge proofs} allow you to prove that you know + a secret without revealing any information about it. + \item They built ``zero-knowledge virtual machines'' where you can execute + an entire program that runs as a zero-knowledge proof. + \item ZKP battleship game: server proves to the players that its + output to their battleship guesses is correct, without revealing any + additional information (e.g. ship location). + \end{itemize} + \end{column} + + \begin{column}{0.4\textwidth} + \imagewithcaption{battleship.jpg}{Battleship board game. Source: Hasbro} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Evaluating a hash function's quality} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Recall}: + \begin{itemize}[<+->] + \item \textbf{Asymmetric primitives} are based on mathematical + problems, can be mathematically proven secure (given assumptions!) + \item \textbf{Symmetric primitives} (encryption, hashing\ldots) + are statistically, empirically, heuristically shown to be secure, + not proven secure. + \item The more cryptanalysis they survive, the higher confidence + we have in their security. + \end{itemize} + \end{itemize} + \end{column} + + \begin{column}{0.4\textwidth} + \imagewithcaption{qiao.png}{Cryptanalysis of AES.} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{What about encryption?} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item Symmetric primitive of choice for encryption: \textbf{AES}. + \item Not that far off in terms of design process from hash functions, + but: + \begin{itemize}[<+->] + \item AES is a PRP (pseudorandom permutation) + \item HMAC-SHA256 is a PRF (pseudorandom function) + \end{itemize} + \end{itemize} + \end{column} + + \begin{column}{0.4\textwidth} + \imagewithcaption{aes_subbytes.png}{AES's SubBytes operation. Source: Wikipedia} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{PRF versus PRP} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Pseudo-Random Function (SHA-2)} + \begin{itemize}[<+->] + \item \textbf{Input} is arbitrary-length, + \item \textbf{Output} is fixed-length, looks random (as discussed + earlier). + \item Indistinguishable from a truly random function by an adversary with + limited computational power. + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \textbf{Pseudo-Random Permutation (AES)} + \begin{itemize}[<+->] + \item \textbf{Input and output} are the same length, forming a permutation. + \item Each input maps uniquely to one output, allowing invertibility. + \item Indistinguishable from a truly random permutation by an adversary + with limited computational power. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{$\mathsf{PRF}: F_{k}= X \rightarrow Y$} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item We want the mapping to be: + \begin{itemize} + \item One-way + \item ``Randomized'' + \item Relations between inputs not reflected in outputs + \end{itemize} + \end{itemize} + \end{column} + + \begin{column}{0.8\textwidth} + \begin{tikzpicture}[scale=0.38] + % Define colors + \definecolor{domaingreen}{RGB}{102, 170, 68} + \definecolor{rangegreen}{RGB}{170, 187, 136} + \definecolor{circlecolor}{RGB}{235, 137, 85} + \definecolor{purplearrow}{RGB}{160, 78, 160} + \definecolor{redarrow}{RGB}{237, 50, 36} + + % Input space (domain) X - made square + \draw[dashed, thick, domaingreen, fill=domaingreen] + (0,0) rectangle (8,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (4,-0.8) + {Size: infinite!}; + \node[font=\small] at (4,9) {Input space (domain) $X$}; + + % Output (range) Y - made square - moved more to the right + \draw[thick, rangegreen, fill=rangegreen] (15,2) rectangle (20,7); + \node[text width=4cm, align=center, font=\normalsize] + at + (17.5,1.2) + {Size: fixed}; + \node[font=\small] at (17.5,8.5) {Output (range) $Y$}; + % Input dots - adjusted positions for square domain + \filldraw[circlecolor] (2,7) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,7) -- (16.2,6.4); + \pause + \filldraw[circlecolor] (16.2,6.4) circle (0.3); + \pause + + \filldraw[circlecolor] (3,6) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,6) -- (18.6,5.3); + \pause + \filldraw[circlecolor] (18.6,5.3) circle (0.3); + \pause + + \filldraw[circlecolor] (2,5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,5) -- (16.8,4.2); + \pause + \filldraw[circlecolor] (16.8,4.2) circle (0.3); + \pause + + \filldraw[circlecolor] (4,3.5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (4,3.5) -- (18.4,3.2); + \pause + \filldraw[circlecolor] (18.4,3.2) circle (0.3); + \pause + + \filldraw[circlecolor] (2,2) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,2) -- (17.1,2.7); + \pause + \filldraw[circlecolor] (17.1,2.7) circle (0.3); + \pause + + \filldraw[circlecolor] (3,1) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, ultra thick, redarrow] + (3,1) -- (16.8,4.2); + \node[redarrow, font=\scriptsize\bfseries, rotate=14] + at + (10,3) + {Collisions are inevitable}; + \end{tikzpicture} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{$\mathsf{PRP}: F_{k}= X \rightarrow X$} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item \textbf{Bijective} (two-way) + \begin{itemize} + \item \textbf{Injective}: no two inputs map to same output (no + collisions) + \item \textbf{Surjective}: Every output has one corresponding input + \end{itemize} + \item ``Randomized'' + \item Relations between inputs not reflected in outputs + \end{itemize} + \end{column} + + \begin{column}{0.8\textwidth} + \begin{tikzpicture}[scale=0.38] + % Define colors + \definecolor{domaingreen}{RGB}{102, 170, 68} + \definecolor{rangegreen}{RGB}{102, 170, 68} + \definecolor{circlecolor}{RGB}{235, 137, 85} + \definecolor{purplearrow}{RGB}{160, 78, 160} + + % Input space (domain) X - made square + \draw[dashed, thick, domaingreen, fill=domaingreen] + (0,0) rectangle (8,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (4,-0.8) + {Size: fixed}; + \node[font=\normalsize] at (4,9) {Input space (domain) $X$}; + + % Output (range) Y - made square, same size as domain, moved left + \draw[thick, rangegreen, fill=rangegreen] (12,0) rectangle (20,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (16,-0.8) + {Size: fixed}; + \node[font=\normalsize] at (16,9) {Output (range) $X$}; + % Input dots - adjusted positions for square domain + \filldraw[circlecolor] (2,7) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,7) -- (14.2,7.4); + \pause + \filldraw[circlecolor] (14.2,7.4) circle (0.3); + \pause + + \filldraw[circlecolor] (3,6) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,6) -- (18.6,5.3); + \pause + \filldraw[circlecolor] (18.6,5.3) circle (0.3); + \pause + + \filldraw[circlecolor] (2,5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,5) -- (13.8,4.2); + \pause + \filldraw[circlecolor] (13.8,4.2) circle (0.3); + \pause + + \filldraw[circlecolor] (4,3.5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (4,3.5) -- (17.4,2.2); + \pause + \filldraw[circlecolor] (17.4,2.2) circle (0.3); + \pause + + \filldraw[circlecolor] (2,2) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,2) -- (16.1,6.7); + \pause + \filldraw[circlecolor] (16.1,6.7) circle (0.3); + \pause + + \filldraw[circlecolor] (3,1) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,1) -- (19.0,1.4); + \pause + \filldraw[circlecolor] (19.0,1.4) circle (0.3); + \end{tikzpicture} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{AES is a block cipher} + \begin{itemize}[<+->] + \item AES takes a 16-byte input, produces a 16-byte output. + \item Key can be 16, 24 or 32 bytes. + \item OK, so what if we want to encrypt more than 16 bytes? + \item \textbf{Proposal}: split the plaintext into 16 byte chunks, encrypt + each of them with the same key. + \end{itemize} +\end{frame} + +\begin{frame}{Block cipher examples} + \begin{columns} + \begin{column}{0.33\textwidth} + \imagewithcaption{tux_plaintext.png}{What we start with} + \end{column} + \pause + \begin{column}{0.33\textwidth} + \imagewithcaption{tux_encrypted_ecb.png}{What we get} + \end{column} + \pause + \begin{column}{0.33\textwidth} + \imagewithcaption{tux_encrypted_ctr.png}{What we actually want} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Block cipher modes of operation} + \bigimagewithcaption{block_cipher_modes.png}{Source: Wikipedia} +\end{frame} + +\begin{frame}{Cryptographic building blocks} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Security goals} + \begin{itemize} + \item \textbf{Confidentiality}: Data exchanged between Client and Server + is only known to those parties. + + \item \textbf{Authentication}: If Server receives data from Client, + then Client sent it to Server. + + \item \textbf{Integrity}: If Server modifies data owned by Client, + Client can find out. + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \textbf{Examples} + \begin{itemize}[<+->] + \item \textbf{Confidentiality}: When you send a private message on Signal, + only you and the recipient can read the content. + \item \textbf{Authentication}: When you receive an email from your boss, + you can verify it actually came from them. + \item \textbf{Integrity}: Your computer can verify that software update + downloads haven't been tampered with during transmission. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Security goals: more examples} + \begin{itemize}[<+->] + \item \textbf{TLS (HTTPS)} ensures that data exchanged between the client + and the server is confidential and that parties are authenticated. + \begin{itemize} + \item Allows you to log into gmail.com without your ISP learning your password. + \end{itemize} + \item \textbf{FileVault 2} ensures data confidentiality and integrity on + your MacBook. + \begin{itemize} + \item Prevents thieves from accessing your data if your MacBook is stolen. + \end{itemize} + \item \textbf{Signal} implements post-compromise security, an advanced security + goal. + \begin{itemize} + \item Allows a conversation to ``heal'' in the event of a temporary key + compromise. + + \item More on that later in the course. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{TLS 1.3: high-level sketch} + \bigimagewithcaption{tls_13_sketch}{Source: Mostafa Ibrahim} +\end{frame} + +\begin{frame}{TLS 1.3: high-level sketch} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Public key agreement} (eg. Diffie-Hellman) is used to establish + a shared secret between the client and the server. + \item \textbf{AES} is used for encrypting data in transit. + \item \textbf{SHA-2} is used for hashing (checking certificates, etc.) + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \bigimagewithcaption{tls_13_sketch}{Source: Mostafa Ibrahim} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{TLS 1.3: high-level sketch} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Through the design, we accomplish the desired \textbf{security + goals} under a well-specified \textbf{threat model}: + \item \textbf{Security goals}: confidentiality of data, authentication + of the server towards the client\ldots + \item \textbf{Threat model}: malicious Internet Service Provider (ISP), + etc. + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \bigimagewithcaption{tls_13_sketch}{Source: Mostafa Ibrahim} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{How TLS 1.3 was made} + \bigimagewithcaption{fischer}{} +\end{frame} + +\begin{frame}{How TLS 1.3 was made} + \bigimagewithcaption{fischer_tls_13_bubbles}{} +\end{frame} + +\begin{frame}{From hard problems to real-world security} + \begin{center} + \Large\textbf{The journey we'll trace} + \end{center} + \vspace{0.5cm} + \begin{enumerate}[<+->] + \item \textbf{Mathematical insight}: Discrete logarithm is hard to compute. + \item \textbf{Cryptographic innovation}: Diffie-Hellman key exchange leverages this hardness. + \item \textbf{Real-world impact}: Secure communication for billions of people daily. + \end{enumerate} + \vspace{1cm} + \textbf{This is the power of applied cryptography}: transforming abstract mathematical problems into tools that help people and protect our digital lives. +\end{frame} + +\begin{frame}{Course goals} + \begin{itemize}[<+->] + \item Understand the reasoning behind the math of modern cryptography. + \item Analyze and prove the security of cryptographic constructions. + \item Understand how cryptographic constructions can be composed to build real-world + secure protocols and systems. + \item Discern between theoretical cryptography and applied cryptography from + an engineering perspective. + \item Critically assess security implementations and evaluate real-world cryptographic + protocols. + \item Gain an understanding of the future of cryptography and its role in emerging + technologies. + \end{itemize} +\end{frame} + +\begin{frame}{Course prerequisites} + \begin{itemize} + \item Good but optional: CMPS 215 (Theory of Computation) + \item If you want to understand whether you have the sufficient background for this course, review this revision chapter and try to do all the exercises: \url{https://joyofcryptography.com/pdf/chap0.pdf} + \end{itemize} +\end{frame} + +\begin{frame}{Class materials} + \begin{itemize}[<+->] + \item \textbf{Joy of Cryptography}: learn how to reason about and prove systems secure. + \item \textbf{Attack papers, codebases, labs}: hard engineering perspective. + \vspace{1cm} + \item \textbf{Always keep an eye on the website:} Course news, updates, + materials, slides will all be posted there. + \url{https://appliedcryptography.page} + \item I am aiming for the most engaging course possible! + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/1-2.tex b/slides/1-2.tex new file mode 100644 index 0000000..42fbf1f --- /dev/null +++ b/slides/1-2.tex @@ -0,0 +1,500 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 1: Provable Security} +\covertopicname{1.2: One-Time Pad \& The Provable Security Mindset} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{How it's made} + \bigimagewithcaption{fischer_theory.png}{Fischer et al., The Challenges of Bringing Cryptography from Research Papers to Products: Results from an Interview Study with Experts, USENIX Security 2024} +\end{frame} + +\begin{frame}{Thinking about secrecy} + \bigimagewithcaption{naive_enc.pdf}{Source: The Joy of Cryptography} +\end{frame} + +\begin{frame}{Thinking about secrecy} + \begin{columns}[c] + \column{0.5\textwidth}{ + \begin{itemize}[<+->] + \item Keep the whole design secret? + \item \textbf{``Advantages''}: + \begin{itemize}[<+->] + \item Attacker doesn’t know how our cipher (or system, more generally,) works. + \end{itemize} + \item \textbf{Disadvantages}: + \begin{itemize}[<+->] + \item Figuring out how the thing works might mean a break. + \item Can’t expose cipher to scrutiny. + \item Everyone needs to invent a cipher. + \end{itemize} + \end{itemize} + } + \column{0.5\textwidth}{ + \imagewithcaption{naive_enc.pdf}{Source: The Joy of Cryptography} + } + \end{columns} +\end{frame} + +\begin{frame}{Kerckhoff's principle} + \begin{itemize}[<+->] + \item \textit{``A cryptosystem should be secure even if everything about the system, except the key, is public knowledge.''} — Auguste Kerckhoffs, 1883 + \item \textbf{Why it matters}: + \begin{itemize}[<+->] + \item No ``security through obscurity'' + \item The key is the only secret: the rest can be audited, tested, trusted + \item Encourages open standards and peer review + \item If your system's security depends on nobody knowing how it works, it's not secure. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Thinking about secrecy} + \bigimagewithcaption{keyed_enc.pdf}{\textbf{Concentrate all the need for secrecy in the key!}} +\end{frame} + +\begin{frame}{Thinking about secrecy} + \begin{columns}[c] + \column{0.5\textwidth}{ + \begin{itemize}[<+->] + \item Cipher can be scrutinized, used by anyone. + \item Design can be shown to hold so long as the key is secret. + \item This is how virtually all cryptography is designed today. + \end{itemize} + } + \column{0.5\textwidth}{ + \imagewithcaption{keyed_enc.pdf}{Source: The Joy of Cryptography} + } + \end{columns} +\end{frame} + +\begin{frame}{One-time pad}{First look at a symmetric cipher} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \sssubroutine{Enc}{K, M}{ + $C \coloneq K \oplus M$ \\ + return $C$ + }{2} + \end{column} + \begin{column}{0.5\textwidth} + \sssubroutine{Dec}{K, C}{ + $M \coloneq K \oplus C$ \\ + return $M$ + }{2} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{XOR (Exclusive OR) operation} + \begin{columns}[c] + \column{0.6\textwidth}{ + \begin{table} + \centering + \begin{tabular}{|c|c|c|} + \hline + \textbf{A} & \textbf{B} & \textbf{A $\oplus$ B} \\ + \hline + \texttt{0} & \texttt{0} & \texttt{0} \\ + \hline + \texttt{0} & \texttt{1} & \texttt{1} \\ + \hline + \texttt{1} & \texttt{0} & \texttt{1} \\ + \hline + \texttt{1} & \texttt{1} & \texttt{0} \\ + \hline + \end{tabular} + \caption{Truth table for XOR operation} + \end{table} + \begin{itemize} + \item XOR returns 1 when inputs differ + \item XOR returns 0 when inputs are the same + \item Key property: $x \oplus x = 0$ and $x \oplus 0 = x$ + \item Self-inverse: $(M \oplus K) \oplus K = M$ + \end{itemize} + } + \column{0.4\textwidth}{ + \begin{center} + \begin{tikzpicture}[scale=0.8] + \draw[thick] (0,0) circle (1.5); + \draw[thick] (1,0) circle (1.5); + \node at (0,-2) {A}; + \node at (1,-2) {B}; + \begin{scope} + \clip (0,0) circle (1.5); + \clip (1,0) circle (1.5); + \fill[cyan!30] (-1.5,-1.5) rectangle (2.5,1.5); + \end{scope} + \draw[thick] (0,0) circle (1.5); + \draw[thick] (1,0) circle (1.5); + \node at (0.5,0) {$A \oplus B$}; + \end{tikzpicture} + \end{center} + } + \end{columns} +\end{frame} + +\begin{frame}{One-time pad}{First look at a symmetric cipher} + \bigimagewithcaption{xor_enc.png}{(We're encoding the message and key as bits)} +\end{frame} + +\begin{frame}{One-time pad}{First look at a symmetric cipher} + \bigimagewithcaption{xor_dec.png}{(We're encoding the message and key as bits)} +\end{frame} + +\begin{frame}{Key derivation}{Uniform distribution} + \begin{itemize}[<+->] + \item How to derive $K$? + \item $K$ is ideally random. + \item True randomness isn’t practical, so $K$ is in practice pseudo-random. + \item We need a pseudo-random uniform distribution: + \item If $\mathcal{S}$ is a set of $m$ items, then the uniform distribution over $\mathcal{S}$ assigns probability $\frac{1}{m}$ to each item $x \in \mathcal{S}$ + \item In practice, this just means we need the bits to be random, unpredictable, uniformly distributed in terms of probability + \item Sampling a $K$ from a pseudo-random uniform distribution is written as $K \twoheadleftarrow \bits^n$ + \end{itemize} +\end{frame} + +\begin{frame}{Adversary's access to oracle} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item ``Victim'' chooses their key. + \item Adversary chooses the message and receives the ciphertext. + \item We say that \textbf{the adversary has access to an encryption oracle}. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{attacker_interface.pdf}{Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Adversary's access to oracle} + \begin{center} + \begin{tikzpicture}[ + box/.style={rectangle, draw, minimum height=2.5cm, align=left, fill=white}, + dashed box/.style={rectangle, draw, dashed, minimum width=2.5cm, minimum height=2.5cm, align=center, fill=white}, + >=Stealth, + ] + \node[dashed box] (adversary) {$adversary$}; + \node[box, right=2cm of adversary](attack){ + $\underline{\func{attack}{M}}$: \hfill \quad \quad \textcolor{gray}{\scriptsize \textit{// adversary chooses $M$}} \\ + \quad $K \twoheadleftarrow \bits^{n}$ \hfill \quad \quad \textcolor{gray}{\scriptsize \textit{// victim samples $K$}} \\ + \quad $C \coloneq \textsf{Enc}(K, M)$ \hfill \quad \quad \textcolor{gray}{\scriptsize \textit{// victim encrypts}} \\ + \quad return $C$ \hfill \quad \quad \textcolor{gray}{\scriptsize \textit{// adversary sees $C$}} + }; + \draw[->] (adversary) -- node[above] {$M$} (attack); + \draw[<-] ([yshift=-0.5cm]adversary.east) -- node[below] {$C$} ([yshift=-0.5cm]attack.west); + \end{tikzpicture} + \end{center} +\end{frame} + +\begin{frame}{Adversary's access to oracle} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Adversary can query oracle an unbounded number of times. + \item Two queries with same $M$ may return different $(C, C')$, since victim may use different $K$. + \item $K$ is always chosen correctly (pseudo-random uniform sampling) + \item ``Randomized oracle'' + \item Attacker cannot see $K$. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{attacker_interface.pdf}{Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Adversary's access to oracle} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item When we prove security, we prove what is or isn’t possible by the attacker calling \textsc{Attack}$(M)$. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{attacker_interface.pdf}{Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame} + \begin{center} + \Large\textit{``If I use OTP according to the attack scenario (I sample keys uniformly and use each key to encrypt just one ciphertext), then no matter how the plaintexts are chosen, and no matter how the ciphertext is subsequently used, I can enjoy a certain security guarantee.''} + \end{center} +\end{frame} + +\begin{frame}{One-time pad}{Correctness proof} + \begin{itemize}[<+->] + \item $\forall(n > 0,\; K \in \bits^{n},\; M \in \bits^{n}),\; \textsf{Dec}(K, \textsf{Enc}(K, M)) = M$ + \item For all positive $n$, any key of $n$ bits and message of $n$ bits will decrypt back to the same plaintext if encrypted into a ciphertext. + \item \textbf{Proof}: + \begin{align*} + \textsf{Dec}(K, \textsf{Enc}(K, M)) & = \textsf{Dec}(K, K \oplus M) \\ + & = K \oplus (K \oplus M) \\ + & = (K \oplus K) \oplus M \\ + & = 0^n \oplus M \\ + & = M \quad \qed + \end{align*} + \end{itemize} +\end{frame} + +\begin{frame}{One-time pad}{How do we prove security?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Generally}: a cipher is secure if the adversary can't distinguish the output of calls to $ATTACK$ from random junk. + \item \textbf{Formally}: For all positive integers $n$ and all choices of plaintext $M \in \{\texttt{0}, \texttt{1}\}^n$, the output of the following subroutine is uniformly distributed: + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sssubroutine{Attack}{M}{ + $K \twoheadleftarrow \bits^{n}$ \\ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1.5} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{One-time pad}{How do we prove security?} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{itemize}[<+->] + \item If the key is random, the output will be uniformly distributed! + \item Suppose $M = \bit{01}$: + \begin{itemize}[<+->] + \item $K = \bit{00}$ is chosen with probability $1/4$:\\$C = K \oplus M = \bit{00} \oplus \bit{01} = \bit{01}$. + \item $K = \bit{01}$ is chosen with probability $1/4$:\\$C = K \oplus M = \bit{01} \oplus \bit{01} = \bit{00}$. + \item $K = \bit{10}$ is chosen with probability $1/4$:\\$C = K \oplus M = \bit{10} \oplus \bit{01} = \bit{11}$. + \item $K = \bit{11}$ is chosen with probability $1/4$:\\$C = K \oplus M = \bit{11} \oplus \bit{01} = \bit{10}$. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.3\textwidth} + \sssubroutine{Attack}{M}{ + $K \twoheadleftarrow \bits^{n}$ \\ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1.5} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{One-time pad}{How do we prove security?} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{itemize}[<+->] + \item What if this is true only for $M = \bit{01}$? + \item Fine, let's pick any $M, C \in \bits^n$. + \item What is \prob{\textsc{Attack}$(M) = C$}? + \item Answer: Exactly when $C = \textsf{Enc}(K, M) = K \oplus M$. + \item ...which occurs for exactly one $K$. + \item Since $K$ is chosen uniformly from $\bits^n$, the probability of choosing that $K$ is $\frac{1}{2^n}. \quad \qed$ + \end{itemize} + \end{column} + \begin{column}{0.3\textwidth} + \sssubroutine{Attack}{M}{ + $K \twoheadleftarrow \bits^{n}$ \\ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1.5} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{One-time pad}{From the adversary's perspective...} + \begin{columns}[c] + \begin{column}{0.35\textwidth} + \sssubroutine{Attack}{M}{ + $K \twoheadleftarrow \bits^{n}$ \\ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1.5} + \end{column} + \begin{column}{0.3\textwidth} + \begin{center} + {\huge{$\approxeq$}} \\[1em] + {\scriptsize\textit{(indistinguishable \\ from)}} + \end{center} + \end{column} + \begin{column}{0.35\textwidth} + \sssubroutine{Junk}{M}{ + $C \twoheadleftarrow \bits^{n}$ \\ + return $C$ + }{2} + \end{column} + \end{columns} +\end{frame} + +\begin{frame} + \begin{center} + \huge \textit{``Real or random?''} + \end{center} +\end{frame} + +\begin{frame}{Limitations of security proofs}{Part 1} + \begin{itemize}[<+->] + \item Rigor and the real world famously don't mix. + \item Security proofs are good for rigor but address very little regarding real-world concerns: + \begin{itemize}[<+->] + \item How can Alice \& Bob obtain a secret key, which only they know? + \item How can they keep $K$ secret? + \item How can a computer sample from the uniform distribution? + \item How can Alice ensure that $C$ is sent reliably to Bob? + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Limitations of security proofs}{Part 2} + \begin{itemize}[<+->] + \item More questions proofs don't address: + \begin{itemize}[<+->] + \item How can Alice hide the fact that she is talking to Bob (rather than hide only the content)? + \item How can Alice be sure that she is communicating with Bob, not an impostor? + \item How can we incentivize Alice and Bob to use encryption? + \item Should the government be allowed to obtain a warrant to read encrypted communications? + \end{itemize} + \item Security proofs are about specific properties within specific models. + \item Real-world security depends on many factors beyond what our models capture. + \item Having a security proof is necessary but not sufficient for real-world security. + \end{itemize} +\end{frame} + +\begin{frame}{The value of security proofs} + \begin{itemize}[<+->] + \item Despite limitations, security proofs provide important benefits: + \begin{itemize}[<+->] + \item \textbf{Precise guarantees}: Clearly define what security properties are achieved. + \item \textbf{Confidence}: When properly structured, proofs ensure no obvious attacks exist. + \item \textbf{Foundation for composition}: Proven components can be securely combined. + \item \textbf{Precise terminology}: Forces us to clearly define our terms and assumptions. + \end{itemize} + \item Security proofs help identify the \textit{boundaries} of security: + \begin{itemize}[<+->] + \item What assumptions are necessary? + \item What threats are addressed vs. unaddressed? + \item What conditions must hold for security to be maintained? + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{The provable security mindset} + \begin{itemize}[<+->] + \item Building systems with provable security in mind: + \begin{itemize}[<+->] + \item Start with clear security goals and adversary model. + \item Design systems whose security can be formally analyzed. + \item Identify and document necessary assumptions. + \item Distinguish between proven properties and conjectures. + \end{itemize} + \item Good practical security requires both: + \begin{itemize}[<+->] + \item Rigorous proofs for core mechanisms. + \item Practical engineering to address real-world constraints. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{OTP: security assumptions \& constraints}{Part 1} + \begin{itemize}[<+->] + \item Our security proofs rely on specific assumptions about the adversary: + \begin{itemize}[<+->] + \item \textbf{Key reuse}: Keys are never intentionally reused (though may repeat by chance). + \item \textbf{Observation only}: Adversary passively observes ciphertext but doesn't tam.per with it + \item \textbf{Message independence}: Choice of message $M$ is independent of key $K$. + \item \textbf{Key secrecy}: Adversary learns nothing about the key. + \item \textbf{No sampling influence}: Adversary cannot influence how the key is sampled. + \end{itemize} + \item These constraints are \textit{necessary} for the security proofs to hold! + \end{itemize} +\end{frame} + +\begin{frame}{OTP: security assumptions \& constraints}{Part 2} + \begin{itemize}[<+->] + \item Side-channel attacks violate our model: + \begin{itemize}[<+->] + \item We assume adversary cannot coerce victim to run a different algorithm. + \item Cannot observe execution details: + \begin{itemize}[<+->] + \item CPU timing information (clock cycles). + \item Memory access patterns. + \item Cache hits/misses. + \item Power consumption during encryption. + \end{itemize} + \end{itemize} + \item Real-world security requires considering these additional attack vectors. + \item Our security proofs address a \textit{specific threat model} that may not capture all real-world threats. + \end{itemize} +\end{frame} + +\begin{frame}{One-time pad}{What's so special about XOR?} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{itemize}[<+->] + \item Let's replace $\oplus$ with $\land$. What would happen? + \item Output no longer uniform! + \end{itemize} + \begin{table} + \centering + \begin{tabular}{|c|c|c|} + \hline + \textbf{A} & \textbf{B} & \textbf{A $\land$ B} \\ + \hline + \texttt{0} & \texttt{0} & \texttt{0} \\ + \hline + \texttt{0} & \texttt{1} & \texttt{0} \\ + \hline + \texttt{1} & \texttt{0} & \texttt{0} \\ + \hline + \texttt{1} & \texttt{1} & \texttt{1} \\ + \hline + \end{tabular} + \caption{Truth table for AND operation} + \end{table} + \end{column} + \begin{column}{0.3\textwidth} + \sssubroutine{Attack}{M}{ + $K \twoheadleftarrow \bits^{n}$ \\ + $C \coloneq K \land M$ \\ + return $C$ + }{1.5} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{One-time pad}{What about $\%\ n$?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Let's replace $\oplus$ with $\%\ n$. What would happen? + \item Still good! + \item Can you prove correctness and security? + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sssubroutine{Attack}{M}{ + $K \twoheadleftarrow \mathbb{Z}_{n}$ \\ + $C \coloneq (K + M)\ \%\ n$ \\ + return $C$ + }{1.5} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} + +\end{document} diff --git a/slides/1-3.tex b/slides/1-3.tex new file mode 100644 index 0000000..e14d047 --- /dev/null +++ b/slides/1-3.tex @@ -0,0 +1,1279 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 1: Provable Security} +\covertopicname{1.3: Provable Security \\ \& Computational Cryptography} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\section{Provable Security} + +\begin{frame}{Last time, we defined subroutines} + \begin{center} + \begin{tikzpicture}[ + box/.style={rectangle, draw, minimum height=2.5cm, align=left, fill=white}, + dashed box/.style={rectangle, draw, dashed, minimum width=2.5cm, minimum height=2.5cm, align=center, fill=white}, + >=Stealth, + ] + \node[dashed box] (adversary) {$adversary$}; + \node[box, right=2cm of adversary](attack){ + $\underline{\func{attack}{M}}$: \hfill \quad \quad \textcolor{gray}{\scriptsize \textit{// adversary chooses $M$}} \\ + \quad $K \twoheadleftarrow \bits^{n}$ \hfill \quad \quad \textcolor{gray}{\scriptsize \textit{// victim samples $K$}} \\ + \quad $C \coloneq \textsf{Enc}(K, M)$ \hfill \quad \quad \textcolor{gray}{\scriptsize \textit{// victim encrypts}} \\ + \quad return $C$ \hfill \quad \quad \textcolor{gray}{\scriptsize \textit{// adversary sees $C$}} + }; + \draw[->] (adversary) -- node[above] {$M$} (attack); + \draw[<-] ([yshift=-0.5cm]adversary.east) -- node[below] {$C$} ([yshift=-0.5cm]attack.west); + \end{tikzpicture} + \end{center} +\end{frame} + +\begin{frame}{Subroutines} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item ``Victim'' chooses their key. + \item Adversary chooses the message and receives the ciphertext. + \item We say that \textbf{the adversary has access to an encryption oracle}. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{attacker_interface.pdf}{Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Attack scenarios as libraries} + \begin{columns}[c] + \begin{column}{0.65\textwidth} + \begin{itemize}[<+->] + \item This is a \textbf{library} with two \textbf{subroutines} and a \textbf{global variable} $D$. + \item Victim holds a 6-sided die. + \item The first line of the library represents an initialization step. + \item Attacker can call the subroutines at any time, and: + \begin{enumerate} + \item Make a guess about the current value of the die and learn whether the guess was correct. + \item Instruct the victim to (privately) re-roll the die. + \end{enumerate} + \end{itemize} + \end{column} + \begin{column}{0.35\textwidth} + \vspace{-1cm} + \begin{center} + \sslibrary{}{dice-guess}{ + $D \twoheadleftarrow \{1, 2, 3, 4, 5, 6\}$ \\[1em] + \sslibrarysubroutine{guess}{G}{ + return $D == G$ + }{1} \\[1em] + \sslibrarysubroutine{reroll}{G}{ + $D \twoheadleftarrow \{1, 2, 3, 4, 5, 6\}$ + }{1} + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{One-time pad}{From the adversary's perspective...} + \begin{columns}[c] + \begin{column}{0.35\textwidth} + \sssubroutine{Attack}{M}{ + $K \twoheadleftarrow \bits^{n}$ \\ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1.5} + \end{column} + \begin{column}{0.3\textwidth} + \begin{center} + {\huge{$\approxeq$}} \\[1em] + {\scriptsize\textit{(indistinguishable \\ from)}} + \end{center} + \end{column} + \begin{column}{0.35\textwidth} + \sssubroutine{Junk}{M}{ + $C \twoheadleftarrow \bits^{n}$ \\ + return $C$ + }{2} + \end{column} + \end{columns} +\end{frame} + +\begin{frame} + \begin{center} + \huge \textit{``Real or random?''} + \end{center} +\end{frame} + +\begin{frame}{Programs and libraries} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \prog{} is a \textbf{program} that calls \textbf{library} \lib{}{dice-guess}. + \item Programs can only see the output of function calls to libraries. + \begin{itemize}[<+->] + \item Programs can't read the values of library variables, + \item Programs can't measure how long it took to run a subroutine, + \item Etc. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \ssprogram{}{ + if \func{guess}{6}:\\ + \quad return true\\ + \func{reroll}{}\\ + return \func{guess}{6} + }{0.95} + }{\link}{ + \sslibrary{}{dice-guess}{ + $D \twoheadleftarrow \{1, 2, 3, 4, 5, 6\}$ \\[1em] + \sslibrarysubroutine{guess}{G}{ + return $D == G$ + }{1} \\[1em] + \sslibrarysubroutine{reroll}{G}{ + $D \twoheadleftarrow \{1, 2, 3, 4, 5, 6\}$ + }{1} + }{0.95} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{When are libraries interchangeable?} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \begin{itemize}[<+->] + \item Libraries are \textbf{interchangeable} when they: + \begin{itemize}[<+->] + \item Have the same interface, + \item \prob{\prog{}\link\lib{}{1} \Rightarrow \texttt{true}} $=$ \prob{\prog{}\link\lib{}{2} \Rightarrow \texttt{true}} + \end{itemize} + \item i.e. when their usage and output is indistinguishable from the adversary's perspective when they are paired with \prog{}. + \item A lot of the time, \prog{}'s mission is to try to \textit{distinguish} between \lib{}{1} and \lib{}{2}. + \end{itemize} + \end{column} + \begin{column}{0.45\textwidth} + \begin{flushright} + \sslinked{ + \sslibrary{}{otp-real}{ + \sslibrarysubroutine{otp.enc}{M}{ + $K \twoheadleftarrow \bits^{n}$ \\ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1} + }{1} + }{\interchangeable{}}{ + \sslibrary{}{otp-rand}{ + \sslibrarysubroutine{otp.enc}{M}{ + $R \twoheadleftarrow \bits^{n}$ \\ + return $R$ + }{1} + }{1} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{When are libraries interchangeable?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Are these libraries interchangeable? + \item \textbf{Yes!} Their only difference happens in \textit{unreachable lines of code}. + \end{itemize} + \end{column} + \begin{column}{0.05\textwidth} + \end{column} + \begin{column}{0.45\textwidth} + \sslinked{ + \sslibrary{}{a}{ + \sslibrarysubroutine{foo}{M}{ + $X \twoheadleftarrow \{1, \ldots, n\}$ \\ + if $X < 0$: \\ + \quad return $\bit{0}^n$ + }{1} + }{1} + }{\interchangeable{?}}{ + \sslibrary{}{b}{ + \sslibrarysubroutine{foo}{M}{ + $X \twoheadleftarrow \{1, \ldots, n\}$ \\ + if $X < 0$: \\ + \quad return $\bit{0}^1$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{When are libraries interchangeable?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Are these libraries interchangeable? + \item \textbf{Yes!} Their only difference is the value they assign to a \textit{variable that is never actually used}. + \end{itemize} + \end{column} + \begin{column}{0.05\textwidth} + \end{column} + \begin{column}{0.45\textwidth} + \sslinked{ + \sslibrary{}{a}{ + \sslibrarysubroutine{foo}{A, B}{ + $Y \twoheadleftarrow \bits^n$\\ + $C \coloneq \func{bar}{A}$\\ + return $Y$ + }{1}\\[1em] + \sslibrarysubroutine{bar}{M}{ + $X \twoheadleftarrow \bits^n$\\ + return $X$ + }{1} + }{1} + }{\interchangeable{?}}{ + \sslibrary{}{b}{ + \sslibrarysubroutine{foo}{A, B}{ + $Y \twoheadleftarrow \bits^n$\\ + $C \coloneq \func{bar}{B}$\\ + return $Y$ + }{1}\\[1em] + \sslibrarysubroutine{bar}{M}{ + $X \twoheadleftarrow \bits^n$\\ + return $X$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{When are libraries interchangeable?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Are these libraries interchangeable? + \item $\|$ denotes string concatenation. + \begin{itemize} + \item $\texttt{Po} \| \texttt{tato} = \texttt{Potato}$ + \end{itemize} + \item \textbf{Yes!} Outputting the concatentaion two randomly sampled uniform strings of lengths $n$ and $m$ is the same as outputting a single random string of length $n + m$. + \end{itemize} + \end{column} + \begin{column}{0.05\textwidth} + \end{column} + \begin{column}{0.45\textwidth} + \sslinked{ + \sslibrary{}{a}{ + \sslibrarysubroutine{sample}{}{ + $X \twoheadleftarrow \bits^n$\\ + $Y \twoheadleftarrow \bits^m$\\ + return $X \| Y$ + }{1} + }{1} + }{\interchangeable{?}}{ + \sslibrary{}{b}{ + \sslibrarysubroutine{sample}{}{ + $R \twoheadleftarrow \bits^{n+m}$\\ + return $R$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{When are libraries interchangeable?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Are these libraries interchangeable? + \item \textbf{No!} The first library uses the same $K$ for all subsequent encryptions, which breaks OTP security. + \begin{itemize} + \item Recall that OTP requires keys to be only used once (hence the name). + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.05\textwidth} + \end{column} + \begin{column}{0.45\textwidth} + \sslinked{ + \sslibrary{}{a}{ + $K \twoheadleftarrow \bits^n$\\[1em] + \sslibrarysubroutine{otp.enc}{M}{ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1} + }{1} + }{\interchangeable{?}}{ + \sslibrary{}{b}{ + \sslibrarysubroutine{otp.enc}{M}{ + $C \twoheadleftarrow \bits^n$\\ + return $C$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{How do we show the distinguisher?} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize}[<+->] + \item What happens if we call \prog{}\link\lib{}{a} multiple times? + \begin{itemize} + \item We'll get the same output $\equiv K$ each time! + \end{itemize} + \item \prob{\prog{}\link\lib{}{a} \Rightarrow \texttt{true}} $= 1$, + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{flushright} + \sslinked{ + \ssprogram{}{ + $C_1 \coloneq \func{otp.enc}{\bit{0}^n}$\\ + $C_2 \coloneq \func{otp.enc}{\bit{0}^n}$\\ + return $C_1 == C_2$ + }{1} + }{\link}{ + \sslibrary{}{a}{ + $K \twoheadleftarrow \bits^n$\\[1em] + \sslibrarysubroutine{otp.enc}{M}{ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1} + }{1} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{How do we show the distinguisher?} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item What happens if we call \prog{}\link\lib{}{a} multiple times? + \begin{itemize} + \item We'll get the same output $\equiv K$ each time! + \end{itemize} + \item \prob{\prog{}\link\lib{}{a} \Rightarrow \texttt{true}} $= 1$, + \item \prob{\prog{}\link\lib{}{b} \Rightarrow \texttt{true}} $= \frac{1}{2^n}$. + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{flushright} + \sslinked{ + \ssprogram{}{ + $C_1 \coloneq \func{otp.enc}{\bit{0}^n}$\\ + $C_2 \coloneq \func{otp.enc}{\bit{0}^n}$\\ + return $C_1 == C_2$ + }{1} + }{\link}{ + \sslibrary{}{b}{ + \sslibrarysubroutine{otp.enc}{M}{ + $C \twoheadleftarrow \bits^n$\\ + return $C$ + }{1} + }{1} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{OTP: why key re-use is bad} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{align*} + C_i \oplus C_j & = (K \oplus M_i) \oplus (K \oplus M_j) \\ + & = K \oplus K \oplus M_i \oplus M_j \\ + & = \bit{0}^n \oplus M_i \oplus M_j \\ + & = M_i \oplus M_j + \end{align*} + \begin{itemize} + \item \prob{\prog{}\link\lib{}{a} \Rightarrow \texttt{true}} $= 1$\footnote{Interactive demo: \url{https://www.douglas.stebila.ca/teaching/visual-one-time-pad/}} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{flushright} + \sslinked{ + \ssprogram{}{ + $M_1 \twoheadleftarrow \bits^n$\\ + $M_2 \twoheadleftarrow \bits^n$\\ + $C_1 \coloneq \func{otp.enc}{M_1}$\\ + $C_2 \coloneq \func{otp.enc}{M_2}$\\ + return $C_1 \oplus C_2 == M_1 \oplus M_2$ + }{0.85} + }{\link}{ + \sslibrary{}{a}{ + $K \twoheadleftarrow \bits^n$\\[1em] + \sslibrarysubroutine{otp.enc}{M}{ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1} + }{0.85} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proving two libraries are interchangeable} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Are these libraries interchangeable? + \item Let's find out! + \item \textbf{Goal:} transform \lib{}{xor-samp-1} to \lib{}{xor-samp-2}, proving that each transformation step does not effect any change on calling programs. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{flushright} + \sslinked{ + \sslibrary{}{xor-samp-1}{ + \sslibrarysubroutine{sample}{M}{ + $X \twoheadleftarrow \bits^n$ \\ + $Y \coloneq X \oplus M$ \\ + return $(X, Y)$ + }{1} + }{1} + }{\interchangeable{?}}{ + \sslibrary{}{xor-samp-2}{ + \sslibrarysubroutine{sample}{M}{ + $Y \twoheadleftarrow \bits^n$ \\ + $X \coloneq Y \oplus M$ \\ + return $(X, Y)$ + }{1} + }{1} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proving two libraries are interchangeable}{Step 1} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item We start at \lib{}{xor-samp-1}. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{}{xor-samp-1}{ + \sslibrarysubroutine{sample}{M}{ + $X \twoheadleftarrow \bits^n$ \\ + $Y \coloneq X \oplus M$ \\ + return $(X, Y)$ + }{1} + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proving two libraries are interchangeable}{Step 2} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Let's add a new variable $X'$. + \item Note that $X = X'$: + \begin{itemize} + \item $X' = Y \oplus M = (X \oplus M) \oplus M = X$. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{}{hyb-1}{ + \sslibrarysubroutine{sample}{M}{ + $X \twoheadleftarrow \bits^n$ \\ + $Y \coloneq X \oplus M$ \\ + \hl{$X' \coloneq Y \oplus M$} \\ + return $(X, Y)$ + }{1} + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proving two libraries are interchangeable}{Step 3} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item So, we can return $(X', Y)$ without any change on the library's effect. + \begin{itemize} + \item $X' = Y \oplus M = (X \oplus M) \oplus M = X$. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{}{hyb-2}{ + \sslibrarysubroutine{sample}{M}{ + $X \twoheadleftarrow \bits^n$ \\ + $Y \coloneq X \oplus M$ \\ + $X' \coloneq Y \oplus M$ \\ + \hl{return $(X', Y)$} + }{1} + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proving two libraries are interchangeable}{Step 4} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item The first two lines of \func{sample}{M} are the same as \func{otp.enc}{M}, so we link it and use it instead. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslinked{ + \sslibrary{}{hyb-3-4}{ + \sslibrarysubroutine{sample}{M}{ + \hl{$Y \coloneq \func{otp.enc}{M}$} \\ + $X' \coloneq Y \oplus M$ \\ + return $(X', Y)$ + }{1} + }{1} + }{\link}{ + \sslibrary{}{otp-real}{ + \sslibrarysubroutine{otp.enc}{M}{ + $K \twoheadleftarrow \bits^n$ \\ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1} + }{1} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proving two libraries are interchangeable}{Step 5} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item The first two lines of \func{sample}{M} are the same as \func{otp.enc}{M}, so we link it and use it instead. + \item Recall that \lib{}{otp-real} \interchangeable{} \lib{}{otp-rand}! + \item So, we replace \lib{}{otp-real} with \lib{}{otp-rand}. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslinked{ + \sslibrary{}{hyb-3-4}{ + \sslibrarysubroutine{sample}{M}{ + $Y \coloneq \func{otp.enc}{M}$ \\ + $X' \coloneq Y \oplus M$ \\ + return $(X', Y)$ + }{1} + }{1} + }{\link}{ + \sslibrary{}{otp-rand}{ + \sslibrarysubroutine{otp.enc}{M}{ + $R \twoheadleftarrow \bits^{n}$ \\ + return $R$ + }{1} + }{1} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proving two libraries are interchangeable}{Step 6} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item The first two lines of \func{sample}{M} are the same as \func{otp.enc}{M}, so we link it and use it instead. + \item Recall that \lib{}{otp-real} \interchangeable{} \lib{}{otp-rand}! + \item So, we replace \lib{}{otp-real} with \lib{}{otp-rand}. + \item We inline \lib{}{otp-rand} back into our main library. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{}{hyb-5}{ + \sslibrarysubroutine{sample}{M}{ + $Y \hl{\twoheadleftarrow \bits^n}$ \\ + $X' \coloneq Y \oplus M$ \\ + return $(X', Y)$ + }{1} + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proving two libraries are interchangeable}{Step 7} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item The first two lines of \func{sample}{M} are the same as \func{otp.enc}{M}, so we link it and use it instead. + \item Recall that \lib{}{otp-real} \interchangeable{} \lib{}{otp-rand}! + \item So, we replace \lib{}{otp-real} with \lib{}{otp-rand}. + \item We inline \lib{}{otp-rand} back into our main library. + \item Finally, we rename $X'$ to $X$. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{}{hyb-6}{ + \sslibrarysubroutine{sample}{M}{ + $Y \twoheadleftarrow \bits^n$ \\ + $\hl{X} \coloneq Y \oplus M$ \\ + return $(\hl{X}, Y)$ + }{1} + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proving two libraries are interchangeable}{Result} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Interchangeable! + \item Note how we had to show equivalence \textbf{at each step}. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslinked{ + \sslibrary{}{hyb-6}{ + \sslibrarysubroutine{sample}{M}{ + $Y \twoheadleftarrow \bits^n$ \\ + $X \coloneq Y \oplus M$ \\ + return $(X, Y)$ + }{1} + }{1} + }{\interchangeable{}}{ + \sslibrary{}{xor-samp-2}{ + \sslibrarysubroutine{sample}{M}{ + $Y \twoheadleftarrow \bits^n$ \\ + $X \coloneq Y \oplus M$ \\ + return $(X, Y)$ + }{1} + }{1} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Cryptographic primitives} + \begin{itemize}[<+->] + \item Specific algorithms like OTP are important in cryptography, but OTP is just one instance of an \textbf{encryption scheme}. + \item In cryptography, useful abstractions like ``encryption scheme'' are called \textbf{primitives}. + \item Three things are important when defining a cryptographic primitive: + \begin{enumerate}[<+->] + \item \textbf{Syntax}: The basic raw interface - algorithms, inputs/outputs and their types. + \item \textbf{Correctness}: Basic functionality without adversaries - e.g., ``decryption should be the inverse of encryption''. + \item \textbf{Security}: Guarantees that hold in specific attack scenarios with adversaries. + \end{enumerate} + \end{itemize} +\end{frame} + +\begin{frame}{Cryptographic primitives}{$\Sigma$: a symmetric-key encryption scheme} + \begin{itemize} + \item \textbf{$\Sigma.\textsf{KeyGen}() = K$} + \begin{itemize} + \item Input: none + \item Output: key $K \in \Sigma.\mathcal{K}$ {\tiny(the ``key space'')}. + \end{itemize} + \item \textbf{$\Sigma.\textsf{Enc}(K, M) = C$} + \begin{itemize} + \item Input: key $K \in \Sigma.\mathcal{K}$, plaintext $M \in \Sigma.\mathcal{M}$ {\tiny(the ``message space'')}. + \item Output: ciphertext $C \in \Sigma.\mathcal{C}$. + \end{itemize} + \item \textbf{$\Sigma.\textsf{Dec}(K, C) = M$} + \begin{itemize} + \item Input: key $K \in \Sigma.\mathcal{K}$, ciphertext $C \in \Sigma.\mathcal{C}$ {\tiny(the ``ciphertext space'')}. + \item Output: plaintext $M \in \Sigma.\mathcal{M}$. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Correctness of a SKE} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Correctness for SKE}{ + An SKE scheme $\Sigma$ is correct if encryption and decryption are inverses, in the following sense: + \begin{align*} + \prob{\Sigma.\textsf{Dec}(K, \Sigma.\textsf{Enc}(K, M)) = M} = 1 + \end{align*} + for all $M \in \Sigma.\mathcal{M}$ and $K \in \Sigma.\mathcal{K}$. + } + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item The definition involves a probability because $\Sigma.\textsf{Enc}$ may be a randomized algorithm. + \item This means that decryption should \textbf{always} recover the original message. + \item Even if encryption adds randomness, decryption must be deterministic for each key-ciphertext pair. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{One-time secrecy of a SKE} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{One-time Secrecy for SKE}{ + An SKE scheme $\Sigma$ has one-time secrecy if the following libraries are interchangeable: + \vspace{0.5mm} + \begin{center} + \sslinked{ + \sslibrary{\Sigma}{ots-real}{ + \sslibrarysubroutine{ots.enc}{M}{ + $K \twoheadleftarrow \Sigma.\mathcal{K}$ \\ + $C \coloneq \Sigma.\textsf{Enc}(K, M)$ \\ + return $C$ + }{1} + }{0.8} + }{\interchangeable{}}{ + \sslibrary{\Sigma}{ots-rand}{ + \sslibrarysubroutine{ots.enc}{M}{ + $C \twoheadleftarrow \Sigma.\mathcal{C}$ \\ + return $C$ + }{1} + }{0.8} + } + \end{center} + } + \end{column} + \begin{column}{0.5\textwidth} + An encryption scheme has one-time secrecy if its ciphertexts are uniformly distributed, when keys are sampled uniformly, kept secret, and used for only one encryption, and no matter how the plaintexts are chosen. + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Reminder: AND $(\land)$} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{itemize}[<+->] + \item Let's replace $\oplus$ with $\land$. What would happen? + \item Output no longer uniform! + \end{itemize} + \begin{table} + \centering + \begin{tabular}{|c|c|c|} + \hline + \textbf{A} & \textbf{B} & \textbf{A $\land$ B} \\ + \hline + \texttt{0} & \texttt{0} & \texttt{0} \\ + \hline + \texttt{0} & \texttt{1} & \texttt{0} \\ + \hline + \texttt{1} & \texttt{0} & \texttt{0} \\ + \hline + \texttt{1} & \texttt{1} & \texttt{1} \\ + \hline + \end{tabular} + \caption{Truth table for AND operation} + \end{table} + \end{column} + \begin{column}{0.3\textwidth} + \sssubroutine{Attack}{M}{ + $K \twoheadleftarrow \bits^{n}$ \\ + $C \coloneq K \land M$ \\ + return $C$ + }{1.5} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Creating a distinguisher program} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Can you write a distinguisher program showing that these libraries are \textbf{not} interchangeable? + \item \ssprogram{}{ + $M \coloneq \bit{0}^n$\\ + $C \coloneq \func{ots.enc}{M}$\\ + return $C == \bit{0}^n$ + }{1} + \item \prob{A\link\lib{}{ots-real} \Rightarrow \texttt{true}} $= 1$ + \item \prob{A\link\lib{}{ots-rand} \Rightarrow \texttt{true}} $= \frac{1}{2^n}$ + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslinked{ + \sslibrary{}{ots-real}{ + \sslibrarysubroutine{ots.enc}{M}{ + $K \twoheadleftarrow \bits^n$ \\ + $C \coloneq K \land M$ \\ + return $C$ + }{1} + }{1} + }{\interchangeable{?}}{ + \sslibrary{}{ots-rand}{ + \sslibrarysubroutine{ots.enc}{M}{ + $C \twoheadleftarrow \bits^n$ \\ + return $C$ + }{1} + }{1} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\section{Computational Cryptography} + +\begin{frame}{Computational notions in cryptography} + \begin{itemize} + \item Security definitions in theoretical cryptography can be too strict: + \begin{itemize} + \item Even attacks requiring a trillion years of computation. + \item Even attacks with probability lower than winning the lottery 100 times. + \end{itemize} + \item Modern provable security takes a more practical approach: + \begin{itemize} + \item We dismiss attacks with ``astronomically'' high computational cost. + \item We dismiss attacks with ``astronomically'' tiny success probability. + \end{itemize} + \item Instead of ``no attack can succeed, not even in principle'', + \item We prove: ``every attack has either astronomically high cost or astronomically small success probability''. + \end{itemize} +\end{frame} + +\begin{frame}{The concrete approach to provable security} + \begin{itemize} + \item In the concrete approach to provable security, we aim to be as quantitative as possible about security claims. + \item We rarely say definitively that a cryptographic algorithm ``is secure'', as we did with OTP. + \item Instead, we use statements like: + \begin{itemize} + \item \textit{``Any attack that expends at most $2^{80}$ effort can succeed with probability no better than $2^{-64}$.''} + \end{itemize} + \item It is up to the user to judge whether this quantitative level of security is acceptable based on their use-case. + \item This gives users a concrete basis for security decisions. + \end{itemize} +\end{frame} + +\begin{frame}{Monetary cost of huge computations} + \begin{itemize} + \item One way to think about huge computations is their monetary cost. + \item The table below shows roughly how much a computation involving $2^n$ CPU cycles would cost on the cheapest available Amazon EC2 cloud computing service: + \end{itemize} + \begin{table} + \centering + \begin{tabular}{cll} + \textbf{Clock cycles} & \textbf{Approx cost (USD)} & \textbf{Point of reference} \\ + \hline + $2^{50}$ & \$3.50 & cup of coffee \\ + $2^{55}$ & \$100 & dinner at a high-end restaurant \\ + $2^{65}$ & \$130,000 & apartment in Achrafieh \\ + $2^{75}$ & \$130 million & budget of one of the Harry Potter movies \\ + $2^{85}$ & \$140 billion & GDP of Hungary \\ + $2^{92}$ & \$20 trillion & GDP of the United States \\ + $2^{99}$ & \$2 quadrillion & all of human economic activity since 300,000 BCE \\ + $2^{128}$ & a lot! & a billion human civilizations' worth of effort \\ + \end{tabular} + \end{table} +\end{frame} + +\begin{frame}{Understanding tiny probabilities} + \begin{itemize} + \item Let's put extremely small probabilities in perspective: + \begin{itemize} + \item In 2009, Patricia Demauro rolled dice 154 consecutive times without getting a 7 in craps. + \item Probability of this event: $(30/36)^{154} \approx 2^{-40.6}$ + \item Often cited as one of the most improbable documented events in gambling history. + \end{itemize} + \item Other extremely unlikely gambling events: + \begin{itemize} + \item In 1943, a roulette wheel reportedly landed on red 32 consecutive times. + \item Probability: $(18/38)^{31} \approx 2^{-33.4}$ + \item Winning the American Powerball lottery: $2^{-28.1}$ + \item Winning Powerball two consecutive weeks: $2^{-56.2}$ + \end{itemize} + \item These examples help us intuitively grasp what probabilities like $2^{-40}$ or $2^{-50}$ actually mean. + \end{itemize} +\end{frame} + +\begin{frame}{Computational scale of Bitcoin mining} + \begin{itemize}[<+->] + \item Let's consider cryptocurrencies based on proof-of-work, like Bitcoin. + \item These systems incentivize users to perform truly obscene amounts of computation. + \item In Bitcoin's proof-of-work mechanism: + \begin{itemize} + \item Users race to perform SHA-256 hash computations as fast as possible. + \item The collective Bitcoin network has performed approximately $2^{95}$ SHA-256 hashes in total. + \item In the last 12 months alone: approximately $2^{93.6}$ hashes. + \item Current market cap for Bitcoin: approximately 400 billion USD. + \end{itemize} + \item This shows the enormous scale of computation that economic incentives can support. + \end{itemize} +\end{frame} + +\begin{frame}{The asymptotic approach to provable security} + \begin{itemize}[<+->] + \item The concrete approach gives practical guidance (e.g., key sizes) but requires managing tedious quantitative details. + \item The asymptotic approach: + \begin{itemize} + \item Makes qualitative, all-or-nothing statements + \item Considers behavior as key size approaches infinity + \item Hides tedious quantitative details + \end{itemize} + \item Similar to asymptotic analysis using big-O notation. + \item Example: Instead of calculating that an operation takes exactly $16n^2 + 24n + 74$ steps, we can simply say it takes $O(n^2)$ steps + \end{itemize} +\end{frame} + +\begin{frame}{AES: An example of asymptotic security analysis} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item The Advanced Encryption Standard (AES) is a common symmetric-key encryption algorithm. + \item It comes in different variants: AES-128, AES-192, AES-256. + \item In asymptotic analysis, we'd say: + \begin{itemize} + \item AES is secure against all polynomial-time adversaries. + \item Any successful attack must take exponential time in the key length. + \end{itemize} + \item This hides the concrete details about specific computational costs. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Concrete security for AES-128: + \begin{itemize} + \item Best known attack: $\approx 2^{126.1}$ operations + \end{itemize} + \item For AES-256: + \begin{itemize} + \item Best known attack: $\approx 2^{254.4}$ operations + \item Far beyond capability of any conceivable computation + \end{itemize} + \item Asymptotic approach: Both are ``computationally secure'' + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Polynomial running time} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item In the asymptotic approach, we focus only on adversaries that run in polynomial time. + \item The security parameter $\lambda$ determines the level of security: + \begin{itemize} + \item Usually the length of secret keys in bits + \item All algorithms have access to $\lambda$ as a global variable + \item Example: AES-128 uses $\lambda = 128$, AES-256 uses $\lambda = 256$. (``256-bit security'') + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \definitionbox{Polynomial Running Time}{ + An algorithm runs in polynomial time if there is a polynomial $p$ such that the algorithm takes at most $O(p(n))$ steps on inputs of length $n$. + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Negligible functions} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Negligible Functions}{ + A function $f$ is negligible if it approaches zero faster than $1/p(\lambda)$, for every polynomial $p$. Formally: + \begin{itemize} + \item For every polynomial $p$, there exists $\lambda_0$ such that $f(\lambda) < 1/p(\lambda)$ for all $\lambda > \lambda_0$. + \item For every polynomial $p$, we have $p(\lambda) \in O(1/f(\lambda))$. + \end{itemize} + } + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{You can probably ignore the definition and just think about this intuitively:} + \item In cryptography, we want attack probabilities to be negligible in the security parameter $\lambda$. + \item Negligible probability: essentially zero for practical purposes when $\lambda$ is large enough. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Birthday paradox} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item In a classroom of 50 students, what's the probability that at least two share a birthday? + \begin{itemize} + \item 2\%? + \item 20\%? + \item 50\%? + \item 97\%? + \end{itemize} + \item Many people guess around 15-20\%, but the actual probability is about 97\%! + \item This is counterintuitive because \textbf{we're not looking for a specific birthday - we're looking for \textit{any} match among all possible pairs}. + \item With 50 students, we have $\binom{50}{2} = 1,225$ possible pairs to check!\footnote{$\binom{50}{2}$ is a binomial coefficient. It means: \textit{``how many ways can I choose two different items from a set of 50?''}} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Birthday paradox} + \begin{itemize}[<+->] + \item With just 23 people, probability exceeds 50\% + \item Formula for $n$ people: + \begin{align*} + P = 1 - \frac{365!}{(365-n)! \cdot 365^n} + \end{align*} + \item Implication: Finding collisions in a space of size $N$ happens with roughly $\sqrt{N}$ samples. + \item This is why many cryptographic systems need large output spaces! + \end{itemize} +\end{frame} + +\begin{frame}{Birthday probabilities} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item Many cryptographic algorithms fail if two executions sample the same random value. + \item General question: If we take $q$ independent uniform samples from a set of $N$ items, what's the probability some value is chosen more than once? + \item This probability is called $\func{birthday}{q,N}$ + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \begin{align*} + \func{birthday}{q,N} = 1 - \prod_{i=1}^{q-1} \left(1 - \frac{i}{N}\right) + \end{align*} + \begin{itemize}[<+->] + \item Surprisingly high probability! + \item With $q \approx 1.2\sqrt{N}$, probability $\approx 0.5$ + \item For birthdays: only need 23 people for $>50\%$ chance + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Indistinguishability in computational security} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \definitionbox{Indistinguishability}{ + Let \lib{}{1} and \lib{}{2} be two libraries with the same interface. The \textbf{advantage} of a calling program \prog{} in distinguishing \lib{}{1} and \lib{}{2} is: + \begin{align*} + \left| \prob{\prog{} \link \lib{}{1} \Rightarrow \texttt{true}} - \prob{\prog{} \link \lib{}{2} \Rightarrow \texttt{true}} \right| + \end{align*} + \lib{}{1} $\approxeq$ \lib{}{2}, if every polynomial-time calling program has only negligible advantage in distinguishing them. + } + \end{column} + \begin{column}{0.4\textwidth} + \begin{itemize}[<+->] + \item Previously, libraries were interchangeable when probabilities were \textbf{identical}. + \item Now, libraries are indistinguishable when probabilities are \textbf{negligibly close}. + \item Again: this is intuitive, no need to stress about the formal definition. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The ``bad event'' proof technique}{Definition} + \definitionbox{Bad Event Technique}{ + Let \lib{}{1} and \lib{}{2} be libraries that each include a boolean variable named \hl{\texttt{bad}}, and assume that after \texttt{bad} is set to \texttt{true} it remains \texttt{true} forever. We say that the bad event is triggered if the library ever sets \texttt{bad := true}. + \\[1em] + If \lib{}{1} and \lib{}{2} have identical source code, except for statements reachable only when \texttt{bad := true}, then: + \begin{align*} + \left| \prob{\prog{} \link \lib{}{1} \Rightarrow \texttt{true}} - \prob{\prog{} \link \lib{}{2} \Rightarrow \texttt{true}} \right| \leq \prob{\prog{} \link \lib{}{1} \func{trigger}{\texttt{bad}}} + \end{align*} + } +\end{frame} + +\begin{frame}{The ``bad event'' proof technique}{Key insights} + \begin{itemize}[<+->] + \item \prog{}'s advantage is bounded by \prob{\prog{} \link \lib{}{1} \func{trigger}{\texttt{bad}}}. + \item Practical application: + \begin{itemize}[<+->] + \item Define a sequence of hybrid libraries. + \item Identify ``bad events'' between consecutive hybrids. + \item Show these events occur with negligible probability. + \end{itemize} + \item Enables us to focus on analyzing specific failure cases rather than full behavior. + \end{itemize} +\end{frame} + +\begin{frame}{The ``bad event'' proof technique}{Example} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Are these libraries \textbf{computationally indistinguishable?} + \item Yes! Let's prove it use the bad event technique. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{}{1}{ + \sslibrarysubroutine{predict}{x}{ + $R \twoheadleftarrow \bits^\lambda$\\ + return $R == X$ + }{1} + }{1} + }{\overset{?}{\approxeq}}{ + \sslibrary{}{2}{ + \sslibrarysubroutine{predict}{x}{ + return \texttt{false} + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The ``bad event'' proof technique}{Example} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item Are these libraries \textbf{computationally indistinguishable?} + \item Yes! Let's prove it use the bad event technique. + \item Note: these libraries are interchangeable with \lib{}{1} and \lib{}{2} (as seen on next slide). + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{'}{1}{ + \sslibrarysubroutine{predict}{x}{ + $R \twoheadleftarrow \bits^\lambda$\\ + if $R == X$:\\ + \quad \hl{$\texttt{bad} \coloneq \texttt{true}$}\\ + \quad return \hl{\texttt{true}}\\ + return \texttt{false} + }{1} + }{1} + }{\overset{?}{\approxeq}}{ + \sslibrary{'}{2}{ + \sslibrarysubroutine{predict}{x}{ + $R \twoheadleftarrow \bits^\lambda$\\ + if $R == X$:\\ + \quad \hl{$\texttt{bad} \coloneq \texttt{true}$}\\ + \quad return \hl{\texttt{false}}\\ + return \texttt{false} + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The ``bad event'' proof technique}{Just to be clear} + \sslinked{ + \sslinked{ + \sslibrary{}{1}{ + \sslibrarysubroutine{predict}{x}{ + $R \twoheadleftarrow \bits^\lambda$\\ + return $R == X$ + }{1} + }{1} + }{\interchangeable{}}{ + \sslibrary{'}{1}{ + \sslibrarysubroutine{predict}{x}{ + $R \twoheadleftarrow \bits^\lambda$\\ + if $R == X$:\\ + \quad \hl{$\texttt{bad} \coloneq \texttt{true}$}\\ + \quad return \hl{\texttt{true}}\\ + return \texttt{false} + }{1} + }{1} + } + }{\overset{?}{\approxeq}}{ + \sslinked{ + \sslibrary{'}{2}{ + \sslibrarysubroutine{predict}{x}{ + $R \twoheadleftarrow \bits^\lambda$\\ + if $R == X$:\\ + \quad \hl{$\texttt{bad} \coloneq \texttt{true}$}\\ + \quad return \hl{\texttt{false}}\\ + return \texttt{false} + }{1} + }{1} + }{\interchangeable{}}{ + \sslibrary{}{2}{ + \sslibrarysubroutine{predict}{x}{ + return \texttt{false} + }{1} + }{1} + } + } +\end{frame} + +\begin{frame}{The ``bad event'' proof technique}{Example} + \begin{columns}[c] + \begin{column}{0.8\textwidth} + \begin{itemize} + \item We need to analyze how likely it is that the bad event happens: + \begin{itemize} + \item The bad event occurs when $R == X$. + \item Since $R$ is randomly chosen from a huge set, this match is extremely unlikely. + \item Even if an adversary makes many attempts, the chance of seeing this bad event remains tiny. + \item As we increase the security parameter $\lambda$, the chance becomes vanishingly small. + \end{itemize} + \item Therefore, the libraries are computationally indistinguishable! + \item For any \prog{}, computationally speaking, we'd get the same distribution of outputs. + \end{itemize} + \end{column} + \begin{column}{0.2\textwidth} + \sslinked{ + \sslibrary{'}{1}{ + \sslibrarysubroutine{predict}{x}{ + $R \twoheadleftarrow \bits^\lambda$\\ + if $R == X$:\\ + \quad \hl{$\texttt{bad} \coloneq \texttt{true}$}\\ + \quad return \hl{\texttt{true}}\\ + return \texttt{false} + }{1} + }{0.4} + }{\overset{?}{\approxeq}}{ + \sslibrary{'}{2}{ + \sslibrarysubroutine{predict}{x}{ + $R \twoheadleftarrow \bits^\lambda$\\ + if $R == X$:\\ + \quad \hl{$\texttt{bad} \coloneq \texttt{true}$}\\ + \quad return \hl{\texttt{false}}\\ + return \texttt{false} + }{1} + }{0.4} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The ``end-of-time'' strategy for bad events} + \begin{itemize}[<+->] + \item Sometimes analyzing bad events can be complex, especially when values are chosen by the adversary. + \item The end-of-time strategy: + \begin{enumerate}[<+->] + \item Postpone all bad-event logic to the end of the library execution. + \item Collect information during normal execution. + \item Check for bad events only at the very end. + \end{enumerate} + \item Advantages: + \begin{itemize}[<+->] + \item Simplifies analysis by separating normal behavior from bad-event checking. + \item Makes it easier to bound the probability of bad events. + \item Particularly useful for complex cryptographic proofs. + \end{itemize} + \item We'll use this in the next topic! + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/1-4.tex b/slides/1-4.tex new file mode 100644 index 0000000..fa61f5d --- /dev/null +++ b/slides/1-4.tex @@ -0,0 +1,2163 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 1: Provable Security} +\covertopicname{1.4: Pseudorandomness} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\section{Pseudorandom Generators} + +\begin{frame}{Limitations of One-Time Pad} + \definitionbox{The Key Length Problem}{ + One-time pad is not a particularly useful encryption scheme in practice. + } + \begin{itemize}[<+->] + \item The key must be as long as the plaintext! + \item This creates a chicken-and-egg situation: + \begin{itemize}[<+->] + \item To privately send $n$ bits of information, + \item We must already privately share $n$ bits of information. + \end{itemize} + \item Impractical for most real-world applications. + \begin{itemize}[<+->] + \item Clearly this is not what we're doing when we use HTTPS, + \item or WhatsApp, or pay for something via a debit card... + \end{itemize} + \item We need encryption schemes where the key can be smaller than the message. + \end{itemize} +\end{frame} + +\begin{frame}{Idea: find a way to expand the key} + \begin{itemize}[<+->] + \item Given a key $k_s$ of size $\left|k_s\right| < \left|m\right|$, find a way to obtain $\left|k_e\right| \geq \left|m\right|$ + \item In the real world, we have two kinds of symmetric encryption schemes: + \begin{itemize}[<+->] + \item \textbf{Block ciphers}: AES, 3DES, etc. + \item \textbf{Stream ciphers}: ChaCha20, RC4, etc. + \end{itemize} + \item This is exactly what stream ciphers do! + \begin{itemize}[<+->] + \item Start with a small key $k_s$ of a fixed size $\left|k_s\right| = \lambda$, + \item Magically expand it to $k_e$ where $\left|k_e\right| \geq \left|m\right|$, + \item $\func{enc}{K, M} = K \oplus M$ + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Requirements for Key Expansion} + \begin{itemize}[<+->] + \item Our method would need to be \textbf{deterministic}, so that both the sender and receiver can expand their key in the same way (to encrypt/decrypt). + \item Its output distribution would need to be \textbf{uniform}, since that is a crucial property for the security of OTP. + \item Unfortunately, it's \textbf{not possible} to achieve both of these properties simultaneously. + \begin{itemize}[<+->] + \item Suppose the expansion method is a deterministic function $G: \bits^n \rightarrow \bits^{n+\ell}$ + \item Its outputs are $\ell$ bits longer than its inputs! + \item There are $2^{n+\ell}$ strings of length $n+\ell$ but only (at most) $2^n$ possible outputs of $G$ + \item So the outputs of $G$ can never induce a uniform distribution. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Enter pseudorandomness} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item In cryptography, something is \textbf{pseudorandom} if it is indistinguishable from a uniform distribution.\footnote{The Oxford English Dictionary defines the prefix pseudo- as ``apparently but not really.''} + \item We need to invent some \textbf{``secure pseudorandom generator'' (PRG)} $G$ that takes a \textbf{seed} $S$ and ends up being indistinguishable from a true uniform distribution when thrown into a library: + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{}{prg-real}{ + \sslibrarysubroutine{prg.sample}{}{ + $S \twoheadleftarrow \bits^\lambda$\\ + return $G(S)$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{prg-rand}{ + \sslibrarysubroutine{prg.sample}{}{ + $Y \twoheadleftarrow \bits^{\lambda+\ell}$\\ + return $Y$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Enter pseudorandomness} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item In cryptography, something is \textbf{pseudorandom} if it is indistinguishable from a uniform distribution.\footnote{The Oxford English Dictionary defines the prefix pseudo- as ``apparently but not really.''} + \item We need to invent some \textbf{``secure pseudorandom generator'' (PRG)} $G$ that takes a \textbf{seed} $S$ and ends up being indistinguishable from a true uniform distribution when thrown into a library: + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{prg_distributions.pdf}{Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Enter pseudorandomness} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item We don't know how to make PRGs, or even if they exist. + \item So we simply invent functions that we think act close enough to PRGs (when subjected to statistical and mathematical analysis). + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{}{prg-real}{ + \sslibrarysubroutine{prg.sample}{}{ + $S \twoheadleftarrow \bits^\lambda$\\ + return $G(S)$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{prg-rand}{ + \sslibrarysubroutine{prg.sample}{}{ + $Y \twoheadleftarrow \bits^{\lambda+\ell}$\\ + return $Y$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{One-time secrecy of a SKE} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{One-time Secrecy for SKE}{ + An SKE scheme $\Sigma$ has one-time secrecy if the following libraries are interchangeable: + \vspace{0.5mm} + \begin{center} + \sslinked{ + \sslibrary{\Sigma}{ots-real}{ + \sslibrarysubroutine{ots.enc}{M}{ + $K \twoheadleftarrow \Sigma.\mathcal{K}$ \\ + $C \coloneq \Sigma.\textsf{Enc}(K, M)$ \\ + return $C$ + }{1} + }{0.8} + }{\interchangeable{}}{ + \sslibrary{\Sigma}{ots-rand}{ + \sslibrarysubroutine{ots.enc}{M}{ + $C \twoheadleftarrow \Sigma.\mathcal{C}$ \\ + return $C$ + }{1} + }{0.8} + } + \end{center} + } + \end{column} + \begin{column}{0.5\textwidth} + An encryption scheme has one-time secrecy if its ciphertexts are uniformly distributed, when keys are sampled uniformly, kept secret, and used for only one encryption, and no matter how the plaintexts are chosen. + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Does a PRG-based encryption scheme\\ have one-time secrecy?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + If: + \sslinked{ + \sslibrary{}{prg-real}{ + \sslibrarysubroutine{ots.enc}{}{ + $S \twoheadleftarrow \bits^\lambda$\\ + return $G(S)$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{prg-rand}{ + \sslibrarysubroutine{ots.enc}{}{ + $Y \twoheadleftarrow \bits^{\lambda+\ell}$\\ + return $Y$ + }{1} + }{1} + } + \end{column} + \begin{column}{0.5\textwidth} + Then: + \sslinked{ + \sslibrary{}{ots-real}{ + \sslibrarysubroutine{ots.enc}{M}{ + $K \twoheadleftarrow \bits^\lambda$ \\ + $Y \coloneq G(K)$ \\ + $C \coloneq Y \oplus M$ \\ + return $C$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{}{ots-rand}{ + \sslibrarysubroutine{ots.enc}{M}{ + $C \twoheadleftarrow \bits^{\lambda+\ell}$ \\ + return $C$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Attacking PRGs} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Assume that $G(S)$ is a secure PRG. + \item Is \func{h}{S} secure? + \end{itemize} + \sssubroutine{H}{S}{ + $A \| B \coloneq G(S)$ \\ + $C \| D \coloneq G(B)$ \\ + return $A \| B \| C \| D$ + }{1} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{H}{prg-real}{ + \sslibrarysubroutine{ots.enc}{}{ + $S \twoheadleftarrow \bits^\lambda$ \\ + $A \| B \coloneq G(S)$ \\ + $C \| D \coloneq G(B)$ \\ + return $A \| B \| C \| D$ + }{1} + }{1} + }{\overset{?}{\approxeq}}{ + \sslibrary{H}{prg-rand}{ + \sslibrarysubroutine{ots.enc}{M}{ + $Y \twoheadleftarrow \bits^{4\lambda}$ \\ + return $Y$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Attacking PRGs} + \begin{columns}[c] + \begin{column}{0.45\textwidth} + \begin{itemize}[<+->] + \item Assume that $G(S)$ is a secure PRG. + \item Is \func{h}{S} secure? + \item \textbf{No}: + \item \prob{\prog{}\link\lib{H}{prg-real} \Rightarrow \texttt{true}} $ = 1$ + \end{itemize} + \end{column} + \begin{column}{0.55\textwidth} + \begin{flushright} + \sslinked{ + \ssprogram{}{ + $A \| B \| C \| D \coloneq \func{ots.enc}{}$ \\ + return $G(B) == C \| D$ + }{0.9} + }{\link}{ + \sslibrary{H}{prg-real}{ + \sslibrarysubroutine{ots.enc}{}{ + $S \twoheadleftarrow \bits^\lambda$ \\ + $A \| B \coloneq G(S)$ \\ + $C \| D \coloneq G(B)$ \\ + return $A \| B \| C \| D$ + }{1} + }{0.9} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Attacking PRGs} + \begin{columns}[c] + \begin{column}{0.45\textwidth} + \begin{itemize} + \item<1-3> Assume that $G(S)$ is a secure PRG. + \item<1-3> Is \func{h}{S} secure? + \item<1-3> \textbf{No}: + \item<1-3> \prob{\prog{}\link\lib{H}{prg-real} \Rightarrow \texttt{true}} $ = 1$ + \item<2-3> \prob{\prog{}\link\lib{H}{prg-rand} \Rightarrow \texttt{true}} $ = \frac{1}{2^{2\lambda}}$ + \item<3> Difference certainly not negligible. + \end{itemize} + \end{column} + \begin{column}{0.55\textwidth} + \begin{flushright} + \sslinked{ + \ssprogram{}{ + $A \| B \| C \| D \coloneq \func{ots.enc}{}$ \\ + return $G(B) == C \| D$ + }{0.9} + }{\link}{ + \sslibrary{H}{prg-rand}{ + \sslibrarysubroutine{ots.enc}{M}{ + $Y \twoheadleftarrow \bits^{4\lambda}$ \\ + return $Y$ + }{1} + }{0.9} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Example: RC4 (a stream cipher)} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item Used in WEP, SSL/TLS, and other protocols. + \item Simple PRG that takes a seed and produces a keystream. + \item Basic operation: + \begin{itemize}[<+->] + \item Initialize S-box with permutation of bytes 0-255. + \item Use key to scramble the S-box. + \item Generate pseudorandom bytes iteratively. + \end{itemize} + \item Several weaknesses found over time: + \begin{itemize}[<+->] + \item Statistical biases in initial output. + \item Correlation between key and output bytes. + \item Considered cryptographically broken today. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \alertbox{Security Warning}{ + RC4 is presented as a historical example only. It should not be used in new applications due to known weaknesses. Modern alternatives include ChaCha20. + } + \vspace{1em} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}[fragile]{RC4 PRG Algorithm} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \begin{itemize}[<+->] + \item RC4 generates a pseudorandom stream of bytes used to encrypt data. + \item After key setup (which initializes array S), the algorithm produces keystream bytes: + \item Each output byte requires simple operations: + \begin{itemize}[<+->] + \item Array index calculations. + \item Array value swapping. + \item Modular addition. + \end{itemize} + \item Fast implementation in software. + \item Despite simplicity, it has several cryptographic weaknesses. + \end{itemize} + \end{column} + \begin{column}{0.45\textwidth} + \imagewithcaption{rc4_prga_py.png}{RC4 PRG implementation in Python.} + \end{column} + \end{columns} +\end{frame} + +\section{Pseudorandom Functions} + +\begin{frame}{Pseudorandom function: definition} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Pseudorandom Function (PRF)}{ + A function $F: \bits^\lambda \times \bits^n \rightarrow \bits^m$ is a secure pseudorandom function (PRF) if the following two libraries are indistinguishable: + } + \begin{itemize} + \item $n$ the input length of the PRF. + \item $m$ the output length of the PRF. + \item $\lambda$ is the key size and hence the security parameter. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{F}{prf-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + return $F(K, X)$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{F}{prf-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + if $L[X]$ undefined:\\ + \quad $L[X] \twoheadleftarrow \bits^m$\\ + return $L[X]$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{PRG vs PRF: Key Differences} + \begin{columns}[t] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{PRG (Pseudorandom Generator)}: + \begin{itemize}[<+->] + \item Takes short seed, produces longer output + \item Generates entire output as a monolithic string + \item $G: \bits^\lambda \rightarrow \bits^{\lambda+\ell}$ + \end{itemize} + \end{itemize} + \begin{center} + \sslibrary{F}{prf-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + if $L[X]$ undefined:\\ + \quad $L[X] \twoheadleftarrow \bits^m$\\ + return $L[X]$ + }{1} + }{0.7} + \end{center} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{PRF (Pseudorandom Function)}: + \begin{itemize}[<+->] + \item Maps inputs to pseudorandom outputs + \item Provides access to individual blocks of output + \item Can generate output for any input on demand + \item $F: \bits^\lambda \times \bits^n \rightarrow \bits^m$ + \end{itemize} + \item PRFs enable ``selective access'' to pseudorandom values without generating the entire sequence + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{$\mathsf{PRF}: F_{k}= X \rightarrow Y$} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item We want the mapping to be: + \begin{itemize} + \item One-way + \item ``Randomized'' + \item Relations between inputs not reflected in outputs + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.8\textwidth} + \begin{tikzpicture}[scale=0.38] + % Define colors + \definecolor{domaingreen}{RGB}{102, 170, 68} + \definecolor{rangegreen}{RGB}{170, 187, 136} + \definecolor{circlecolor}{RGB}{235, 137, 85} + \definecolor{purplearrow}{RGB}{160, 78, 160} + \definecolor{redarrow}{RGB}{237, 50, 36} + + % Input space (domain) X - made square + \draw[dashed, thick, domaingreen, fill=domaingreen] + (0,0) rectangle (8,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (4,-0.8) + {Size: infinite!}; + \node[font=\small] at (4,9) {Input space (domain) $X$}; + + % Output (range) Y - made square - moved more to the right + \draw[thick, rangegreen, fill=rangegreen] (15,2) rectangle (20,7); + \node[text width=4cm, align=center, font=\normalsize] + at + (17.5,1.2) + {Size: fixed}; + \node[font=\small] at (17.5,8.5) {Output (range) $Y$}; + % Input dots - adjusted positions for square domain + \filldraw[circlecolor] (2,7) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,7) -- (16.2,6.4); + \pause + \filldraw[circlecolor] (16.2,6.4) circle (0.3); + \pause + + \filldraw[circlecolor] (3,6) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,6) -- (18.6,5.3); + \pause + \filldraw[circlecolor] (18.6,5.3) circle (0.3); + \pause + + \filldraw[circlecolor] (2,5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,5) -- (16.8,4.2); + \pause + \filldraw[circlecolor] (16.8,4.2) circle (0.3); + \pause + + \filldraw[circlecolor] (4,3.5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (4,3.5) -- (18.4,3.2); + \pause + \filldraw[circlecolor] (18.4,3.2) circle (0.3); + \pause + + \filldraw[circlecolor] (2,2) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,2) -- (17.1,2.7); + \pause + \filldraw[circlecolor] (17.1,2.7) circle (0.3); + \pause + + \filldraw[circlecolor] (3,1) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, ultra thick, redarrow] + (3,1) -- (16.8,4.2); + \node[redarrow, font=\scriptsize\bfseries, rotate=14] + at + (10,3) + {Collisions are inevitable}; + \end{tikzpicture} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{PRFs in the real world: hash functions} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \definitionbox{Hash Function Properties}{ + \begin{itemize}\item Takes input of \textbf{any size} + \item Produces output of \textbf{fixed size} + \item Is \textbf{deterministic} (same input $\rightarrow$ same output) + \item Even a \textbf{tiny change} in input creates completely different output + \item Is \textbf{efficient} to compute\end{itemize} + } + \end{column} + \begin{column}{0.45\textwidth} + \begin{tcolorbox} + [colback=black!5!white,colframe=ciphergray] $\mathsf{SHA256}(\texttt{hello}) =$ \\ \texttt{2cf24dba5fb0a30e26e83b2ac5}\\ \texttt{b9e29e1b161e5c1fa7425e7304}\\ + \texttt{3362938b9824} + + $\mathsf{SHA256}(\texttt{hullo}) =$ \\ \texttt{7835066a1457504217688c8f5d}\\ + \texttt{06909c6591e0ca78c254ccf174}\\ \texttt{50d0d999cab0} + \end{tcolorbox} + \textcolor{cipherprimary}{\textbf{Note:} \small One character change $\rightarrow$ + completely different hash!} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Expected properties of a hash function} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize} + \item \textbf{Collision resistance}: computationally infeasible to find + two different inputs producing the same hash. + \item \textbf{Preimage resistance}: given the output of a hash function, + it is computationally infeasible to reconstruct the original input. + \item \textbf{Second preimage resistance}: given an input and an output, + it's computationally infeasible to find another different input + producing the same output. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{sha2.png}{SHA-2 compression function. Source: Wikipedia} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Hash functions: what are they good for?} + \begin{itemize}[<+->] + \item \textbf{Password storage}: Store the hash of the password on the server, + not the password itself. Then check candidate passwords against the hash. + \item \textbf{Data integrity verification}: Hash a file. Later hash it + again and compare hashes to check if the file has changed, suffered storage + degradation, etc. + \item \textbf{Proof of work}: Server asks client to hash something a lot of + times before they can access some resource. Useful for anti-spam, Bitcoin + mining, etc. + \end{itemize} +\end{frame} + +\begin{frame}{An insecure PRF construction} + \begin{columns}[c] + \begin{column}{0.45\textwidth} + \definitionbox{Claim: An Insecure PRF}{ + The function $F(K, X) = G(K) \oplus X$ is not a secure PRF, even if $G$ is a secure PRG. + } + \begin{itemize}[<+->] + \item This construction fails because: + \begin{itemize}[<+->] + \item The key $K$ is only fed through the PRG once. + \item The same value $G(K)$ is used for all queries. + \item This creates exploitable patterns in outputs. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.55\textwidth} + \begin{center} + \sslinked{ + \sslibrary{F}{prf-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + return $G(K) \oplus X$ + }{1} + }{1} + }{\cancel{\approxeq}}{ + \sslibrary{F}{prf-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + if $L[X]$ undefined:\\ + \quad $L[X] \twoheadleftarrow \bits^m$\\ + return $L[X]$ + }{1} + }{1} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{An insecure PRF construction} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item When an adversary sees two outputs: + \begin{align*} + Y_1 & = G(K) \oplus X_1 \\ + Y_2 & = G(K) \oplus X_2 + \end{align*} + \item Taking $Y_1 \oplus Y_2$ causes $G(K)$ to cancel: + \begin{align*} + Y_1 \oplus Y_2 & = G(K) \oplus X_1 \oplus G(K) \oplus X_2 \\ + & = X_1 \oplus X_2 + \end{align*} + \item In a truly random function, $Y_1 \oplus Y_2 = X_1 \oplus X_2$ would be extremely unlikely! + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \begin{center} + \sslinked{ + \sslibrary{F}{prf-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + return $G(K) \oplus X$ + }{1} + }{0.7} + }{\cancel{\approxeq}}{ + \sslibrary{F}{prf-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + if $L[X]$ undefined:\\ + \quad $L[X] \twoheadleftarrow \bits^m$\\ + return $L[X]$ + }{1} + }{0.7} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Another insecure PRF construction} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Claim: Another Insecure PRF}{ + The function $H(K_1 \| K_2, X_1 \| X_2) = F(K_1, X_1) \oplus F(K_2, X_2)$ is not a secure PRF, even if $F$ is a secure PRF. + } + \begin{itemize}[<+->] + \item An unsuccessful attempt to use a PRF with shorter input length to build one with a larger input length. + \end{itemize} + \end{column} + \begin{column}{0.55\textwidth} + \begin{center} + \sslinked{ + \sslibrary{H}{prf-real}{ + $K_1 \| K_2 \twoheadleftarrow \bits^{2\lambda}$\\[1em] + \sslibrarysubroutine{prf.query}{X_1 \| X_2}{ + return $F(K_1, X_1) \oplus F(K_2, X_2)$ + }{1} + }{0.7} + }{\cancel{\approxeq}}{ + \sslibrary{H}{prf-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prf.query}{X_1 \| X_2}{ + if $L[X_1 \| X_2]$ undefined:\\ + \quad $L[X_1 \| X_2] \twoheadleftarrow \bits^m$\\ + return $L[X_1 \| X_2]$ + }{1} + }{0.7} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Why the previous PRF is broken} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item When inputs share the same first half, the corresponding outputs of $H$ have a common term $F(K_1, X_1)$ + \item Consider querying four inputs: $A\|B$, $A\|B'$, $A'\|B$, $A'\|B'$ (where $A \neq A'$ and $B \neq B'$) + \begin{align*} + Y_1 & = F(K_1, A) \oplus F(K_2, B) \\ + Y_2 & = F(K_1, A) \oplus F(K_2, B') \\ + Y_3 & = F(K_1, A') \oplus F(K_2, B) \\ + Y_4 & = F(K_1, A') \oplus F(K_2, B') + \end{align*} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item If we XOR $Y_1 \oplus Y_2$, the $F(K_1, A)$ terms cancel out. + \item Similarly, $Y_3 \oplus Y_4$ causes $F(K_1, A')$ to cancel: + \begin{itemize} + \item $Y_1 \oplus Y_2 = F(K_2, B) \oplus F(K_2, B')$ + \item $Y_3 \oplus Y_4 = F(K_2, B) \oplus F(K_2, B')$ + \end{itemize} + \item So $\prob{Y_1 \oplus Y_2 == Y_3 \oplus Y_4} = 1$ + \item With a truly random function, $\prob{Y_1 \oplus Y_2 == Y_3 \oplus Y_4} = \frac{1}{2^m}$ (extremely unlikely!) + \item Also, Given $Y_{1\cdots3}$, we can predict $Y_4$! + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The Golden Rule of PRFs} + \definitionbox{The Golden Rule of PRFs}{ + If a PRF $F$ is being used as a component in a larger construction $H$, then security usually rests on how well $H$ can ensure distinct inputs to $F$. + } + \begin{itemize}[<+->] + \item When analyzing PRF security, focus on input uniqueness. + \item Repeated inputs to a PRF create exploitable patterns. + \item Even if $F$ is secure, $H$ can be broken if it causes $F$ to receive duplicate inputs. + \item Don't try to directly distinguish $F$'s outputs from uniform. + \item Instead, exploit how $H$ uses $F$ incorrectly. + \item Find input patterns that force collisions within $F$. + \end{itemize} +\end{frame} + +\section{Pseudorandom Permutations} + +\begin{frame}{What is a permutation?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Permutation}{ + A permutation is a rearrangement where each input value maps to exactly one output value, and each possible output appears exactly once. + } + \begin{itemize}[<+->] + \item Permutations rearrange elements rather than transforming them. + \item Every element in the domain appears exactly once in the range. + \item The function is invertible. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Example}: simple substitution cipher. Each letter maps to another letter: + \begin{align*} + a & \mapsto g,\quad b \mapsto a,\quad c \mapsto r \\ + d & \mapsto b,\quad e \mapsto l,\quad \ldots + \end{align*} + \item Under this permutation: + \begin{itemize} + \item ``cabbage'' $\mapsto$ ``rgaagdl'' + \item ``rgaagdl'' $\mapsto$ ``cabbage'' + \end{itemize} + \item This mapping is reversible because it's a permutation over $\{a,\ldots,z\}$. + \item Each letter appears exactly once in the output alphabet. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{PRF versus PRP} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Pseudo-Random Function (SHA-2)} + \begin{itemize}[<+->] + \item \textbf{Input} is arbitrary-length, + \item \textbf{Output} is fixed-length, looks random (as discussed + earlier). + \item Indistinguishable from a truly random function by an adversary with + limited computational power. + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \textbf{Pseudo-Random Permutation (AES)} + \begin{itemize}[<+->] + \item \textbf{Input and output} are the same length, forming a permutation. + \item Each input maps uniquely to one output, allowing invertibility. + \item Indistinguishable from a truly random permutation by an adversary + with limited computational power. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{PRPs compared to PRFs} + \begin{itemize}[<+->] + \item \textbf{Invertibility}: PRPs can be efficiently inverted given the key + \begin{itemize}[<+->] + \item Enable both encryption and decryption + \item Can recover input from output (and vice versa) + \end{itemize} + \item \textbf{No range collision}: Each input maps to a unique output + \begin{itemize}[<+->] + \item Provides perfect input recovery + \item Reduces vulnerability to collision-based attacks, birthday attacks, and certain forms of differential cryptanalysis + \end{itemize} + \item \textbf{Versatility}: A secure PRP can be used as a PRF + \begin{itemize}[<+->] + \item ``Downgrade'' trivially by ignoring inverse capability + \item The reverse is not true (PRF → PRP conversion is complex) + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{$\mathsf{PRF}: F_{k}= X \rightarrow Y$} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item We want the mapping to be: + \begin{itemize} + \item One-way + \item ``Randomized'' + \item Relations between inputs not reflected in outputs + \end{itemize} + \end{itemize} + \end{column} + + \begin{column}{0.8\textwidth} + \begin{tikzpicture}[scale=0.38] + % Define colors + \definecolor{domaingreen}{RGB}{102, 170, 68} + \definecolor{rangegreen}{RGB}{170, 187, 136} + \definecolor{circlecolor}{RGB}{235, 137, 85} + \definecolor{purplearrow}{RGB}{160, 78, 160} + \definecolor{redarrow}{RGB}{237, 50, 36} + + % Input space (domain) X - made square + \draw[dashed, thick, domaingreen, fill=domaingreen] + (0,0) rectangle (8,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (4,-0.8) + {Size: infinite!}; + \node[font=\small] at (4,9) {Input space (domain) $X$}; + + % Output (range) Y - made square - moved more to the right + \draw[thick, rangegreen, fill=rangegreen] (15,2) rectangle (20,7); + \node[text width=4cm, align=center, font=\normalsize] + at + (17.5,1.2) + {Size: fixed}; + \node[font=\small] at (17.5,8.5) {Output (range) $Y$}; + % Input dots - adjusted positions for square domain + \filldraw[circlecolor] (2,7) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,7) -- (16.2,6.4); + \pause + \filldraw[circlecolor] (16.2,6.4) circle (0.3); + \pause + + \filldraw[circlecolor] (3,6) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,6) -- (18.6,5.3); + \pause + \filldraw[circlecolor] (18.6,5.3) circle (0.3); + \pause + + \filldraw[circlecolor] (2,5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,5) -- (16.8,4.2); + \pause + \filldraw[circlecolor] (16.8,4.2) circle (0.3); + \pause + + \filldraw[circlecolor] (4,3.5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (4,3.5) -- (18.4,3.2); + \pause + \filldraw[circlecolor] (18.4,3.2) circle (0.3); + \pause + + \filldraw[circlecolor] (2,2) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,2) -- (17.1,2.7); + \pause + \filldraw[circlecolor] (17.1,2.7) circle (0.3); + \pause + + \filldraw[circlecolor] (3,1) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, ultra thick, redarrow] + (3,1) -- (16.8,4.2); + \node[redarrow, font=\scriptsize\bfseries, rotate=14] + at + (10,3) + {Collisions are inevitable}; + \end{tikzpicture} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{$\mathsf{PRP}: F_{k}= X \rightarrow X$} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item \textbf{Bijective} (two-way) + \begin{itemize} + \item \textbf{Injective}: no two inputs map to same output (no + collisions) + \item \textbf{Surjective}: Every output has one corresponding input + \end{itemize} + \item ``Randomized'' + \item Relations between inputs not reflected in outputs + \end{itemize} + \end{column} + + \begin{column}{0.8\textwidth} + \begin{tikzpicture}[scale=0.38] + % Define colors + \definecolor{domaingreen}{RGB}{102, 170, 68} + \definecolor{rangegreen}{RGB}{102, 170, 68} + \definecolor{circlecolor}{RGB}{235, 137, 85} + \definecolor{purplearrow}{RGB}{160, 78, 160} + + % Input space (domain) X - made square + \draw[dashed, thick, domaingreen, fill=domaingreen] + (0,0) rectangle (8,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (4,-0.8) + {Size: fixed}; + \node[font=\normalsize] at (4,9) {Input space (domain) $X$}; + + % Output (range) Y - made square, same size as domain, moved left + \draw[thick, rangegreen, fill=rangegreen] (12,0) rectangle (20,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (16,-0.8) + {Size: fixed}; + \node[font=\normalsize] at (16,9) {Output (range) $X$}; + % Input dots - adjusted positions for square domain + \filldraw[circlecolor] (2,7) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,7) -- (14.2,7.4); + \pause + \filldraw[circlecolor] (14.2,7.4) circle (0.3); + \pause + + \filldraw[circlecolor] (3,6) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,6) -- (18.6,5.3); + \pause + \filldraw[circlecolor] (18.6,5.3) circle (0.3); + \pause + + \filldraw[circlecolor] (2,5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,5) -- (13.8,4.2); + \pause + \filldraw[circlecolor] (13.8,4.2) circle (0.3); + \pause + + \filldraw[circlecolor] (4,3.5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (4,3.5) -- (17.4,2.2); + \pause + \filldraw[circlecolor] (17.4,2.2) circle (0.3); + \pause + + \filldraw[circlecolor] (2,2) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,2) -- (16.1,6.7); + \pause + \filldraw[circlecolor] (16.1,6.7) circle (0.3); + \pause + + \filldraw[circlecolor] (3,1) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,1) -- (19.0,1.4); + \pause + \filldraw[circlecolor] (19.0,1.4) circle (0.3); + \end{tikzpicture} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{``Lazy dictionaries'' versus ``lazy permutations''}{Ideal PRF versus ideal PRP} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{F}{prf-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + if $L[X]$ undefined:\\ + \quad $L[X] \twoheadleftarrow \bits^m$\\ + return $L[X]$ + }{1} + }{1} + \end{center} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{F}{prp-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prp.query}{X}{ + if $L[X]$ undefined:\\ + \quad $Y \twoheadleftarrow \bits^n \ \setminus \ \mathcal{y}$\\ + \quad $\mathcal{y} \coloneq \mathcal{y} \cup \{Y\}$\\ + \quad $L[X] \coloneq Y$\\ + return $L[X]$ + }{1} + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{``Lazy dictionaries'' versus ``lazy permutations''} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item While the PRF (on the left) just picks random outputs for each input... + \item The PRP (on the right) must ensure outputs are never repeated: + \begin{itemize}[<+->] + \item $\mathcal{y}$ tracks all outputs used so far + \item $\setminus$ means ``set difference'' - pick from values not in $\mathcal{y}$ + \item $\cup$ means ``set union'' - add the new value to $\mathcal{y}$ + \end{itemize} + \item This ensures each output appears exactly once - the definition of a permutation + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{F}{prp-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prp.query}{X}{ + if $L[X]$ undefined:\\ + \quad $Y \twoheadleftarrow \bits^n \ \setminus \ \mathcal{y}$\\ + \quad $\mathcal{y} \coloneq \mathcal{y} \cup \{Y\}$\\ + \quad $L[X] \coloneq Y$\\ + return $L[X]$ + }{1} + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Pseudorandom function: definition} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Pseudorandom Function (PRF)}{ + A function $F: \bits^\lambda \times \bits^n \rightarrow \bits^m$ is a secure pseudorandom function (PRF) if the following two libraries are indistinguishable: + } + \begin{itemize} + \item $n$ the input length of the PRF. + \item $m$ the output length of the PRF. + \item $\lambda$ is the key size and hence the security parameter. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{F}{prf-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + return $F(K, X)$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{F}{prf-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prf.query}{X}{ + if $L[X]$ undefined:\\ + \quad $L[X] \twoheadleftarrow \bits^m$\\ + return $L[X]$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Pseudorandom permutation: definition} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Pseudorandom Permutation (PRP)}{ + A keyed permutation $F^{\pm}$ is a secure pseudorandom permutation (PRP) if the following two libraries are indistinguishable: + } + \begin{itemize}[<+->] + \item $n$ the input length of the PRP. Also the output length! + \item $\lambda$ is the key size and hence the security parameter. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{F}{prp-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{prp.query}{X}{ + return $F(K, X)$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{F}{prp-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prp.query}{X}{ + if $L[X]$ undefined:\\ + \quad $Y \twoheadleftarrow \bits^n \ \setminus \ \mathcal{y}$\\ + \quad $\mathcal{y} \coloneq \mathcal{y} \cup \{Y\}$\\ + \quad $L[X] \coloneq Y$\\ + return $L[X]$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Pseudorandom permutation: definition} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Pseudorandom Permutation (PRP)}{ + A keyed permutation $F^{\pm}$ is a secure pseudorandom permutation (PRP) if the following two libraries are indistinguishable: + } + \begin{itemize}[<+->] + \item We obviously can't use \lib{F}{prp-rand} in the real world. + \item It doesn't scale. So we need practical approximative alternatives. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{F}{prp-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{prp.query}{X}{ + return $F(K, X)$ + }{1} + }{1} + }{\approxeq}{ + \sslibrary{F}{prp-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{prp.query}{X}{ + if $L[X]$ undefined:\\ + \quad $Y \twoheadleftarrow \bits^n \ \setminus \ \mathcal{y}$\\ + \quad $\mathcal{y} \coloneq \mathcal{y} \cup \{Y\}$\\ + \quad $L[X] \coloneq Y$\\ + return $L[X]$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Building a permutation through Feistel ciphers} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item An $r$-round \textbf{Feistel cipher} with \textbf{round functions} $F_1,\ldots,F_r$ is defined as follows:\\ + \begin{center} + \sssubroutine{$\mathbb{F}$}{X_{0}\|X_{1}}{ + for $i = 1$ to $r$:\\ + \quad $X_{i+1} \coloneq X_{i-1} \oplus F_{i}(X_{i})$\\ + return $X_{r}\|X_{r+1}$ + }{1} + \end{center} + \item A Feistel cipher is always a permutation on $\bits^{2n}$, regardless of its round functions. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{feistel_cipher.pdf}{Feistel cipher.\\Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Building a permutation through Feistel ciphers} + \definitionbox{Feistel Ciphers Are Permutations}{ + A Feistel cipher is always a permutation on $\bits^{2n}$, regardless of its round functions. + } + \begin{itemize}[<+->] + \item \textbf{Proof:} Each round of a Feistel cipher computes the next block as: + \begin{itemize}[<+->] + \item $X_{i+1} = X_{i-1} \oplus F_{i}(X_{i})$ + \end{itemize} + \item To invert this round, we can rearrange the equation to solve for $X_{i-1}$ in terms of $X_{i}$ and $X_{i+1}$: + \begin{itemize}[<+->] + \item $X_{i-1} = X_{i+1} \oplus F_{i}(X_{i})$ + \end{itemize} + \item $F_i$ itself does not need to have an inverse - both the forward and inverse direction of the Feistel cipher evaluate $F_i$ in the forward direction! $\qed$ + \end{itemize} +\end{frame} + +\begin{frame}{Building a permutation through Feistel ciphers}{Inversion} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item $\mathbb{F}^{-1}$ is the \textbf{inversion}, allowing Feistel ciphers to function as PRPs: + \begin{center} + \sssubroutine{$\mathbb{F}^{-1}$}{X_{r}\|X_{r+1}}{ + for $i = r$ \hl{down to} $1$:\\ + \quad $X_{i-1} \coloneq X_{i+1} \oplus F_{i}(X_{i})$\\ + return $X_{0}\|X_{1}$ + }{1} + \end{center} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{feistel_cipher_inv.pdf}{Feistel cipher inversion.\\Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Forward and backward on one slide}{Just in case it's helpful} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{center} + \sssubroutine{$\mathbb{F}$}{X_{0}\|X_{1}}{ + for $i = 1$ to $r$:\\ + \quad $X_{i+1} \coloneq X_{i-1} \oplus F_{i}(X_{i})$\\ + return $X_{r}\|X_{r+1}$ + }{1.2} + \end{center} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sssubroutine{$\mathbb{F}^{-1}$}{X_{r}\|X_{r+1}}{ + for $i = r$ down to $1$:\\ + \quad $X_{i-1} \coloneq X_{i+1} \oplus F_{i}(X_{i})$\\ + return $X_{0}\|X_{1}$ + }{1.2} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Keyed Feistel ciphers} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item Let's add a key in there. Wow, encryption! + \item $K_{1\cdots i}$ called is the \textbf{key schedule}. + \item If each round function $F_i$ uses a distinct key $K_i$, it increases the security of the Feistel network against certain attacks. + \item By using a PRF as round function $F_i$, the security of the Feistel cipher would be grounded on the PRF's security basis. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \begin{center} + \sssubroutine{$\mathbb{F}$}{K_1\|\cdots\|K_r,\ X_0\|X_1}{ + for $i = 1$ to $r$:\\ + \quad $X_{i+1} \coloneq X_{i-1} \oplus F_{i}(K_{i}, X_{i})$\\ + return $X_{r}\|X_{r+1}$ + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Meet-in-the-middle attacks on Feistel ciphers}{Why use a key schedule and not the same key?} + \begin{columns}[c] + \begin{column}{0.65\textwidth} + \begin{itemize}[<+->] + \item Using the \textbf{same key} for all rounds creates significant vulnerabilities. + \item A meet-in-the-middle attack can break an $r$-round Feistel cipher with complexity $> \frac{2^{|K|}}{2}$. + \item The attack works by computing partial encryptions from both ends: + \begin{enumerate}[<+->] + \item Forward: Compute halfway through encryption. + \item Backward: Compute halfway through decryption. + \item Look for ``meeting points'' in the middle. + \end{enumerate} + \item With identical round functions, effective security may be only \textbf{half} the number of rounds. + \end{itemize} + \end{column} + \begin{column}{0.35\textwidth} + \begin{center} + \sssubroutine{$\mathbb{F}$}{K,\ X_0\|X_1}{ + for $i = 1$ to $r$:\\ + \quad $X_{i+1} \coloneq X_{i-1} \oplus F(K, X_{i})$\\ + return $X_{r}\|X_{r+1}$ + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Breaking a 2-round Feistel cipher} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{A 2-round Feistel cipher cannot be a secure PRP.} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sssubroutine{$\mathbb{F}$}{K_1\|K_2,\ X_0\|X_1}{ + $X_{2} \coloneq X_{0} \oplus F(K_1, X_1)$\\ + $X_{3} \coloneq X_{1} \oplus F(K_2, X_2)$\\ + return $X_{2}\|X_{3}$ + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Breaking a 2-round Feistel cipher} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize}[<+->] + \item Once again, real or random? + \item We can indeed produce an adversary \prog{} that can distinguish between these two libraries. + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{center} + \sslinked{ + \sslibrary{\mathbb{F}}{prp-real}{ + $K_1\|K_2 \twoheadleftarrow \bits^{2\lambda}$\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + $X_{2} \coloneq X_{0} \oplus F(K_1, X_1)$\\ + $X_{3} \coloneq X_{1} \oplus F(K_2, X_2)$\\ + return $X_{2}\|X_{3}$ + }{1} + }{0.8} + }{\cancel{\approxeq}}{ + \sslibrary{\mathbb{F}}{prp-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X}{ + if $L[X]$ undefined:\\ + \quad $Y \twoheadleftarrow \bits^n \ \setminus \ \mathcal{y}$\\ + \quad $\mathcal{y} \coloneq \mathcal{y} \cup \{Y\}$\\ + \quad $L[X] \coloneq Y$\\ + return $L[X]$ + }{1} + }{0.8} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Breaking a 2-round Feistel cipher} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize}[<+->] + \item Let's query $(A \| B)$ and $(A' \| B)$ where $A \neq A'$ + \begin{itemize} + \item $Y_1 \| Y_2 = \func{prp.query}{A \| B}$ + \item $Y_1' \| Y_2' = \func{prp.query}{A' \| B}$ + \end{itemize} + \item In a 2-round Feistel cipher: + \begin{itemize} + \item $Y_1 = A \oplus F(K_1, B)$ + \item $Y_1' = A' \oplus F(K_1, B)$ + \item $Y_1 \oplus Y_1' = A \oplus A'$ + \end{itemize} + \item In a true PRP, \prob{Y_1 \oplus Y_1' == A \oplus A'} is negligible + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{center} + \sslinked{ + \ssprogram{}{ + $Y_1\|Y_2 = \func{prp.query}{A\|B}$\\ + $Y^{'}_1\|Y^{'}_2 = \func{prp.query}{A^{'}\|B}$\\ + return $Y_1 \oplus Y^{'}_1 == A \oplus A^{'}$ + }{0.8} + }{\link}{ + \sslibrary{\mathbb{F}}{prp-real}{ + $K_1\|K_2 \twoheadleftarrow \bits^{2\lambda}$\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + $X_{2} \coloneq X_{0} \oplus F(K_1, X_1)$\\ + $X_{3} \coloneq X_{1} \oplus F(K_2, X_2)$\\ + return $X_{2}\|X_{3}$ + }{1} + }{0.8} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{However, a 3+ round Feistel cipher is fine!} + \begin{center} + \sslinked{ + \sslinked{ + \ssprogram{}{ + $Y_1\|Y_2 = \func{prp.query}{A\|B}$\\ + $Y^{'}_1\|Y^{'}_2 = \func{prp.query}{A^{'}\|B}$\\ + return $Y_1 \oplus Y^{'}_1 == A \oplus A^{'}$ + }{0.7} + }{\link}{ + \sslibrary{\mathbb{F}}{prp-real}{ + $K_1\|K_2 \twoheadleftarrow \bits^{2\lambda}$\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + $X_{2} \coloneq X_{0} \oplus F(K_1, X_1)$\\ + $X_{3} \coloneq X_{1} \oplus F(K_2, X_2)$\\ + return $X_{2}\|X_{3}$ + }{1} + }{0.7} + } + }{\cancel{\approxeq}}{ + \sslinked{ + \ssprogram{}{ + $Y_1\|Y_2 = \func{prp.query}{A\|B}$\\ + $Y^{'}_1\|Y^{'}_2 = \func{prp.query}{A^{'}\|B}$\\ + return $Y_1 \oplus Y^{'}_1 == A \oplus A^{'}$ + }{0.7} + }{\link}{ + \sslibrary{\mathbb{F}}{prp-real}{ + $K_1\|K_2\|K_3 \twoheadleftarrow \bits^{3\lambda}$\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + $X_{2} \coloneq X_{0} \oplus F(K_1, X_1)$\\ + $X_{3} \coloneq X_{1} \oplus F(K_2, X_2)$\\ + $X_{4} \coloneq X_{2} \oplus F(K_3, X_3)$\\ + return $X_{3}\|X_{4}$ + }{1} + }{0.7} + } + } + \end{center} +\end{frame} + +\begin{frame}{However, a 3+ round Feistel cipher is fine!} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize}[<+->] + \item Luby and Rackoff proved that a 3-round Feistel cipher is indistinguishable from a pseudorandom permutation.\footnote{\url{https://appliedcryptography.page/papers/luby-rackoff.pdf}} + \item Can we also prove it using our provable security framework? + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{center} + \sslinked{ + \sslibrary{\mathbb{F}}{prp-real}{ + $K_1\|K_2\|K_3 \twoheadleftarrow \bits^{3\lambda}$\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + $X_{2} \coloneq X_{0} \oplus F(K_1, X_1)$\\ + $X_{3} \coloneq X_{1} \oplus F(K_2, X_2)$\\ + $X_{4} \coloneq X_{2} \oplus F(K_3, X_3)$\\ + return $X_{3}\|X_{4}$ + }{1} + }{0.8} + }{\approxeq}{ + \sslibrary{\mathbb{F}}{prp-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X}{ + if $L[X]$ undefined:\\ + \quad $Y \twoheadleftarrow \bits^n \ \setminus \ \mathcal{y}$\\ + \quad $\mathcal{y} \coloneq \mathcal{y} \cup \{Y\}$\\ + \quad $L[X] \coloneq Y$\\ + return $L[X]$ + }{1} + }{0.8} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The ``bad event'' proof technique}{Reminder} + \definitionbox{Bad Event Technique}{ + Let \lib{}{1} and \lib{}{2} be libraries that each include a boolean variable named \hl{\texttt{bad}}, and assume that after \texttt{bad} is set to \texttt{true} it remains \texttt{true} forever. We say that the bad event is triggered if the library ever sets \texttt{bad := true}. + \\[1em] + If \lib{}{1} and \lib{}{2} have identical source code, except for statements reachable only when \texttt{bad := true}, then: + \begin{align*} + \left| \prob{\prog{} \link \lib{}{1} \Rightarrow \texttt{true}} - \prob{\prog{} \link \lib{}{2} \Rightarrow \texttt{true}} \right| \leq \prob{\prog{} \link \lib{}{1} \func{trigger}{\texttt{bad}}} + \end{align*} + } +\end{frame} + +\begin{frame}{The ``bad event'' proof technique}{Reminder} + \begin{itemize}[<+->] + \item \prog{}'s advantage is bounded by \prob{\prog{} \link \lib{}{1} \func{trigger}{\texttt{bad}}}. + \item Practical application: + \begin{itemize}[<+->] + \item Define a sequence of hybrid libraries. + \item Identify ``bad events'' between consecutive hybrids. + \item Show these events occur with negligible probability. + \end{itemize} + \item Enables us to focus on analyzing specific failure cases rather than full behavior. + \end{itemize} +\end{frame} + +\begin{frame}{The ``end-of-time'' strategy for bad events}{Reminder} + \begin{itemize}[<+->] + \item Sometimes analyzing bad events can be complex, especially when values are chosen by the adversary. + \item The end-of-time strategy: + \begin{enumerate}[<+->] + \item Postpone all bad-event logic to the end of the library execution. + \item Collect information during normal execution. + \item Check for bad events only at the very end. + \end{enumerate} + \item Advantages: + \begin{itemize}[<+->] + \item Simplifies analysis by separating normal behavior from bad-event checking. + \item Makes it easier to bound the probability of bad events. + \item Particularly useful for complex cryptographic proofs. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{However, a 3+ round Feistel cipher is fine!} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item Luby and Rackoff proved that a 3-round Feistel cipher is indistinguishable from a pseudorandom permutation.\footnote{\url{https://appliedcryptography.page/papers/luby-rackoff.pdf}} + \item Can we also prove it using our provable security framework? + \item Yes, with the bad events proof technique! + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{center} + \sslinked{ + \sslibrary{\mathbb{F}}{prp-real}{ + $K_1\|K_2\|K_3 \twoheadleftarrow \bits^{3\lambda}$\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + $X_{2} \coloneq X_{0} \oplus F(K_1, X_1)$\\ + $X_{3} \coloneq X_{1} \oplus F(K_2, X_2)$\\ + $X_{4} \coloneq X_{2} \oplus F(K_3, X_3)$\\ + return $X_{3}\|X_{4}$ + }{1} + }{0.8} + }{\approxeq}{ + \sslibrary{\mathbb{F}}{prp-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X}{ + if $L[X]$ undefined:\\ + \quad $Y \twoheadleftarrow \bits^n \ \setminus \ \mathcal{y}$\\ + \quad $\mathcal{y} \coloneq \mathcal{y} \cup \{Y\}$\\ + \quad $L[X] \coloneq Y$\\ + return $L[X]$ + }{1} + }{0.8} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 1} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item We start at \lib{\mathbb{F}}{prp-real}. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + $K_1\|K_2\|K_3 \twoheadleftarrow \bits^{3\lambda}$\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + $X_{2} \coloneq X_{0} \oplus F(K_1, X_1)$\\ + $X_{3} \coloneq X_{1} \oplus F(K_2, X_2)$\\ + $X_{4} \coloneq X_{2} \oplus F(K_3, X_3)$\\ + return $X_{3}\|X_{4}$ + }{1} + }{0.8} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 2} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item We add a cache $L[\cdot]$ so that each distinct output is computed only once. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + $K_1\|K_2\|K_3 \twoheadleftarrow \bits^{3\lambda}$\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + \hl{if $L[X_0\|X_1]$ undefined:}\\ + \quad $X_{2} \coloneq X_{0} \oplus F(K_1, X_1)$\\ + \quad $X_{3} \coloneq X_{1} \oplus F(K_2, X_2)$\\ + \quad $X_{4} \coloneq X_{2} \oplus F(K_3, X_3)$\\ + \quad \hl{$L[X_0\|X_1] \coloneq X_3\|X_4$}\\ + return \hl{$L[X_0\|X_1]$} + }{1} + }{0.8} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 3} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item We add additional sub-cache $L_i[\cdot]$ for each $F(K_i,\cdot)$ + \item Since we already assume $F$ to be a secure PRF, we can replace it with the ideal PRF and remove $K$. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \vspace{-1.5cm} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad \hl{if $L_1[X_1]$ undefined:}\\ + \quad \quad \hl{$L_1[X_1] \twoheadleftarrow \bits^\lambda$}\\ + \quad $X_{2} \coloneq X_{0} \oplus \hl{L_1[X_1]}$\\ + \quad \hl{if $L_2[X_2]$ undefined:}\\ + \quad \quad \hl{$L_2[X_2] \twoheadleftarrow \bits^\lambda$}\\ + \quad $X_{3} \coloneq X_{1} \oplus \hl{L_2[X_2]}$\\ + \quad \hl{if $L_3[X_3]$ undefined:}\\ + \quad \quad \hl{$L_3[X_3] \twoheadleftarrow \bits^\lambda$}\\ + \quad $X_{4} \coloneq X_{2} \oplus \hl{L_3[X_3]}$\\ + \quad $L[X_0\|X_1] \coloneq X_3\|X_4$\\ + return $L[X_0\|X_1]$ + }{1} + }{0.8} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 4} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item We expect $X_2$ and $X_3$ to never repeat. So, we can trigger the bad event if they do. + \item Later, we must show that the bad event's probability is negligible. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \vspace{-1.5cm} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad if $L_1[X_1]$ undefined:\\ + \quad \quad $L_1[X_1] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{2} \coloneq X_{0} \oplus L_1[X_1]$\\ + \quad if $L_2[X_2]$ \hl{defined: $\texttt{bad} \coloneq \texttt{true}$}\\ + \quad $L_2[X_2] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{3} \coloneq X_{1} \oplus L_2[X_2]$\\ + \quad if $L_3[X_3]$ \hl{defined: $\texttt{bad} \coloneq \texttt{true}$}\\ + \quad $L_3[X_3] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{4} \coloneq X_{2} \oplus L_3[X_3]$\\ + \quad $L[X_0\|X_1] \coloneq X_3\|X_4$\\ + return $L[X_0\|X_1]$ + }{1} + }{0.8} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 5} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Instead of sampling $L_2[X_2]$ uniformly and then computing $X_3$, we can sample $X_3$ uniformly and compute $L_2[X_2]$. + \item Same for $L_3[X_3]$ and $X_4$. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \vspace{-1.5cm} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad if $L_1[X_1]$ undefined:\\ + \quad \quad $L_1[X_1] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{2} \coloneq X_{0} \oplus L_1[X_1]$\\ + \quad if $L_2[X_2]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad \hl{$X_3 \twoheadleftarrow \bits^\lambda$}\\ + \quad $L_2[X_2] \hl{\coloneq X_3 \oplus X_1}$\\ + \quad if $L_3[X_3]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad \hl{$X_4 \twoheadleftarrow \bits^\lambda$}\\ + \quad $L_3[X_3] \hl{\coloneq X_4 \oplus X_2}$\\ + \quad $L[X_0\|X_1] \coloneq X_3\|X_4$\\ + return $L[X_0\|X_1]$ + }{1} + }{0.8} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 6} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item We can move the sampling steps to the top since they're no longer dependent on other variables. + \item Note how nothing after $L[X_0\|X_1] \coloneq X_3\|X_4$ affects what the adversary sees! + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \vspace{-1.5cm} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad \hl{$X_3 \twoheadleftarrow \bits^\lambda$}\\ + \quad \hl{$X_4 \twoheadleftarrow \bits^\lambda$}\\ + \quad \hl{$L[X_0\|X_1] \coloneq X_3\|X_4$}\\ + \quad if $L_1[X_1]$ undefined:\\ + \quad \quad $L_1[X_1] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{2} \coloneq X_{0} \oplus L_1[X_1]$\\ + \quad if $L_2[X_2]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_2[X_2] \coloneq X_3 \oplus X_1$\\ + \quad if $L_3[X_3]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_3[X_3] \coloneq X_4 \oplus X_2$\\ + \hl{return $L[X_0\|X_1]$} + }{1} + }{0.8} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 7} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item We can move the sampling steps to the top since they're no longer dependent on other variables. + \item Note how nothing after $L[X_0\|X_1] \coloneq X_3\|X_4$ affects what the adversary sees! + \item So, we can move all bad-event logic to the end of time, without changing the bad event's overall probability. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \vspace{-1.5cm} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad \hl{$L[X_0\|X_1] \coloneq \bits^{2\lambda}$}\\ + \quad \hl{$\mathcal{X} \coloneq \mathcal{X} \cup \{X_0\|X_1\}$}\\ + \quad return $L[X_0\|X_1]$ + }{1}\\[1em] + \sslibrarysubroutine{\hl{end of time}}{}{ + \hl{for each $X_0\|X_1 \in \mathcal{X}:$}\\ + \quad \hl{$X_3\|X_4 \coloneq L[X_0\|X_1]$}\\ + \quad if $L_1[X_1]$ undefined:\\ + \quad \quad $L_1[X_1] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{2} \coloneq X_{0} \oplus L_1[X_1]$\\ + \quad if $L_2[X_2]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_2[X_2] \coloneq X_3 \oplus X_1$\\ + \quad if $L_3[X_3]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_3[X_3] \coloneq X_4 \oplus X_2$ + }{1} + }{0.7} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 8} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item We need to analyze the probability of the bad event happening. + \item Let's say the adversary makes $q$ queries. + \item The bad event happens if: + \begin{itemize}[<+->] + \item $X_2$ value collides with previous $X_2$. + \item $X_3$ value collides with previous $X_3$. + \end{itemize} + \item Recall: $X_2 = X_0 \oplus L_1[X_1]$ where $L_1[X_1]$ is chosen randomly. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \vspace{-1.5cm} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad $L[X_0\|X_1] \coloneq \bits^{2\lambda}$\\ + \quad $\mathcal{X} \coloneq \mathcal{X} \cup \{X_0\|X_1\}$\\ + \quad return $L[X_0\|X_1]$ + }{1}\\[1em] + \sslibrarysubroutine{end of time}{}{ + for each $X_0\|X_1 \in \mathcal{X}:$\\ + \quad $X_3\|X_4 \coloneq L[X_0\|X_1]$\\ + \quad if $L_1[X_1]$ undefined:\\ + \quad \quad $L_1[X_1] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{2} \coloneq X_{0} \oplus L_1[X_1]$\\ + \quad if $L_2[X_2]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_2[X_2] \coloneq X_3 \oplus X_1$\\ + \quad if $L_3[X_3]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_3[X_3] \coloneq X_4 \oplus X_2$ + }{1} + }{0.7} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 9} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item So, we need to analyze when $X_2$ collisions occur. + \item If $(X_0, X_1)$ and $(X_0', X_1')$ are two different inputs... + \item A collision happens when $X_2 = X_2'$: + \begin{align*} + X_0 \oplus L_1[X_1] = X_0' \oplus L_1[X_1'] + \end{align*} + \item If $X_1 \neq X_1'$, then $L_1[X_1]$ and $L_1[X_1']$ are independent random values + \item The probability of this specific collision is $2^{-\lambda}$ + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \vspace{-1.5cm} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad $L[X_0\|X_1] \coloneq \bits^{2\lambda}$\\ + \quad $\mathcal{X} \coloneq \mathcal{X} \cup \{X_0\|X_1\}$\\ + \quad return $L[X_0\|X_1]$ + }{1}\\[1em] + \sslibrarysubroutine{end of time}{}{ + for each $X_0\|X_1 \in \mathcal{X}:$\\ + \quad $X_3\|X_4 \coloneq L[X_0\|X_1]$\\ + \quad if $L_1[X_1]$ undefined:\\ + \quad \quad $L_1[X_1] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{2} \coloneq X_{0} \oplus L_1[X_1]$\\ + \quad if $L_2[X_2]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_2[X_2] \coloneq X_3 \oplus X_1$\\ + \quad if $L_3[X_3]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_3[X_3] \coloneq X_4 \oplus X_2$ + }{1} + }{0.7} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 10 - Total probability analysis} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item For $q$ queries, we have at most $q(q-1)/2$ pairs of queries + \item Prob. of any $X_2$ collision across $q$ queries: + $q(q-1)/(2 \cdot 2^{\lambda}) \approx q^2/2^{\lambda+1}$ + \item Similarly for $X_3$ values: the probability of any $X_3$ collision is at most $q^2/2^{\lambda+1}$. + \item Total probability of bad event: at most $q^2/2^{\lambda}$ + \item With $\lambda \gg \log q$, this probability is negligible. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \vspace{-1.5cm} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad $L[X_0\|X_1] \coloneq \bits^{2\lambda}$\\ + \quad $\mathcal{X} \coloneq \mathcal{X} \cup \{X_0\|X_1\}$\\ + \quad return $L[X_0\|X_1]$ + }{1}\\[1em] + \sslibrarysubroutine{end of time}{}{ + for each $X_0\|X_1 \in \mathcal{X}:$\\ + \quad $X_3\|X_4 \coloneq L[X_0\|X_1]$\\ + \quad if $L_1[X_1]$ undefined:\\ + \quad \quad $L_1[X_1] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{2} \coloneq X_{0} \oplus L_1[X_1]$\\ + \quad if $L_2[X_2]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_2[X_2] \coloneq X_3 \oplus X_1$\\ + \quad if $L_3[X_3]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_3[X_3] \coloneq X_4 \oplus X_2$ + }{1} + }{0.7} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher}{Step 11} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item By the bad event technique, the advantage of any adversary is at most $q^2/2^{\lambda}$. + \item Without bad events, our last hybrid samples each response randomly. + \item Since the sampling logic is all that remains visible to the adversary, this is equivalent to the final simplified library. + \item This is indistinguishable from a truly random permutation for $q \ll 2^{\lambda/2}$ queries. + \item (The birthday bound tells us that's when collisions become likely) + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \vspace{-1.5cm} + \begin{center} + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad $L[X_0\|X_1] \coloneq \bits^{2\lambda}$\\ + \quad $\mathcal{X} \coloneq \mathcal{X} \cup \{X_0\|X_1\}$\\ + \quad return $L[X_0\|X_1]$ + }{1}\\[1em] + \sslibrarysubroutine{end of time}{}{ + for each $X_0\|X_1 \in \mathcal{X}:$\\ + \quad $X_3\|X_4 \coloneq L[X_0\|X_1]$\\ + \quad if $L_1[X_1]$ undefined:\\ + \quad \quad $L_1[X_1] \twoheadleftarrow \bits^\lambda$\\ + \quad $X_{2} \coloneq X_{0} \oplus L_1[X_1]$\\ + \quad if $L_2[X_2]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_2[X_2] \coloneq X_3 \oplus X_1$\\ + \quad if $L_3[X_3]$ defined: $\texttt{bad} \coloneq \texttt{true}$\\ + \quad $L_3[X_3] \coloneq X_4 \oplus X_2$ + }{1} + }{0.7} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Proof of security for 3-round Feistel cipher} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item Rest of the transition steps are trivial. $\qed$ + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \sslinked{ + \sslibrary{\mathbb{F}}{prp-real}{ + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X_0\|X_1}{ + if $L[X_0\|X_1]$ undefined:\\ + \quad $L[X_0\|X_1] \coloneq \bits^{2\lambda}$\\ + \quad return $L[X_0\|X_1]$ + }{1} + }{0.7} + }{\approxeq}{ + \sslibrary{\mathbb{F}}{prp-rand}{ + $L \coloneq$ [\ ]\\[1em] + \sslibrarysubroutine{$\text{prp.query}_{\mathbb{F}}$}{X}{ + if $L[X]$ undefined:\\ + \quad $Y \twoheadleftarrow \bits^n \ \setminus \ \mathcal{y}$\\ + \quad $\mathcal{y} \coloneq \mathcal{y} \cup \{Y\}$\\ + \quad $L[X] \coloneq Y$\\ + return $L[X]$ + }{1} + }{0.7} + } + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{DES: Feistel in practice} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Data Encryption Standard (DES)} is a classic real-world implementation of the Feistel structure + \item Properties: + \begin{itemize} + \item 16 Feistel rounds. + \item 56-bit key (64 bits with parity). + \item 64-bit block size. + \item Standardized in 1977. + \end{itemize} + \item Problem: By the 1990s, 56-bit keys became too small for security. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Triple DES (3DES)} replaced it: + \begin{itemize} + \item Uses three DES operations in sequence. + \item $C = E_{K3}(D_{K2}(E_{K1}(P)))$ + \item Effectively doubles the key length. + \item Compatible with legacy DES when $K1 = K2 = K3$ + \end{itemize} + \item 3DES still used in legacy systems, but largely replaced by AES for performance reasons. + \item Lesson: Feistel structure made it possible to adapt DES rather than abandon it. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{EFF's ``Deep Crack''} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item In 1998, the Electronic Frontier Foundation built a special-purpose machine called ``Deep Crack''.\footnote{I'm not responsible for any readings into that name.} + \item Cost: Only \$250,000 (far less than the NSA budget!) + \item Purpose: Prove that 56-bit DES keys were insufficient. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{deep_crack_a.jpg}{EFF's ``Deep Crack''} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{EFF's ``Deep Crack''} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item July 1998: Deep Crack broke a DES challenge in just 56 hours. + \item Message revealed: ``It's time for those 128-, 192-, and 256-bit keys.'' + \item Impact: + \begin{itemize} + \item Publicly demonstrated DES was obsolete. + \item Accelerated adoption of AES. + \item Made ``it's theoretically breakable'' a practical reality. + \item Priceless reaction from government officials! + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{deep_crack_b.jpg}{Paul Kocher. He's still active in cryptography today, insanely productive research career, many crazy attacks} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{AES: a good example of a PRP} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item AES is the most widely used PRP in the world. + \item It works on fixed-size blocks: 128 bits. + \item Key sizes: 128, 192, or 256 bits. + \item Each AES key defines a specific permutation over the space of all 128-bit values. + \item For each key, AES maps each possible 128-bit input to exactly one 128-bit output. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Different keys create different permutations. + \item AES is efficiently invertible: + \begin{itemize}[<+->] + \item $\text{Dec}(K, \text{Enc}(K, M)) = M$ + \end{itemize} + \item AES is believed to be computationally indistinguishable from a random permutation. + \item Has withstood extensive cryptanalysis for over 20 years. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{AES structure} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Internal structure: substitution-permutation network with multiple rounds.\footnote{Check out this amazing interactive animation of AES's internal structure: \url{https://formaestudio.com/rijndaelinspector/archivos/Rijndael_Animation_v4_eng-html5.html}} + \begin{itemize}[<+->] + \item SubBytes: non-linear substitution + \item ShiftRows: transposition + \item MixColumns: mixing operation + \item AddRoundKey: XOR with round key + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{flushright} + \scalebox{0.55}{ + \begin{tikzpicture}[ + block/.style={rectangle, draw, fill=ciphergray!15, minimum width=2cm, minimum height=0.6cm, align=center, font=\footnotesize}, + arrow/.style={-stealth, thick}, + node distance=0.5cm + ] + % Input + \node[block] (input) {Plaintext (128 bits)}; + + % Initial round (just key addition) + \node[block, below=0.8cm of input] (addroundkey0) {AddRoundKey}; + \draw[arrow] (input) -- (addroundkey0); + \node[right=0.3cm of addroundkey0, align=left, font=\scriptsize] (roundkey0) {Round Key 0}; + \draw[arrow] (roundkey0) -- (addroundkey0); + + % Main rounds box + \draw[rounded corners, dashed] (-2,-2.2) rectangle (2,-5.2); + \node[align=left, font=\scriptsize] at (-1.7,-2.5) {Rounds 1-9}; + + % Main round operations + \node[block, below=0.8cm of addroundkey0] (subbytes) {SubBytes}; + \draw[arrow] (addroundkey0) -- (subbytes); + + \node[block, below=of subbytes] (shiftrows) {ShiftRows}; + \draw[arrow] (subbytes) -- (shiftrows); + + \node[block, below=of shiftrows] (mixcolumns) {MixColumns}; + \draw[arrow] (shiftrows) -- (mixcolumns); + + \node[block, below=of mixcolumns] (addroundkey) {AddRoundKey}; + \draw[arrow] (mixcolumns) -- (addroundkey); + \node[right=0.3cm of addroundkey, align=left, font=\scriptsize] (roundkey) {Round Keys 1-9}; + \draw[arrow] (roundkey) -- (addroundkey); + + % Final round box + \draw[rounded corners, dashed] (-2,-5.8) rectangle (2,-7.8); + \node[align=left, font=\scriptsize] at (-1.7,-6.1) {Round 10}; + + % Final round operations (no MixColumns) + \node[block, below=0.8cm of addroundkey] (subbytes2) {SubBytes}; + \draw[arrow] (addroundkey) -- (subbytes2); + + \node[block, below=of subbytes2] (shiftrows2) {ShiftRows}; + \draw[arrow] (subbytes2) -- (shiftrows2); + + \node[block, below=of shiftrows2] (addroundkey2) {AddRoundKey}; + \draw[arrow] (shiftrows2) -- (addroundkey2); + \node[right=0.3cm of addroundkey2, align=left, font=\scriptsize] (roundkey2) {Round Key 10}; + \draw[arrow] (roundkey2) -- (addroundkey2); + + % Output + \node[block, below=0.8cm of addroundkey2] (output) {Ciphertext (128 bits)}; + \draw[arrow] (addroundkey2) -- (output); + + % Note about final round + \node[align=center, font=\scriptsize, color=red] at (3.2,-6.8) {No MixColumns\\in final round}; + \end{tikzpicture} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{AES: security and attacks over time} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item AES has been heavily analyzed for over 20 years. + \item Best attacks against full AES have gradually improved: + \begin{itemize}[<+->] + \item 2011: Biclique attack (Bogdanov et al.) reduced complexity to $2^{126.1}$ for AES-128. + \item Various side-channel attacks developed (power analysis, cache timing).\footnote{This is the main way to attack AES in practice. Side-channel attacks will be discussed in more depth later in the course.} + \item Advances in meet-in-the-middle and related-key techniques. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Despite these advances: + \begin{itemize}[<+->] + \item No practical attacks on full AES-128. + \item Best attacks still require $\approx 2^{126}$ operations. + \item At this complexity, attacks remain purely theoretical. + \item Would require resources far exceeding global computing power. + \end{itemize} + \item Even quantum computers offer only modest advantage (Grover's algorithm reduces security to $2^{64}$ operations).\footnote{More on quantum computers and how they affect cryptography later in the course.} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/1-5.tex b/slides/1-5.tex new file mode 100644 index 0000000..1eb32bb --- /dev/null +++ b/slides/1-5.tex @@ -0,0 +1,1657 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 1: Provable Security} +\covertopicname{1.5: Chosen-Plaintext \& Chosen-Ciphertext Attacks} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\section{Chosen-Plaintext Attacks} + +\begin{frame}{CPA Security} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \definitionbox{Security Against Chosen-Plaintext Attacks (CPA Security)}{ + Let $\Sigma$ be an encryption scheme, and let $\Sigma.\mathcal{C}(\ell)$ denote the set of possible ciphertexts for plaintexts of length $\ell$. If $\Sigma$ supports only plaintexts of a single length, we can simply write $\Sigma.\mathcal{C}$ to denote the entire set of ciphertexts.\footnote{i.e. ``just forget about the length''.}\\[0.5em] + + $\Sigma$ has security against \textbf{chosen-plaintext attacks} if the following two libraries are indistinguishable: + } + \end{column} + \begin{column}{0.4\textwidth} + \sslinked{ + \sslibrary{\Sigma}{cpa-real}{ + $K \twoheadleftarrow \Sigma.\mathcal{K}$\\[1em] + \sslibrarysubroutine{cpa.enc}{M}{ + $C \coloneq \Sigma.\texttt{Enc}(K, M)$\\ + return $C$ + }{1} + }{0.8} + }{\approxeq}{ + \sslibrary{\Sigma}{cpa-rand}{ + \sslibrarysubroutine{cpa.enc}{M}{ + $C \twoheadleftarrow \Sigma.\mathcal{C}(|M|)$\\ + return $C$ + }{1} + }{0.8} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Why CPA security matters} + \begin{itemize}[<+->] + \item CPA security means: \textit{``even if I let you encrypt any message you want, you can't obtain any distinguisher regarding my scheme.''} + \item \textbf{Why this matters in real life:} + \begin{itemize}[<+->] + \item Attackers often can trick systems into encrypting data they choose. + \item Without CPA security, seeing these encryptions could reveal your secrets. + \item Example: If bank transactions always encrypt to the same ciphertexts, attackers could identify your purchases. + \end{itemize} + \item The only thing that's allowed to leak is the length of messages/ciphertext. + \item Most modern encryption is designed to have this important property. + \end{itemize} +\end{frame} + +\begin{frame}{Message length: not important, not unimportant} + \begin{itemize}[<+->] + \item Even with CPA security, the \textbf{length} of messages is still leaked. + \item This seemingly minor leak can reveal surprising information: + \begin{itemize}[<+->] + \item \textbf{Encrypted VoIP calls}: Length patterns can reveal which language is spoken. + \item \textbf{Encrypted web traffic}: Sizes of requests/responses identify websites. + \item \textbf{Encrypted messages}: Length patterns can reveal the type of content (document, image, etc.) + \item \textbf{Encrypted commands}: Length often reveals which command was issued. + \end{itemize} + \item Mitigation typically involves padding messages to fixed lengths or standard increments. + \item This is why many secure protocols use fixed-size packets or add random padding. + \end{itemize} +\end{frame} + +\begin{frame}{CPA security is why we avoid deterministic encryption} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Deterministic encryption will always fail CPA security! + \item If the same message always encrypts to the same ciphertext: + \begin{itemize} + \item Attacker can recognize repeat messages. + \item Can build a ``dictionary'' of known plaintexts. + \item etc. + \end{itemize} + \item ECB mode is a classic example of insecure deterministic encryption. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \ssprogram{}{ + $M \twoheadleftarrow \mathcal{M}$\\ + $C_1 \coloneq \func{cpa.enc}{M}$\\ + $C_2 \coloneq \func{cpa.enc}{M}$\\ + return $C_1 == C_2$ + }{1} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Non-deterministic encryption isn't hard...} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item AES-CTR turns AES into a non-deterministic PRF... + \item AES-GCM even turns it into a non-deterministic authenticated cipher...\footnote{More on these later. An authenticated cipher is one where the ciphertext can't be modified by the adversary without that being detected.} + \item We can just as easily make a PRF non-deterministic: + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sssubroutine{enc}{K, M}{ + $R \twoheadleftarrow \bits^\lambda$\\ + $S \coloneq F(K, R) \oplus M$\\ + return $R\|S$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{...but it can be fragile} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item We switch M and R's places in \lib{}{cpa-real}'s encryption function. + \item Is the scheme still secure? + \item \textbf{No!} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{}{cpa-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cpa.enc}{M}{ + $R \twoheadleftarrow \bits^\lambda$\\ + $S \coloneq F(K, \hl{M}) \oplus \hl{R}$\\ + return $R\|S$ + }{1} + }{1} + }{\overset{?}{\approxeq}}{ + \sslibrary{}{cpa-rand}{ + \sslibrarysubroutine{cpa.enc}{M}{ + $R\|S \twoheadleftarrow \bits^{2\lambda}$\\ + return $R\|S$ + }{1} + }{1} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The Golden Rule of PRFs} + \definitionbox{The Golden Rule of PRFs}{ + If a PRF $F$ is being used as a component in a larger construction $H$, then security usually rests on how well $H$ can ensure distinct inputs to $F$. + } + \begin{itemize}[<+->] + \item When analyzing PRF security, focus on input uniqueness. + \item Repeated inputs to a PRF create exploitable patterns. + \item Even if $F$ is secure, $H$ can be broken if it causes $F$ to receive duplicate inputs. + \item Don't try to directly distinguish $F$'s outputs from uniform. + \item Instead, exploit how $H$ uses $F$ incorrectly. + \item Find input patterns that force collisions within $F$. + \end{itemize} +\end{frame} + +\begin{frame}{...but it can be fragile} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item $F(K, M)$ is now constant. + \item \prob{\prog{}\link\lib{}{cpa-real} \Rightarrow \texttt{true}} $ = 1$ + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \ssprogram{}{ + $M \twoheadleftarrow \mathcal{M}$\\ + $R_1\|S_1 \coloneq \func{cpa.enc}{M}$\\ + $R_2\|S_2 \coloneq \func{cpa.enc}{M}$\\ + return $S_1 \oplus S_2 == R_1 \oplus R_2$ + }{0.8} + }{\link}{ + \sslibrary{}{cpa-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cpa.enc}{M}{ + $R \twoheadleftarrow \bits^\lambda$\\ + $S \coloneq F(K, \hl{M}) \oplus \hl{R}$\\ + return $R\|S$ + }{1} + }{0.8} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{AES is a block cipher}{Reminder} + \begin{itemize}[<+->] + \item AES takes a 16-byte input, produces a 16-byte output. + \item Key can be 16, 24 or 32 bytes. \pause + \item OK, so what if we want to encrypt more than 16 bytes? \pause + \item \textbf{Proposal}: split the plaintext into 16 byte chunks, encrypt + each of them with the same key. + \end{itemize} +\end{frame} + +\begin{frame}{Block cipher examples} + \begin{columns} + \begin{column}{0.33\textwidth} + \imagewithcaption{tux_plaintext.png}{What we start with} + \end{column} + \pause + \begin{column}{0.33\textwidth} + \imagewithcaption{tux_encrypted_ecb.png}{What we get} + \end{column} + \pause + \begin{column}{0.33\textwidth} + \imagewithcaption{tux_encrypted_ctr.png}{What we actually want} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{AES by itself is deterministic} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{itemize}[<+->] + \item AES as a block cipher is inherently \textbf{deterministic}: + \begin{itemize} + \item $\texttt{AES}(K, M) = C$ will always produce the same $C$. + \item This makes raw AES fail CPA security. + \end{itemize} + \item What makes AES secure in practice? + \begin{itemize} + \item \textbf{Block cipher modes} (CBC, CTR, GCM) add randomness/state using ``initialization vectors'' + \begin{itemize} + \item IV is fancy name for ``random bytes used once''.\footnote{Also referred to as ``nonces'' for ``number used once'', although in some block cipher modes such as AES-CBC, they can technically be used multiple times without problems.} + \end{itemize} + \item IVs ensure the same plaintext encrypts differently each time. + \end{itemize} + \item Without a proper mode, AES is like ECB mode: predictable patterns + \end{itemize} + \end{column} + \begin{column}{0.3\textwidth} + \begin{center} + \ssprogram{AES}{ + $K \twoheadleftarrow \bits^{\lambda}$\\ + $M \twoheadleftarrow \mathcal{M}$\\[0.5em] + $C_1 \coloneq \texttt{AES}(K, M)$\\ + $C_2 \coloneq \texttt{AES}(K, M)$\\[0.5em] + $C_1 == C_2$ + }{0.85} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Block cipher modes of operation} + \bigimagewithcaption{block_cipher_modes.png}{Source: Wikipedia} +\end{frame} + +\begin{frame}{CBC mode: a closer look} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item CBC (Cipher Block Chaining) uses previous ciphertext to randomize current block. + \item Requires a random initialization vector (IV). + \item Each block's encryption depends on all previous blocks. + \item Changes to one block affect all subsequent ciphertext blocks. + \item Sequential encryption (can't parallelize). + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \sssubroutine{Enc}{K, M_1\|\cdots\|M_\ell}{ + $C_0 \twoheadleftarrow \bits^\lambda$\\ + $\text{for } i=1 \text{ to } \ell:$\\ + $\quad C_i \coloneq F(K, C_{i-1} \oplus M_i)$\\ + $\textbf{return } C_0\|C_1\|\cdots\|C_\ell$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CBC mode: a closer look} + \vspace{-0.3cm} + \bigimagewithcaption{cbc_with_dec.pdf}{Source: The Joy of Cryptography} +\end{frame} + +\begin{frame}{CTR mode: a closer look} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item CTR (Counter) mode turns a block cipher into a stream cipher. + \item Uses a nonce ($C_0$) plus a counter to create unique inputs to $F$. + \item Each block's encryption is independent of other blocks. + \item Highly parallelizable (unlike CBC). + \item The nonce must never be reused with the same key. + \item Widely used in modern protocols (TLS, SSH, etc.) + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \sssubroutine{Enc}{K, M_1\|\cdots\|M_\ell}{ + $C_0 \twoheadleftarrow \bits^\lambda$\\ + $\text{for } i=1 \text{ to } \ell:$\\ + $\quad C_i \coloneq F(K, C_0 + i - 1) \oplus M_i$\\ + $\textbf{return } C_0\|C_1\|\cdots\|C_\ell$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CTR mode: a closer look} + \bigimagewithcaption{ctr_with_dec.pdf}{Source: The Joy of Cryptography} +\end{frame} + +\section{Chosen-Ciphertext Attacks} + +\begin{frame}{Introducing chosen-ciphertext attacks} + \begin{itemize}[<+->] + \item Imagine this scenario at your company: + \begin{itemize}[<+->] + \item You discover a bug: software crashes when decrypting ciphertexts that yield plaintexts with null characters. + \item You think: ``We never encrypt messages with null bytes, so no problem!'' + \end{itemize} + \item An attacker can: + \begin{itemize}[<+->] + \item Send specially crafted ciphertexts to your system + \item Observe which ones crash your software (contain null bytes) and which don't + \item Use this information to completely break your encryption scheme! + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Introducing chosen-ciphertext attacks} + \begin{itemize} + \item This is a \textbf{chosen-ciphertext attack} (CCA): + \begin{itemize}[<+->] + \item Attacker can submit arbitrary ciphertexts for decryption. + \item System leaks information about the decryption results (the crash). + \item Even small information leaks can completely compromise security. + \item All encryption schemes we've seen so far are vulnerable to this! + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Format-oracle attacks \& malleability} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item Scenario: victim using CTR mode decryption reveals if result contains a null character. + \item Information can leak through crashes, error messages, or behavior differences. + \item A single yes/no bit of information can be enough to break encryption! + \item Malleability: many encryption schemes allow attackers to make predictable changes to plaintexts by modifying ciphertexts. + \item CTR mode is especially vulnerable because XOR allows targeted bit-flipping. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \sssubroutine{nulloracle}{C}{ + $M \coloneq \texttt{CTR.Dec}(K, C)$\\ + if $M$ contains $\bit{0}\bit{0}$ character:\\ + $\quad$ return $\texttt{true}$\\ + else return $\texttt{false}$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Why is it called \func{nulloracle}{c}?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item In mythology and colloquial language: + \begin{itemize} + \item An oracle was a mystic who answered questions on behalf of the gods. + \item Often gave enigmatic answers requiring interpretation. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \vspace{-0.4cm} + \bigimagewithcaption{oracle_painting_zoom.jpg}{\textit{The Oracle} by Camillo Miola, 1880\footnote{Absolutely beautiful painting, well-worth viewing in high resolution: \url{https://upload.wikimedia.org/wikipedia/commons/9/94/Camillo_Miola_\%28Biacca\%29_-_The_Oracle_-_72.PA.32_-_J._Paul_Getty_Museum.jpg}}} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Why is it called \func{nulloracle}{c}?} + \begin{itemize}[<+->] + \item In cryptography and computer science: + \begin{itemize} + \item An oracle is an algorithm that solves a specific problem. + \item You can query it but can't see its internal workings. + \item Oracles are often used as theoretical tools in security proofs. + \end{itemize} + \item Our \func{nulloracle}{c} reveals only: + \begin{itemize} + \item Whether a decrypted ciphertext contains null (\bit{0}\bit{0}) characters. + \item Just a single bit of information (yes/no). + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Null-oracle attack} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item An adversary who has access to \func{nulloracle}{C} can efficiently compute \texttt{Dec}$(K, C)$ for any $C$! + \item Yes, it really is enough. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \sssubroutine{nulloracle}{C}{ + $M \coloneq \texttt{CTR.Dec}(K, C)$\\ + if $M$ contains $\bit{0}\bit{0}$ character:\\ + $\quad$ return $\texttt{true}$\\ + else return $\texttt{false}$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CTR mode is malleable}{Defining malleability} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Malleability}{ + An encryption scheme is \textbf{malleable} if, given an encryption $C$ of an unknown plaintext $M$, it is possible to create a new ciphertext $C' \neq C$ where $M' = \texttt{Dec}(K, C')$ is somehow related to $M$, so that $M'$ reveals some information about $M$. + } + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item In CTR mode: $C_i = F(K, C_0 + i - 1) \oplus M_i$ + \item Flipping a bit in $C_i$ flips exactly the same bit in $M_i$. + \item Attackers can make targeted modifications without knowing the key. + \item Example: change ``transfer \$100'' to ``transfer \$900'' by modifying just one byte. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CTR mode is malleable}{Defining malleability} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item In CTR mode: $C_i = F(K, C_0 + i - 1) \oplus M_i$ + \item Flipping a bit in $C_i$ flips exactly the same bit in $M_i$. + \item Attackers can make targeted modifications without knowing the key. + \item Example: change ``transfer \$100'' to ``transfer \$900'' by modifying just one byte. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{ctr_dec.pdf}{CTR mode decryption.\\Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CTR mode is malleable}{Defining malleability} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item In CTR mode: $C_i = F(K, C_0 + i - 1) \oplus M_i$ + \item Flipping a bit in $C_i$ flips exactly the same bit in $M_i$. + \item Attackers can make targeted modifications without knowing the key. + \item Example: change ``transfer \$100'' to ``transfer \$900'' by modifying just one byte. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{ctr_dec_delta.pdf}{CTR mode decryption.\\Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CTR mode is malleable}{The attack} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Suppose adversary captures ciphertext $C$ and wants to find plaintext $M = \texttt{Dec}(K, C)$. + \item Let's focus on discovering just the last byte of $M$. + \item If the last byte of $M$ is $b$, then $M = M' \| b$. + \item What if we modify the ciphertext by XORing the last byte with $b$? + \item This would turn the last byte of the plaintext into all zeros (null byte)! + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{align*} + C \oplus (\ldots \bit{0}\bit{0} \| b) & \text{ decrypts to:} \\ + & M \oplus (\ldots \bit{0}\bit{0} \| b) \\ + & = (M' \| b) \oplus (\ldots \bit{0}\bit{0} \| b) \\ + & = M' \| (b \oplus b) \\ + & = M' \| \bit{0}\bit{0} + \end{align*} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CTR mode is malleable}{Finding one byte} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Problem: We don't know $b$ in advance! + \item Solution: Try all 255 possible values for $b$. + \item For each guess $g$, we: + \begin{itemize} + \item Create $C' = C \oplus (\ldots \bit{0}\bit{0} \| g)$ + \item Send $C'$ to the \func{nulloracle}{} + \item If oracle returns \texttt{true}, then $g = b$! + \end{itemize} + \item When we find the right value, we've discovered the last byte of $M$. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + Try these ciphertexts:\\ + $C \oplus (\ldots \bit{0}\bit{0} \| \bit{0}\bit{1})$\\ + $C \oplus (\ldots \bit{0}\bit{0} \| \bit{0}\bit{2})$\\ + $C \oplus (\ldots \bit{0}\bit{0} \| \bit{0}\bit{3})$\\ + $\vdots$\\ + $C \oplus (\ldots \bit{0}\bit{0} \| \bit{f}\bit{e})$\\ + $C \oplus (\ldots \bit{0}\bit{0} \| \bit{f}\bit{f})$ + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CTR mode is malleable}{Finding all bytes} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item We can use the same approach for any byte in the plaintext. + \item To find the $i$-th byte: + \begin{itemize} + \item Create a string of all zeros + \item Set only the $i$-th byte to our guess $g$ + \item XOR this with the ciphertext + \item Query the oracle + \end{itemize} + \item By repeating for all bytes, we can recover the entire plaintext! + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \ssprogram{null-oracle}{ + $n := |C_1\|\cdots\|C_{\ell}|$\\ + $M := ""$\\ + \\ + for $i = 1$ to $n$:\\ + $\quad$ for each $b \in \{\bit{0}\bit{1}, \ldots, \bit{f}\bit{f}\}$:\\ + $\quad\quad$ $\Delta := (\bit{0}\bit{0})^n$\\ + $\quad\quad$ $\Delta[i] := b$\\ + $\quad\quad$ if $\func{nulloracle}{C \oplus (0^\lambda \| \Delta)}$:\\ + $\quad\quad\quad$ $M := M \| b$\\ + $\quad\quad\quad$ next $i$\\ + return $M$ + }{0.8} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CTR mode is malleable}{The power of chosen-ciphertext attacks} + \begin{itemize}[<+->] + \item With just 255 queries per byte, we can completely decrypt any ciphertext! + \item For context: decrypting a 1KB file would take about 250,000 queries. + \item This is extremely practical for an attacker. + \item All from a single bit of information about the plaintext (contains null or not). + \item This attack works because: + \begin{itemize} + \item CTR mode is malleable (we can make predictable changes to plaintext) + \item The system leaks a tiny bit of information about decrypted plaintexts + \item Together, these flaws completely break the encryption + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Is the null-oracle attack just brute-force?} + \begin{itemize}[<+->] + \item Yes and no! + \item It's brute-force on each byte independently: + \begin{itemize} + \item To recover $n$-byte plaintext: at most $255n$ oracle queries + \item True brute-force on entire plaintext: $255^n$ (exponentially worse!) + \end{itemize} + \item For a 16-byte message: + \begin{itemize} + \item Null-oracle attack: ~4,080 queries (16 × 255) + \item True brute-force: ~$10^{38}$ queries ($255^{16}$) + \end{itemize} + \item This attack is exponentially more efficient than traditional brute-force. + \end{itemize} +\end{frame} + +\begin{frame}{Can we just rate-limit the number of queries?} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item Rate-limiting might help, but: + \begin{itemize} + \item It only increases attack time, doesn't prevent it. + \item Attackers can be patient or use multiple accounts. + \item Legitimate users suffer from the rate-limiting. + \end{itemize} + \item Better approach: cryptographic solutions! + \begin{itemize} + \item Fix the fundamental vulnerability, not just limit its exploitation. + \item Create systems that are mathematically proven to resist chosen-ciphertext attacks. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{yoda_meme.jpg}{} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Is fixing the null-byte bug enough?} + \begin{itemize}[<+->] + \item The null-character bug is just one example of a broader class of attacks. + \item Format-oracle attacks can exist without implementation bugs! + \item They only need: + \begin{itemize}[<+->] + \item A system that accepts untrusted ciphertexts + \item Decrypts them + \item Behaves differently based on the decryption result + \item In a way the attacker can observe + \end{itemize} + \item This behavior can come from: + \begin{itemize}[<+->] + \item Accidental bugs (null-byte crashes) + \item Intentional features (error messages, timing differences) + \item Normal application logic (web app behaving differently based on decrypted data) + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Real-world format-oracle attacks}{Padding oracle} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item CBC mode requires padding to handle plaintexts that aren't block-aligned. + \item Many implementations crash when encountering invalid padding. + \item This exposes an oracle that tells attackers: ``Does $\texttt{Dec}(K, C)$ have valid padding?'' + \item Attackers can systematically exploit this to decrypt arbitrary ciphertexts. + \item Has led to major vulnerabilities in SSH and SSL/TLS protocols. + \item Example: POODLE attack against SSL 3.0 affected millions of websites.\footnote{\url{https://appliedcryptography.page/papers/google-poodle.pdf}} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Real-world format-oracle attacks}{Timing side-channel} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item Victim interprets plaintext as a number $n$ and performs $n$ operations. + \item Attackers can measure how long the system takes to respond. + \item Response time reveals approximate numerical values inside $\texttt{Dec}(K, C)$. + \item Extremely subtle - even microsecond differences can leak information. + \item Successfully used to break older SSH and SSL/TLS implementations. + \item Example: Lucky Thirteen attack against TLS revealed message contents through timing differences.\footnote{\url{https://appliedcryptography.page/papers/lucky-thirteen.pdf}} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Real-world format-oracle attack}{Apple iMessage} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item Older Apple iMessage versions used gzip compression. + \item System responded differently when a ciphertext decrypted to: + \begin{itemize} + \item A valid gzip file (processed normally) + \item An invalid gzip file (error reported) + \end{itemize} + \item This created an oracle revealing: ``Is $\texttt{Dec}(K, C)$ a valid gzip file?''\footnote{\url{https://appliedcryptography.page/papers/jhu-imessage.pdf}} + \item Attackers who understood the gzip format could exploit this to: + \begin{itemize} + \item Silently recover private messages + \item Bypass encryption entirely + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Real-world format-oracle attack}{XML format Oracles} + \begin{itemize}[<+->] + \item Many systems decrypt data expecting valid XML format. + \item If decrypted data isn't valid XML, system returns an error. + \item This exposes an oracle: ``Is $\texttt{Dec}(K, C)$ valid XML?'' + \item XML has complex syntax rules that attackers can exploit. + \item Can allow complete decryption of arbitrary ciphertexts. + \item Similar attacks exist for other formats (JSON, HTML, etc.) + \end{itemize} +\end{frame} + +\begin{frame}{I thought CTR mode was secure?}{CPA vs. CCA security} + \begin{itemize}[<+->] + \item CTR mode \textit{is} secure against chosen-plaintext attacks (CPA-secure). + \begin{itemize} + \item It uses randomness to ensure identical messages encrypt differently each time. + \item The adversary cannot distinguish encryptions of known plaintexts. + \end{itemize} + \item But CPA security isn't enough in many real-world scenarios! + \begin{itemize} + \item CPA security only considers attackers who can request encryptions. + \item It doesn't protect against attackers who can submit chosen ciphertexts. + \end{itemize} + \item In the null-oracle attack: + \begin{itemize} + \item The victim decrypts ciphertexts chosen by the adversary. + \item Even leaking one bit about the plaintext (contains nulls or not) is fatal. + \item CPA security doesn't model or prevent this type of attack. + \end{itemize} + \item This is why we need stronger security notions (CCA security). + \end{itemize} +\end{frame} + +\begin{frame}{CCA Security} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Security Against Chosen-Ciphertext Attacks (CCA Security)}{ + An encryption scheme $\Sigma$ has security against \textbf{chosen-ciphertext attacks} if the following two libraries are indistinguishable: + } + \end{column} + \begin{column}{0.5\textwidth} + \sslinked{ + \sslibrary{\Sigma}{cca-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cca.enc}{M}{ + $C \coloneq \Sigma.\texttt{Enc}(K, M)$\\ + return $C$ + }{1}\\[1em] + \sslibrarysubroutine{cca.dec}{C}{ + return $\Sigma.\texttt{Dec}(K, C)$ + }{1} + }{0.7} + }{\approxeq}{ + \sslibrary{\Sigma}{cca-rand}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cca.enc}{M}{ + $C \twoheadleftarrow \Sigma.\mathcal{C}(|M|)$\\ + $\mathcal{D}[C] \coloneq M$\\ + return $C$ + }{1}\\[1em] + \sslibrarysubroutine{cca.dec}{C}{ + if $\mathcal{D}[C]$ defined: return $\mathcal{D}[C]$\\ + return $\Sigma.\texttt{Dec}(K, C)$ + }{1} + }{0.7} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Remember our CPA-secure encryption scheme?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item Not CCA-secure! + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sssubroutine{enc}{K, M}{ + $R \twoheadleftarrow \bits^\lambda$\\ + $S \coloneq F(K, R) \oplus M$\\ + return $R\|S$ + }{2} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Remember our CPA-secure encryption scheme?} + \begin{columns}[c] + \begin{column}{0.3\textwidth} + \begin{itemize} + \item Not CCA-secure! + \item In other words, we can trivially distinguish between these libraries: + \end{itemize} + \end{column} + \begin{column}{0.7\textwidth} + \sslinked{ + \sslibrary{}{cca-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cca.enc}{M}{ + $R \twoheadleftarrow \bits^\lambda$\\ + $S \coloneq F(K, R) \oplus M$\\ + return $R\|S$ + }{1}\\[1em] + \sslibrarysubroutine{cca.dec}{R\|S}{ + $M \coloneq F(K, R) \oplus S$\\ + return $M$ + }{1} + }{0.9} + }{\cancel{\approxeq}}{ + \sslibrary{}{cca-rand}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cca.enc}{M}{ + $R\|S \twoheadleftarrow \bits^{2\lambda}$\\ + $\mathcal{D}[R\|S] \coloneq M$\\ + return $R\|S$ + }{1}\\[1em] + \sslibrarysubroutine{cca.dec}{R\|S}{ + if $\mathcal{D}[R\|S]$ defined: return $\mathcal{D}[R\|S]$\\ + $M \coloneq F(K, R) \oplus S$\\ + return $M$ + }{1} + }{0.9} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Malleability strategy} + To break the CCA security of a scheme: + \begin{enumerate} + \item Study the decryption algorithm of the scheme. It often helps to draw a schematic diagram. + \item See whether any changes to a ciphertext make a \textit{predictable} change to the plaintext. + \item Formalize an attack in which the adversary: + \begin{enumerate} + \item Requests the encryption of a chosen plaintext, + \item Modifies the ciphertext as above, + \item Asks for the modified ciphertext to be decrypted. + \end{enumerate} + \end{enumerate} +\end{frame} + +\begin{frame}{Malleability once again} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item Not CCA-secure! + \item Here's a distinguisher: + \end{itemize} + \imagewithcaption{prf_enc_malleable}{Source: The Joy of Cryptography} + \end{column} + \begin{column}{0.5\textwidth} + \ssprogram{}{ + $M \twoheadleftarrow \bits^\lambda$\\ + $\Delta := \text{arbitrary, nonzero, $\lambda$-bit string}$\\ + $R\|S \coloneq \func{cca.enc}{M}$\\ + $M' \coloneq \func{cca.dec}{R\|(S \oplus \Delta)}$\\ + return $M' == M \oplus \Delta$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Another example} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize} + \item Let's try a harder challenge. + \end{itemize} + \imagewithcaption{prf_enc_2}{Source: The Joy of Cryptography} + \end{column} + \begin{column}{0.4\textwidth} + \sslibrary{}{cca-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cca.enc}{M}{ + $R \twoheadleftarrow \bits^\lambda$\\ + $S \coloneq F(K, R) \oplus F(K, M)$\\ + return $R\|S$ + }{1}\\[1em] + \sslibrarysubroutine{cca.dec}{R\|S}{ + $M \coloneq F^{-1}(K, F(K, R) \oplus S)$\\ + return $M$ + }{1} + }{0.85} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Another example} + \begin{columns}[c] + \begin{column}{0.3\textwidth} + \begin{itemize} + \item Let's try a harder challenge. + \end{itemize} + \imagewithcaption{prf_enc_2}{Source: The Joy of Cryptography} + \end{column} + \begin{column}{0.7\textwidth} + \sslinked{ + \sslibrary{}{cca-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cca.enc}{M}{ + $R \twoheadleftarrow \bits^\lambda$\\ + $S \coloneq F(K, R) \oplus F(K, M)$\\ + return $R\|S$ + }{1}\\[1em] + \sslibrarysubroutine{cca.dec}{R\|S}{ + $M \coloneq F^{-1}(K, F(K, R) \oplus S)$\\ + return $M$ + }{1} + }{0.85} + }{\cancel{\approxeq}}{ + \sslibrary{}{cca-rand}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cca.enc}{M}{ + $R\|S \twoheadleftarrow \bits^{2\lambda}$\\ + return $R\|S$ + }{1}\\[1em] + \sslibrarysubroutine{cca.dec}{R\|S}{ + if $\mathcal{D}[R\|S]$ defined: return $\mathcal{D}[R\|S]$\\ + $M \coloneq F^{-1}(K, F(K, R) \oplus S)$\\ + return $M$ + }{1} + }{0.85} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Frankenstein strategy} + Try the following approach in a chosen-ciphertext attack: + \begin{enumerate} + \item Request two separate encryptions of chosen plaintexts; it often helps to use the same plaintext. + \item Mix and match parts of the resulting ciphertexts to obtain two Frankenstein ciphertexts. + \item Ask for the Frankenstein ciphertexts to be decrypted, and see whether anything interesting happens. + \end{enumerate} +\end{frame} + +\begin{frame}{Another example} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item Not CCA-secure! + \item Here's a distinguisher: + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \ssprogram{}{ + $M \twoheadleftarrow \bits^\lambda$\\ + $R_1\|S_1 \coloneq \func{cca.enc}{M}$\\ + $R_2\|S_2 \coloneq \func{cca.enc}{M}$\\ + $M_1^* \coloneq \func{cca.dec}{R_1\|S_2}$\\ + $M_2^* \coloneq \func{cca.dec}{R_2\|S_1}$\\ + return $M_1^* == M_2^*$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\subsection{Message Authentication Codes} + +\begin{frame}{Symmetric primitive example: hash functions}{Reminder} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \definitionbox{Hash Function Properties}{ + \begin{itemize}\item Takes input of \textbf{any size}[<+->] + \item Produces output of \textbf{fixed size} + \item Is \textbf{deterministic} (same input $\rightarrow$ same output) + \item Even a \textbf{tiny change} in input creates completely different output + \item Is \textbf{efficient} to compute\end{itemize} + } + \end{column} + \begin{column}{0.45\textwidth} + \begin{tcolorbox} + [colback=black!5!white,colframe=ciphergray] $\mathsf{SHA256}(\texttt{hello}) =$ \\ \texttt{2cf24dba5fb0a30e26e83b2ac5}\\ \texttt{b9e29e1b161e5c1fa7425e7304}\\ + \texttt{3362938b9824} + + $\mathsf{SHA256}(\texttt{hullo}) =$ \\ \texttt{7835066a1457504217688c8f5d}\\ + \texttt{06909c6591e0ca78c254ccf174}\\ \texttt{50d0d999cab0} + \end{tcolorbox} + \textcolor{cipherprimary}{\textbf{Note:} \small One character change $\rightarrow$ + completely different hash!} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Expected properties of a hash function}{Reminder} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Collision resistance}: computationally infeasible to find + two different inputs producing the same hash. + \item \textbf{Preimage resistance}: given the output of a hash function, + it is computationally infeasible to reconstruct the original input. + \item \textbf{Second preimage resistance}: given an input and an output, + it's computationally infeasible to find another different input + producing the same output. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{sha2.png}{SHA-2 compression function. Source: Wikipedia} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Hash functions: what are they good for?}{Reminder} + \begin{itemize}[<+->] + \item \textbf{Password storage}: Store the hash of the password on the server, + not the password itself. Then check candidate passwords against the hash. + \item \textbf{Data integrity verification}: Hash a file. Later hash it + again and compare hashes to check if the file has changed, suffered storage + degradation, etc. + \item \textbf{Proof of work}: Server asks client to hash something a lot of + times before they can access some resource. Useful for anti-spam, Bitcoin + mining, etc. + \end{itemize} +\end{frame} + +\begin{frame}{Message authentication codes} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Message Authentication Code (MAC)}{ + A MAC is a cryptographic function that takes a key $K$ and a message $M$ and produces a tag $T$ that authenticates the message. Only someone with the same key can verify the tag. + } + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item A MAC provides \textbf{integrity} and \textbf{authenticity} for messages. + \item Unlike hash functions, MACs require a secret key + \item MACs address the malleability problem we saw with encryption schemes. Without a MAC, attackers could modify ciphertexts. + \item A secure MAC should be unforgeable, even after seeing MACs for chosen messages. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{PRFs as MACs} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize}[<+->] + \item A pseudorandom function (PRF) can be used directly as a MAC! + \item The MAC key is the PRF key $K$. + \item To authenticate a message $X$: + \begin{itemize} + \item Compute the tag $T = F(K, X)$ + \item Send both $X$ and $T$ to the recipient + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{flushright} + \sslinked{ + \sslibrary{}{mac-real}{ + $K \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{mac.guess}{X, Y}{ + return $Y == F(K, X)$ + }{1}\\[1em] + \sslibrarysubroutine{mac.reveal}{X}{ + return $F(K, X)$ + }{1} + }{0.75} + }{\approxeq}{ + \sslibrary{}{mac-ideal}{ + \sslibrarysubroutine{mac.guess}{X, Y}{ + if $L[X]$ undefined: return $\texttt{false}$\\ + return $Y == L[X]$ + }{1}\\[1em] + \sslibrarysubroutine{mac.reveal}{X}{ + if $L[X]$ undefined: $L[X] \twoheadleftarrow \bits^\lambda$\\ + return $L[X]$ + }{1} + }{0.75} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{From CPA to CCA security}{The Encrypt-then-MAC approach} + \begin{itemize}[<+->] + \item CPA security isn't enough in the real world. + \item We need protection against chosen-ciphertext attacks. + \item Solution: combine encryption with a MAC!. + \item \textbf{Encrypt-then-MAC}: + \begin{itemize} + \item Encrypt the message normally. + \item Compute a MAC tag of the \textit{ciphertext}. + \item Send both ciphertext and tag. + \item Receiver verifies the tag before decrypting. + \end{itemize} + \item This prevents adversaries from creating valid modified ciphertexts. + \end{itemize} +\end{frame} + +\begin{frame}{Encrypt-then-MAC: formal construction} + \begin{columns}[c] + \begin{column}{0.45\textwidth} + \definitionbox{Encrypt-then-MAC Construction}{ + Let $\Sigma$ be an SKE scheme and $F$ be a PRF with output length $\lambda$ whose domain includes $\Sigma.\mathcal{C}$. + Define a new encryption scheme: + \begin{align*} + \mathcal{K} & = \Sigma.\mathcal{K} \times \bits^\lambda \\ + \mathcal{M} & = \Sigma.\mathcal{M} \\ + \mathcal{C}(\ell) & = \Sigma.\mathcal{C}(\ell) \times \bits^\lambda + \end{align*} + } + \end{column} + \begin{column}{0.55\textwidth} + \sssubroutine{Enc}{(K_e, K_m), M}{ + $C \coloneq \Sigma.\texttt{Enc}(K_e, M)$\\ + $T \coloneq F(K_m, C)$\\ + return $C\|T$ + }{1} + \sssubroutine{Dec}{(K_e, K_m), C\|T}{ + if $F(K_m, C) \neq T$: return $\texttt{err}$\\ + return $\Sigma.\texttt{Dec}(K_e, C)$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{CCA security of Encrypt-then-MAC} + \begin{columns}[c] + \begin{column}{0.45\textwidth} + \definitionbox{CCA Security Claim}{ + If $\Sigma$ is a CPA-secure encryption scheme and $F$ is a secure PRF, then the Encrypt-then-MAC construction is CCA-secure. + } + \begin{itemize}[<+->] + \item Key insight: \textbf{the MAC prevents tampering} + \item Without the MAC key, adversary can't create valid tags. + \item \textbf{Decryption oracle only returns plaintexts for ciphertexts with valid tags.} + \end{itemize} + \end{column} + \begin{column}{0.55\textwidth} + \sslinked{ + \sslibrary{}{cca-real}{ + $K_e \twoheadleftarrow \Sigma.\mathcal{K}$\\ + $K_m \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cca.enc}{M}{ + $C \coloneq \Sigma.\texttt{Enc}(K_e, M)$\\ + $T \coloneq F(K_m, C)$\\ + return $C\|T$ + }{1}\\[1em] + \sslibrarysubroutine{cca.dec}{C\|T}{ + if $F(K_m, C) \neq T$: return $\texttt{err}$\\ + return $\Sigma.\texttt{Dec}(K_e, C)$ + }{1} + }{0.65} + }{\approxeq}{ + \sslibrary{}{cca-rand}{ + $K_e \twoheadleftarrow \Sigma.\mathcal{K}$\\ + $K_m \twoheadleftarrow \bits^\lambda$\\[1em] + \sslibrarysubroutine{cca.enc}{M}{ + $C \twoheadleftarrow \Sigma.\mathcal{C}(|M|)$\\ + $T \twoheadleftarrow \bits^\lambda$\\ + $\mathcal{D}[C\|T] \coloneq M$\\ + return $C\|T$ + }{1}\\[1em] + \sslibrarysubroutine{cca.dec}{C\|T}{ + if $\mathcal{D}[C\|T]$ defined: return $\mathcal{D}[C\|T]$\\ + if $F(K_m, C) \neq T$: return $\texttt{err}$\\ + return $\Sigma.\texttt{Dec}(K_e, C)$ + }{1} + }{0.65} + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Combining MACs and encryption} + \begin{itemize}[<+->] + \item Not every way of combining a MAC and CPA-secure encryption achieves CCA security. + \item There are three common approaches to combining them: + \begin{itemize} + \item \textbf{Encrypt-then-MAC}: Encrypt message, then MAC the ciphertext. + \item \textbf{Encrypt-and-MAC}: Encrypt message and MAC the plaintext separately. + \item \textbf{MAC-then-encrypt}: MAC the plaintext, then encrypt both message and tag. + \end{itemize} + \item Only one approach guarantees CCA security when using any CPA-secure encryption. + \end{itemize} +\end{frame} + +\begin{frame}{Encrypt-then-MAC}{CCA-secure} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{MAC verifies ciphertext integrity} before decryption. + \item Prevents attackers from submitting modified ciphertexts. + \item \textbf{Always CCA-secure} if encryption is CPA-secure and MAC is secure. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sssubroutine{Enc}{(K_e, K_m), M}{ + $C \coloneq \Sigma.\texttt{Enc}(K_e, M)$\\ + $T \coloneq F(K_m, C)$\\ + return $C\|T$ + }{1} + \sssubroutine{Dec}{(K_e, K_m), C\|T}{ + if $F(K_m, C) \neq T$: return $\texttt{err}$\\ + return $\Sigma.\texttt{Dec}(K_e, C)$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Encrypt-and-MAC}{Not even CPA-secure!} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{MAC is computed on the plaintext} + \item Same plaintext always produces same tag, leaking equality information. + \item \textbf{Not even CPA-secure}, let alone CCA-secure. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sssubroutine{Enc}{(K_e, K_m), M}{ + $C \coloneq \Sigma.\texttt{Enc}(K_e, M)$\\ + $T \coloneq F(K_m, M)$\\ + return $C\|T$ + }{1} + \sssubroutine{Dec}{(K_e, K_m), C\|T}{ + $M \coloneq \Sigma.\texttt{Dec}(K_e, C)$\\ + if $F(K_m, M) \neq T$: return $\texttt{err}$\\ + return $M$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{MAC-then-encrypt}{It's complicated} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Tag is hidden inside the ciphertext} + \item Whether this is CCA-secure depends on the specific encryption scheme. + \item \textbf{Not generally CCA-secure} for all CPA-secure encryption schemes. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \sssubroutine{Enc}{(K_e, K_m), M}{ + $T \coloneq F(K_m, M)$\\ + $C \coloneq \Sigma.\texttt{Enc}(K_e, M\|T)$\\ + return $C$ + }{1} + \sssubroutine{Dec}{(K_e, K_m), C}{ + $M\|T \coloneq \Sigma.\texttt{Dec}(K_e, C)$\\ + if $F(K_m, M) \neq T$: return $\texttt{err}$\\ + return $M$ + }{1} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Encrypt + MAC security comparison} + \begin{center} + \begin{tabular}{|l|c|c|} + \hline + \textbf{Construction} & \textbf{CPA-secure?} & \textbf{CCA-secure?} \\ + \hline + Encrypt-then-MAC & Yes & Yes \\ + \hline + Encrypt-and-MAC & No & No \\ + \hline + MAC-then-encrypt & Yes & Maybe \\ + \hline + \end{tabular} + \end{center} + \vspace{1em} + \begin{itemize}[<+->] + \item \textbf{Encrypt-then-MAC} is the safest option. + \item \textbf{Encrypt-and-MAC} should never be used. + \item \textbf{MAC-then-encrypt} requires case-by-case analysis. + \end{itemize} +\end{frame} + +\subsection{Authenticated Encryption} + +\begin{frame}{Authenticated Encryption: beyond CCA security} + \begin{itemize}[<+->] + \item CCA security is stronger than CPA security, but still not the gold standard. + \item CCA security says: adversary-generated ciphertexts won't reveal useful information. + \item But CCA security doesn't require that they decrypt to \texttt{err}. + \item For many applications, we want a stronger guarantee: + \begin{itemize} + \item Only key-holders can create valid ciphertexts. + \item All other ciphertexts should be rejected as invalid. + \end{itemize} + \item This property is called \textbf{Authenticated Encryption (AE)}. + \item Authenticated encryption provides both confidentiality and authenticity. + \end{itemize} +\end{frame} + +\begin{frame}{Authenticated Encryption: formal definition} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \definitionbox{Authenticated Encryption}{ + A SKE scheme $\Sigma$ is a secure authenticated encryption (AE) scheme if the following two libraries are indistinguishable: + } + \end{column} + \begin{column}{0.6\textwidth} + \begin{flushright} + \sslinked{ + \sslibrary{\Sigma}{ae-real}{ + $K \twoheadleftarrow \Sigma.\mathcal{K}$\\[1em] + \sslibrarysubroutine{ae.enc}{M}{ + return $\Sigma.\texttt{Enc}(K, M)$ + }{1}\\[1em] + \sslibrarysubroutine{ae.dec}{C}{ + return $\Sigma.\texttt{Dec}(K, C)$ + }{1} + }{0.75} + }{\approxeq}{ + \sslibrary{\Sigma}{ae-rand}{ + \sslibrarysubroutine{ae.enc}{M}{ + $C \twoheadleftarrow \Sigma.\mathcal{C}(|M|)$\\ + $\mathcal{D}[C] \coloneq M$\\ + return $C$ + }{1}\\[1em] + \sslibrarysubroutine{ae.dec}{C}{ + if $\mathcal{D}[C]$ defined: return $\mathcal{D}[C]$\\ + else: return $\texttt{err}$ + }{1} + }{0.75} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{AE vs. CCA security} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Key difference: \textbf{how we handle adversary-created ciphertexts}. + \item In \lib{\Sigma}{ae-rand}, any ciphertext not created by the library always decrypts to \texttt{err}. + \item In \lib{\Sigma}{cca-rand}, such ciphertexts could decrypt to anything (not necessarily \texttt{err}). + \item So AE requires: + \begin{itemize} + \item Adversary cannot tell real from random ciphertexts (as in CPA) + \item Adversary cannot create new valid ciphertexts (authentication) + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item AE is \textbf{strictly stronger} than CCA security. + \item Every AE scheme is CCA-secure, but not every CCA-secure scheme is an AE. + \item Making the distinction explicit helps us design better protocols. + \item AE is what you should aim for in practice. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{How Encrypt-then-MAC achieves AE} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item Remember our Encrypt-then-MAC construction: + \begin{itemize} + \item Encrypt the plaintext: $C \coloneq \Sigma.\texttt{Enc}(K_e, M)$ + \item MAC the ciphertext: $T \coloneq F(K_m, C)$ + \item Send both: $C\|T$ + \end{itemize} + \item It achieves AE security because: + \begin{itemize} + \item Without $K_m$, adversary can't forge valid tags. + \item Any ciphertext not created by the system will fail MAC verification. + \item MAC verification failures lead to \texttt{err}. + \end{itemize} + \item The proof is nearly identical to CCA security proof. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \definitionbox{AE Security of Encrypt-then-MAC}{ + Encrypt-then-MAC is a secure AE, if the underlying $\Sigma$ is a CPA-secure SKE and $F$ is a secure PRF. + } + \vspace{0.5em} + \definitionbox{AE implies CCA}{ + If an encryption scheme $\Sigma$ is a secure AE, then it is also CCA-secure. + } + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Authenticated Encryption: in practice} + \begin{itemize}[<+->] + \item Modern cryptographic protocols almost always use authenticated encryption. + \item Common AE implementations: + \begin{itemize}[<+->] + \item \textbf{AES-GCM} (Galois/Counter Mode): most widely used, combines CTR mode with a MAC. + \item \textbf{ChaCha20-Poly1305}: popular alternative to AES-GCM, especially on devices without AES hardware. + \item \textbf{AES-CBC + HMAC-SHA256}: older approach, uses Encrypt-then-MAC with AES in CBC mode. + \end{itemize} + \item Important implementation rule: \textbf{verify before decrypt}! + \begin{itemize}[<+->] + \item Always check the MAC before decrypting. + \item Prevents timing side-channels based on decryption behavior. + \item Helps protect against padding oracle attacks and similar vulnerabilities. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{AES-GCM: Galois/Counter Mode} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item AES-GCM (Galois/Counter Mode) is the most widely used AEAD scheme. + \item Combines AES in CTR mode (for encryption) with GMAC (for authentication). + \item Extremely efficient: + \begin{itemize} + \item Single pass over the data. + \item Parallelizable. + \item Hardware acceleration widely available. + \end{itemize} + \item Used in: TLS 1.2/1.3, IPsec, SSH, and many other protocols. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \begin{center} + \sssubroutine{AES-GCM.Enc}{K, N, A, M}{ + $H \coloneq \texttt{AES}(K, 0^{128})$\\ + $\text{for } i=0 \text{ to } \lceil|M|/128\rceil-1:$\\ + $\quad C_i \coloneq M_i \oplus \texttt{AES}(K, N\|i)$\\ + $T \coloneq \texttt{GHASH}_H(A, C) \oplus$\\ + $\quad\quad \texttt{AES}(K, N\|0)$\\ + $\textbf{return } C\|T$ + }{0.87} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{AES-GCM: Galois/Counter Mode} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Inputs}: + \begin{itemize} + \item Key $K$ (128, 192, or 256 bits) + \item Nonce $N$ (usually 96 bits) + \item Associated data $A$ (optional) + \item Plaintext $M$ + \end{itemize} + \item \textbf{Encryption process}: + \begin{itemize} + \item AES-CTR for confidentiality. + \item GHASH (Galois field multiplication) for authentication. + \end{itemize} + \item Authentication tag $T$ protects both ciphertext and associated data. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{gcm.pdf}{Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{AES-GCM: Galois/Counter Mode} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Security strengths}: + \begin{itemize} + \item Provides confidentiality, integrity, and authenticity + \item Formally proven secure (assuming AES is secure) + \item Fast and widely trusted + \end{itemize} + \item \textbf{Critical implementation requirements}: + \begin{itemize} + \item \textbf{Never reuse a nonce} with the same key! + \item A repeated nonce can lead to complete loss of confidentiality and authentication + \item 96-bit nonces are recommended (other sizes are less efficient) + \item Authentication tag should be at least 128 bits long + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Key commitment in authenticated encryption} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Key commitment}: a ciphertext should only decrypt to a valid plaintext under the key used to generate it. + \item Most AEAD schemes (including AES-GCM) don't guarantee this property!\footnote{\url{https://appliedcryptography.page/papers/key-commitment.pdf}} + \item Attack scenario: + \begin{enumerate} + \item Attacker creates special ciphertext $C$. + \item When decrypted with key $K_1$: harmless message. + \item When decrypted with key $K_2$: malicious content! + \item Enables plausible deniability, content smuggling, etc. + \end{enumerate} + \item Practical impact: + \begin{itemize} + \item Attacker can create ciphertexts that decrypt differently under different keys. + \item Enables attacks in multi-recipient contexts. + \item Affects real applications (e.g., messaging, encrypted files). + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{ChaCha20-Poly1305} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item ChaCha20-Poly1305 is a modern AEAD construction: + \begin{itemize} + \item ChaCha20 stream cipher for encryption. + \item Poly1305 MAC for authentication. + \end{itemize} + \item Designed by Daniel J. Bernstein.\footnote{Does the class want to hear about Bernstein vs. United States?} + \item Key characteristics: + \begin{itemize} + \item No table lookups (better resistance to timing attacks) + \item Excellent performance on devices without AES hardware. + \end{itemize} + \item Widely used in TLS 1.3, Signal, WireGuard... + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \begin{center} + \sssubroutine{ChaCha20-Poly1305.Enc}{K, N, A, M}{ + $\text{key}_p \coloneq \texttt{ChaCha20}(K, N, 0)_{0..31}$\\ + $C \coloneq M \oplus \texttt{ChaCha20}(K, N, 1)$\\ + $\text{data} \coloneq \text{pad}(A) \| \text{pad}(C) \|$\\ + $\quad\quad \text{len}(A) \| \text{len}(C)$\\ + $T \coloneq \texttt{Poly1305}_{\text{key}_p}(\text{data})$\\ + $\textbf{return } C\|T$ + }{0.87} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Comparing AEAD implementations} + \begin{center} + \begin{tabular}{|l|c|c|c|} + \hline + \textbf{Property} & \textbf{AES-GCM} & \textbf{ChaCha20-Poly1305} & \textbf{AES+HMAC} \\ + \hline + Performance (HW accel.) & Excellent & Good & Good \\ + \hline + Performance (no accel.) & Poor & Excellent & Moderate \\ + \hline + Security level & 128-256 bits & 256 bits & 128-256 bits \\ + \hline + Side-channel resistance & Moderate & Excellent & Moderate \\ + \hline + Parallelizable & Yes & Partially & No \\ + \hline + Nonce sensitivity & Very high & High & Moderate \\ + \hline + Overhead & Low (single pass) & Low (single pass) & Higher (two pass) \\ + \hline + Implem. complexity & Moderate & Low & High \\ + \hline + \end{tabular} + \end{center} +\end{frame} + +\begin{frame}{Replay attacks}{Step 1: Alice sends original message} + \bigimagewithcaption{aead_scenario_1.pdf}{Source: The Joy of Cryptography} +\end{frame} + +\begin{frame}{Replay attacks}{Step 2: Attacker replays message in a different context} + \bigimagewithcaption{aead_scenario_2.pdf}{Source: The Joy of Cryptography} +\end{frame} + +\begin{frame}{Replay attacks}{Authenticated encryption didn't save us} + \begin{itemize} + \item Even with authenticated encryption, context matters! + \item Scenario: Alice sends Bob encrypted commands. + \begin{itemize} + \item Each ciphertext contains Alice's genuine intent. + \item Bob trusts any ciphertext that decrypts successfully. + \end{itemize} + \item Vulnerability: An adversary can replay legitimate ciphertexts. + \begin{itemize} + \item Alice once sent ``Delete temporary files''. + \item Adversary replays it when Alice meant to say ``Display files''. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Associated data} + \begin{itemize}[<+->] + \item Solution 1: Include context in the plaintext + \begin{itemize} + \item ``\texttt{ACTION: DISPLAY}'' before the actual message. + \item Inefficient - increases message size. + \item Both parties already know the context. + \end{itemize} + \item Better solution: Associated Data (AD) + \begin{itemize} + \item Context that sender and receiver already know. + \item Used during encryption and decryption. + \item Doesn't increase ciphertext size. + \end{itemize} + \item How it works: + \begin{itemize} + \item $\texttt{Enc}(K, A, M) \rightarrow C$ where $A$ is associated data. + \item $\texttt{Dec}(K, A, C) \rightarrow M$ or $\texttt{err}$ + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{AEAD: formal definition} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{AEAD}{ + An encryption scheme $\Sigma$ with associated data is a secure authenticated encryption with associated data (AEAD) scheme if the following two libraries are indistinguishable: + } + \end{column} + \begin{column}{0.5\textwidth} + \begin{flushright} + \sslinked{ + \sslibrary{\Sigma}{aead-real}{ + $K \twoheadleftarrow \Sigma.\mathcal{K}$\\[1em] + \sslibrarysubroutine{aead.enc}{A, M}{ + return $\Sigma.\texttt{Enc}(K, A, M)$ + }{1}\\[1em] + \sslibrarysubroutine{aead.dec}{A, C}{ + return $\Sigma.\texttt{Dec}(K, A, C)$ + }{1} + }{0.75} + }{\approxeq}{ + \sslibrary{\Sigma}{aead-rand}{ + \sslibrarysubroutine{aead.enc}{A, M}{ + $C \twoheadleftarrow \Sigma.\mathcal{C}(|M|)$\\ + $\mathcal{D}[A, C] \coloneq M$\\ + return $C$ + }{1}\\[1em] + \sslibrarysubroutine{aead.dec}{A, C}{ + if $\mathcal{D}[A, C]$ defined:\\ + \quad return $\mathcal{D}[A, C]$\\ + else: return $\texttt{err}$ + }{1} + }{0.75} + } + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Usefulness of AEADs} + \begin{itemize}[<+->] + \item AEAD (Authenticated Encryption with Associated Data) scheme guarantees: + \begin{itemize} + \item Ciphertexts reveal nothing about plaintexts (confidentiality). + \item Only ciphertexts created by the legitimate sender will decrypt without error (authenticity). + \item Decryption only succeeds when the correct associated data is used (context binding). + \end{itemize} + \item What to use as associated data? + \begin{itemize} + \item Protocol information: ``\texttt{DISPLAY}'' vs ``\texttt{DELETE}''. + \item Session identifiers or timestamps. + \item Previous messages in the conversation. + \item Any contextual information both parties already know. + \end{itemize} + \item Use as much associated data as relevant - it's cryptographically ``free''! + \end{itemize} +\end{frame} + +\begin{frame}{Solution: use associated data to provide context} + \bigimagewithcaption{aead_scenario_4.pdf}{Source: The Joy of Cryptography} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/1-6.tex b/slides/1-6.tex new file mode 100644 index 0000000..c4e8ab0 --- /dev/null +++ b/slides/1-6.tex @@ -0,0 +1,1058 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 1: Provable Security} +\covertopicname{1.6: Collision-Resistant Hash Functions} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\section{Defining Hash Functions} + +\begin{frame}{Symmetric primitive example: hash functions}{Reminder} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \definitionbox{Hash Function Properties}{ + \begin{itemize}\item Takes input of \textbf{any size}[<+->] + \item Produces output of \textbf{fixed size} + \item Is \textbf{deterministic} (same input $\rightarrow$ same output) + \item Even a \textbf{tiny change} in input creates completely different output + \item Is \textbf{efficient} to compute\end{itemize} + } + \end{column} + \begin{column}{0.45\textwidth} + \begin{tcolorbox} + [colback=black!5!white,colframe=ciphergray] $\mathsf{SHA256}(\texttt{hello}) =$ \\ \texttt{2cf24dba5fb0a30e26e83b2ac5}\\ \texttt{b9e29e1b161e5c1fa7425e7304}\\ + \texttt{3362938b9824} + + $\mathsf{SHA256}(\texttt{hullo}) =$ \\ \texttt{7835066a1457504217688c8f5d}\\ + \texttt{06909c6591e0ca78c254ccf174}\\ \texttt{50d0d999cab0} + \end{tcolorbox} + \textcolor{cipherprimary}{\textbf{Note:} \small One character change $\rightarrow$ + completely different hash!} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Expected properties of a hash function}{Reminder} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Collision resistance}: computationally infeasible to find + two different inputs producing the same hash. + \item \textbf{Preimage resistance}: given the output of a hash function, + it is computationally infeasible to reconstruct the original input. + \item \textbf{Second preimage resistance}: given an input and an output, + it's computationally infeasible to find another different input + producing the same output. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{sha2.png}{SHA-2 compression function. Source: Wikipedia} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Hash functions: what are they good for?}{Reminder} + \begin{itemize}[<+->] + \item \textbf{Password storage}: Store the hash of the password on the server, + not the password itself. Then check candidate passwords against the hash. + \item \textbf{Data integrity verification}: Hash a file. Later hash it + again and compare hashes to check if the file has changed, suffered storage + degradation, etc. + \item \textbf{Proof of work}: Server asks client to hash something a lot of + times before they can access some resource. Useful for anti-spam, Bitcoin + mining, etc. + \end{itemize} +\end{frame} + +\begin{frame}{Hash function collisions} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \definitionbox{Hash Function Collision}{ + A \textbf{collision} occurs when two different inputs produce the same hash output: + $x \neq y$ but $H(x) = H(y)$ + } + \begin{itemize}[<+->] + \item Collisions \textbf{must exist} due to the pigeonhole principle: + infinitely many possible inputs map to a finite set of outputs. + \item A secure hash function makes finding collisions \textbf{computationally infeasible}. + \end{itemize} + \end{column} + \begin{column}{0.45\textwidth} + \begin{tcolorbox}[colback=black!5!white,colframe=ciphergray] + \textbf{Collision Example:} + + \vspace{0.2cm} + + \texttt{Input 1: document.pdf}\\ + $\mathsf{SHA256} = \texttt{a1b2c3...}$ + + \vspace{0.2cm} + + \texttt{Input 2: malware.exe}\\ + $\mathsf{SHA256} = \texttt{a1b2c3...}$ + + \vspace{0.2cm} + + \textcolor{cipherprimary}{\textbf{Problem:} \small Attacker could substitute malware.exe for document.pdf without detection!} + \end{tcolorbox} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Hash function collisions} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \definitionbox{Hash Function Collision}{ + A \textbf{collision} occurs when two different inputs produce the same hash output: + $x \neq y$ but $H(x) = H(y)$ + } + \begin{itemize}[<+->] + \item If an attacker can find collisions, they could substitute malicious data + that produces the same hash as legitimate data. + \item The \textbf{birthday paradox} shows collisions are found faster than + expected (after $\approx 2^{n/2}$ attempts for an $n$-bit hash). + \end{itemize} + \end{column} + \begin{column}{0.45\textwidth} + \begin{tcolorbox}[colback=black!5!white,colframe=ciphergray] + \textbf{Collision Example:} + + \vspace{0.2cm} + + \texttt{Input 1: document.pdf}\\ + $\mathsf{SHA256} = \texttt{a1b2c3...}$ + + \vspace{0.2cm} + + \texttt{Input 2: malware.exe}\\ + $\mathsf{SHA256} = \texttt{a1b2c3...}$ + + \vspace{0.2cm} + + \textcolor{cipherprimary}{\textbf{Problem:} \small Attacker could substitute malware.exe for document.pdf without detection!} + \end{tcolorbox} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{$\mathsf{PRF}: F_{k}= X \rightarrow Y$} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item We want the mapping to be: + \begin{itemize} + \item One-way + \item ``Randomized'' + \item Relations between inputs not reflected in outputs + \end{itemize} + \end{itemize} + \end{column} + + \begin{column}{0.8\textwidth} + \begin{tikzpicture}[scale=0.38] + % Define colors + \definecolor{domaingreen}{RGB}{102, 170, 68} + \definecolor{rangegreen}{RGB}{170, 187, 136} + \definecolor{circlecolor}{RGB}{235, 137, 85} + \definecolor{purplearrow}{RGB}{160, 78, 160} + \definecolor{redarrow}{RGB}{237, 50, 36} + + % Input space (domain) X - made square + \draw[dashed, thick, domaingreen, fill=domaingreen] + (0,0) rectangle (8,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (4,-0.8) + {Size: infinite!}; + \node[font=\small] at (4,9) {Input space (domain) $X$}; + + % Output (range) Y - made square - moved more to the right + \draw[thick, rangegreen, fill=rangegreen] (15,2) rectangle (20,7); + \node[text width=4cm, align=center, font=\normalsize] + at + (17.5,1.2) + {Size: fixed}; + \node[font=\small] at (17.5,8.5) {Output (range) $Y$}; + % Input dots - adjusted positions for square domain + \filldraw[circlecolor] (2,7) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,7) -- (16.2,6.4); + \pause + \filldraw[circlecolor] (16.2,6.4) circle (0.3); + \pause + + \filldraw[circlecolor] (3,6) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,6) -- (18.6,5.3); + \pause + \filldraw[circlecolor] (18.6,5.3) circle (0.3); + \pause + + \filldraw[circlecolor] (2,5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,5) -- (16.8,4.2); + \pause + \filldraw[circlecolor] (16.8,4.2) circle (0.3); + \pause + + \filldraw[circlecolor] (4,3.5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (4,3.5) -- (18.4,3.2); + \pause + \filldraw[circlecolor] (18.4,3.2) circle (0.3); + \pause + + \filldraw[circlecolor] (2,2) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,2) -- (17.1,2.7); + \pause + \filldraw[circlecolor] (17.1,2.7) circle (0.3); + \pause + + \filldraw[circlecolor] (3,1) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, ultra thick, redarrow] + (3,1) -- (16.8,4.2); + \node[redarrow, font=\scriptsize\bfseries, rotate=14] + at + (10,3) + {Collisions are inevitable}; + \end{tikzpicture} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Birthday paradox} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item In a classroom of 50 students, what's the probability that at least two share a birthday? + \begin{itemize} + \item 2\%? + \item 20\%? + \item 50\%? + \item 97\%? + \end{itemize} + \item Many people guess around 15-20\%, but the actual probability is about 97\%! + \item This is counterintuitive because \textbf{we're not looking for a specific birthday - we're looking for \textit{any} match among all possible pairs}. + \item With 50 students, we have $\binom{50}{2} = 1,225$ possible pairs to check!\footnote{$\binom{50}{2}$ is a binomial coefficient. It means: \textit{``how many ways can I choose two different items from a set of 50?''}} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Birthday paradox} + \begin{itemize}[<+->] + \item With just 23 people, probability exceeds 50\% + \item Formula for $n$ people: + \begin{align*} + P = 1 - \frac{365!}{(365-n)! \cdot 365^n} + \end{align*} + \item Implication: Finding collisions in a space of size $N$ happens with roughly $\sqrt{N}$ samples. + \item This is why many cryptographic systems need large output spaces! + \end{itemize} +\end{frame} + +\begin{frame}{Birthday probabilities} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item Many cryptographic algorithms fail if two executions sample the same random value. + \item General question: If we take $q$ independent uniform samples from a set of $N$ items, what's the probability some value is chosen more than once? + \item This probability is called $\func{birthday}{q,N}$ + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \begin{align*} + \func{birthday}{q,N} = 1 - \prod_{i=1}^{q-1} \left(1 - \frac{i}{N}\right) + \end{align*} + \begin{itemize}[<+->] + \item Surprisingly high probability! + \item With $q \approx 1.2\sqrt{N}$, probability $\approx 0.5$ + \item For birthdays: only need 23 people for $>50\%$ chance + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Example hash functions}{From historical to modern} + \begin{itemize}[<+->] + \item \textbf{Historical/broken hash functions:} + \begin{itemize} + \item \textbf{MD4} (1990): 128-bit, completely broken, collisions found instantly + \item \textbf{MD5} (1992): 128-bit, collisions found in 2004, still widely misused + \item \textbf{SHA-0} (1993): 160-bit, withdrawn shortly after release + \item \textbf{SHA-1} (1995): 160-bit, practical collisions demonstrated in 2017 + \end{itemize} + \item \textbf{Current standard hash functions:} + \begin{itemize} + \item \textbf{SHA-2 family} (2001): SHA-224, SHA-256, SHA-384, SHA-512 + \item \textbf{SHA-3 family} (2015): Based on the Keccak sponge construction + \end{itemize} + \item \textbf{Modern alternatives:} + \begin{itemize} + \item \textbf{BLAKE2} (2012): Faster than MD5, more secure than SHA-3 + \item \textbf{BLAKE3} (2020): Highly parallelizable, extremely fast + \end{itemize} + \end{itemize} +\end{frame} + +\section{Attacks on Hash Functions} + +\begin{frame}{What about attacks on hash functions?} + \begin{itemize}[<+->] + \item Despite their security properties, hash functions can be vulnerable. + \item We'll explore key attack strategies: + \begin{itemize} + \item Precomputation attacks using rainbow tables. + \item Birthday attacks exploiting the birthday paradox. + \item Ways attackers try to find collisions. + \end{itemize} + \item Then we'll discuss countermeasures like salting. + \item We'll then show additional attacks on hash function, and discuss their practical evolution. + \end{itemize} +\end{frame} + +\begin{frame}{Precomputation attacks}{Why salts matter} + \begin{itemize}[<+->] + \item Consider a server storing hashes of users' passwords. + \item With \textbf{unsalted} hashes, an attacker can: + \begin{itemize} + \item Pre-compute hashes of common passwords. + \item Create a dictionary mapping $H(\texttt{password}) \rightarrow \texttt{password}$. + \item Instantly crack common passwords after a breach. + \end{itemize} + \item All hard work is done \textbf{before} the attack. + \item Results can be \textbf{reused} against any system using the same hash function. + \end{itemize} +\end{frame} + +\begin{frame}{Rainbow tables} + \definitionbox{Rainbow Tables}{ + \textbf{Rainbow tables} are specialized data structures that store precomputed hash values to efficiently crack passwords with minimal computation during the actual attack. + } + \begin{itemize}[<+->] + \item Represent a time-memory tradeoff for password cracking. + \item Store chains of hashes rather than individual hash-password pairs. + \item Can crack any password within the table's character set and length parameters. + \item Completely defeated by properly salted hashes. + \end{itemize} +\end{frame} + +\begin{frame}{Salt in hash functions}{Preventing precomputation attacks} + \definitionbox{Hash Salt}{ + A \textbf{salt} is a random value that is concatenated with the input before hashing: + $H(S \| X)$ where $S$ is the salt and $X$ is the original input. + } + \begin{itemize}[<+->] + \item The salt doesn't need to be secret, but should be: + \begin{itemize} + \item Random and unique for each input. + \item Long enough to prevent precomputation ($\geq 16$ bytes). + \item Stored alongside the hash value. + \end{itemize} + \item Salting prevents attackers from using precomputed tables (rainbow tables) to find hash values. + \item Without salt, same inputs always hash to same outputs, enabling reusable attacks. + \end{itemize} +\end{frame} + +\begin{frame}{Practical applications of salting}{Real-world examples} + \begin{itemize}[<+->] + \item \textbf{Web application user accounts} + \begin{itemize} + \item Different users with same password have different hashes. + \item Breach of one site doesn't compromise accounts on others. + \end{itemize} + \item \textbf{Password reset tokens} + \begin{itemize} + \item Salt + timestamp prevents token reuse. + \item Each reset request generates unique token. + \end{itemize} + \item \textbf{API key generation} + \begin{itemize} + \item Salting ensures unique keys even for similar services. + \item Allows key rotation without pattern recognition. + \end{itemize} + \item \textbf{Database record anonymization} + \begin{itemize} + \item Different salts for different datasets prevent correlation attacks. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Hash functions in the real world} + \begin{itemize}[<+->] + \item Hash functions you encounter ``in the wild'' are \textbf{standardized} as \textbf{unsalted} functions. + \item They have only a single input argument: a string to be hashed. + \end{itemize} +\end{frame} + +\begin{frame}{How salt neutralizes precomputation} + \begin{itemize}[<+->] + \item With salted hashes, precomputation becomes useless: + \begin{itemize} + \item Attacker doesn't know the salts until they've already breached the system. + \item Can't precompute $H(S \| X)$ without knowing $S$. + \end{itemize} + \item Using \textbf{different} salt for each user: + \begin{itemize} + \item Forces attacker to choose which user to attack. + \item Attacking two victims requires twice the effort. + \item No more ``attack all users for the price of one''. + \end{itemize} + \item Even if attacker obtains both hash and salt, they still need to brute-force each password individually. + \end{itemize} +\end{frame} + +\begin{frame}{Length extension attacks}{SHA-1 and SHA-2 vulnerability} + \definitionbox{Length Extension Attack}{ + A \textbf{length extension attack} allows an attacker who knows $H(M)$ to calculate $H(M \| P)$ for some padding $P$ without knowing $M$ itself. + } + \begin{itemize}[<+->] + \item Affects hash functions built using the Merkle-Damgård construction: + \begin{itemize} + \item SHA-1, SHA-256, SHA-512, MD5, and others + \item Not SHA-3 (which uses the sponge construction) + \end{itemize} + \item An attacker who knows $H(\texttt{message})$ and the length of $\texttt{message}$ can compute $H(\texttt{message} \| \texttt{padding} \| \texttt{extra\_data})$. + \item This can break naive authentication schemes using $H(\texttt{secret} \| \texttt{message})$. + \end{itemize} +\end{frame} + +\begin{frame}{Length extension attacks}{Real-world implications} + \begin{itemize}[<+->] + \item Consider a web API using: + \begin{itemize} + \item URL: \texttt{api.com/data?val=foo\&hash=123abc} + \item Hash calculated as: $H(\texttt{secret} \| \texttt{val=foo})$ + \item Server verifies request by checking if hash matches + \end{itemize} + \item An attacker can: + \begin{itemize} + \item Take a valid \texttt{hash} value + \item Compute a new hash for \texttt{val=foo\&malicious=true} + \item Without knowing the secret! + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{The Merkle-Damgård construction}{SHA-1, SHA-2} + \begin{columns}[c] + \begin{column}{0.45\textwidth} + \begin{itemize}[<+->] + \item Key components: + \begin{itemize} + \item Message is padded to a multiple of block size. + \item Split into fixed-size blocks. + \item Processes blocks sequentially through a compression function. + \item Each step combines previous state with current block. + \end{itemize} + \item If compression function is collision-resistant, so is the hash function. + \end{itemize} + \end{column} + \begin{column}{0.55\textwidth} + \imagewithcaption{merkle_damgard.pdf}{Source: The Joy of Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The Sponge construction}{SHA-3, BLAKE} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \begin{itemize}[<+->] + \item Two phases: + \begin{itemize} + \item \textbf{Absorbing}: Input blocks are XORed into the state and processed. + \item \textbf{Squeezing}: Output blocks are extracted from the state. + \end{itemize} + \item Naturally resistant to length extension attacks. + \item Versatile: Can produce output of any desired length. + \end{itemize} + \end{column} + \begin{column}{0.45\textwidth} + \imagewithcaption{sponge.png}{Source: The Hash Function BLAKE (by Jean-Philippe Aumasson)} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{HMAC: Protection against length extension} + \definitionbox{HMAC}{ + \textbf{HMAC} (Hash-based Message Authentication Code) is a specific construction for calculating a message authentication code (MAC) using a cryptographic hash function and a secret key. + } + \begin{align*} + \textsf{HMAC}(K, m) = H((K \oplus opad) \| H((K \oplus ipad) \| m)) + \end{align*} + \begin{itemize}[<+->] + \item $opad$ and $ipad$ are fixed padding values. + \item This nested construction defeats length extension attacks. + \item Widely used in TLS, IPsec, and other security protocols. + \item Provides both integrity and authentication. + \end{itemize} +\end{frame} + +\begin{frame}{Xiaoyun Wang's MD5 Collision} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item In 2004, Chinese researcher Xiaoyun Wang demonstrated the first practical MD5 collision. + \item Presented at the CRYPTO 2004 rump session, causing a sensation in the cryptographic community. + \item Interesting backstory: Wang's team initially got confused by endianness issues. + \item The Chinese translation of Bruce Schneier's ``Applied Cryptography'' had incorrectly translated the MD5 algorithm. + \item The translation got the byte ordering (endianness) wrong, making their early collision attempts fail. + \item Once corrected, they succeeded in breaking MD5 much faster than expected. + \item This discovery accelerated the migration away from MD5 in security applications. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{MD5 Chosen-Prefix Collision}{Attacking certificate authorities} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item In 2008, researchers created a rogue CA certificate using MD5 collisions. + \item Exploited weaknesses in how certificates were issued by a legitimate CA. + \item By predicting serial numbers and timestamps, they crafted a malicious certificate with the same MD5 hash. + \item Created a fake Certificate Authority that browsers would trust! + \item Demonstrated at the 25th Chaos Communication Congress. + \item Led to MD5 being rapidly phased out for digital signatures. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{SHA-1 Collision Attack (SHAttered)}{The first practical SHA-1 collision} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item In 2017, Google and CWI Amsterdam researchers demonstrated the first practical collision for SHA-1.\footnote{\url{https://appliedcryptography.page/papers/shattered-sha1.pdf}} + \item Created two different PDF files with identical SHA-1 hashes. + \item Required about 6,500 CPU years and 110 GPU years of computation. + \item Cost estimate: approximately \$110,000 using cloud computing. + \item Proved that SHA-1 should no longer be used for security-critical applications. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Multi-Collision Attacks} + \definitionbox{Multi-Collision}{ + A \textbf{multi-collision} is a set of $k$ distinct inputs that all hash to the same output value. + } + \begin{itemize}[<+->] + \item Joux's 2004 multi-collision attack: + \begin{itemize} + \item Finding $2^n$ colliding messages requires only about $n$ times the work of finding a single collision. + \item For a 128-bit hash, finding $2^{64}$ collisions takes only about 64 times more work than finding one collision. + \item Much more efficient than expected from the birthday paradox! + \end{itemize} + \item Implications: + \begin{itemize} + \item Concatenating two hash functions ($H_1 \| H_2$) provides much less security than expected. + \item Influences modern hash function design. + \end{itemize} + \end{itemize} +\end{frame} + +\section{Password Hashing} + +\begin{frame}{Password-based authentication}{Common use of hash functions} + \begin{itemize}[<+->] + \item Passwords are the most common authentication mechanism. + \item Server must verify if a user's password is correct. + \item Different methods for password storage: + \begin{itemize}[<+->] + \item Storing in the clear (extremely bad) + \item Encryption (also bad) + \item Unsalted hashing (better, but problematic) + \item Salted hashing (good practice) + \item Specialized password hashing (best practice) + \end{itemize} + \item We compare methods by asking: what happens if the server is compromised? + \end{itemize} +\end{frame} + +\begin{frame}{Storing passwords in the clear}{The worst approach} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \begin{itemize}[<+->] + \item Server simply stores exact passwords + \item Password verification is trivial: + \begin{itemize} + \item User enters password $P'$ + \item Server checks if $P' == P$ + \end{itemize} + \item If server is compromised, attacker immediately learns all passwords. + \item Users often reuse passwords across sites, compounding the damage. + \end{itemize} + \end{column} + \begin{column}{0.45\textwidth} + \begin{tcolorbox}[colback=black!5!white,colframe=ciphergray] + \textbf{Database Storage:} + + \vspace{0.2cm} + + \texttt{username: alice}\\ + \texttt{password: secret123} + + \vspace{0.2cm} + + \texttt{username: bob}\\ + \texttt{password: password1} + + \vspace{0.3cm} + + \textcolor{cipherprimary}{\textbf{Problem:} \small Attacker who accesses the database instantly has everyone's actual passwords!} + \end{tcolorbox} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Encrypting passwords}{A common mistake} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \begin{itemize}[<+->] + \item Some systems try to encrypt passwords: + \begin{itemize} + \item Store $\texttt{Enc}(K, P)$ instead of $P$. + \item Decrypt when verifying login. + \end{itemize} + \item Problem: The decryption key $K$ must be accessible to the server. + \item If an attacker compromises the server, they get both: + \begin{itemize} + \item The encrypted passwords. + \item The decryption key. + \end{itemize} + \item Result: Encryption adds no security! + \end{itemize} + \end{column} + \begin{column}{0.45\textwidth} + \begin{tcolorbox}[colback=black!5!white,colframe=ciphergray] + \textbf{Encrypted Password Storage:} + + \vspace{0.2cm} + + \texttt{username: alice}\\ + \texttt{password: A7F3D92C...} + + \vspace{0.2cm} + + \texttt{decryption\_key: 5B8E1...} + + \vspace{0.3cm} + + \textcolor{cipherprimary}{\textbf{Problem:} \small Server needs the key to verify passwords, so attacker gets the key too!} + \end{tcolorbox} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Unsalted password hashing}{A basic approach} + \begin{columns}[c] + \begin{column}{0.55\textwidth} + \begin{itemize}[<+->] + \item For a user with password $P$, the server stores $h = H(P)$. + \item On login, server checks if $H(P') == h$. + \item Advantages over cleartext: + \begin{itemize} + \item Attacker doesn't immediately get passwords. + \item Must spend effort guessing and hashing. + \end{itemize} + \item Problems: + \begin{itemize} + \item Vulnerable to precomputation (rainbow tables). + \item Same password = same hash for all users. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.45\textwidth} + \begin{tcolorbox}[colback=black!5!white,colframe=ciphergray] + \textbf{Unsalted Hash Storage:} + + \vspace{0.2cm} + + \texttt{username: alice}\\ + \texttt{hash: 5f4dcc3b5aa...} + + \vspace{0.2cm} + + \texttt{username: bob}\\ + \texttt{hash: 5f4dcc3b5aa...} + + \vspace{0.3cm} + + \textcolor{cipherprimary}{\textbf{Problem:} \small Alice and Bob have the same password (visible from identical hashes)!} + \end{tcolorbox} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Limitations of unsalted hashing} + \begin{itemize}[<+->] + \item Attacker's work can be \textbf{precomputed}: + \begin{itemize} + \item Generate lookup tables before compromising the server. + \item Rainbow tables provide time-memory tradeoff. + \end{itemize} + \item Same effort cracks multiple accounts: + \begin{itemize} + \item If users have same password, they have same hash. + \item Cracking 1,000 accounts may be no harder than cracking one. + \end{itemize} + \item Common passwords are instantly recognized: + \begin{itemize} + \item $H(\texttt{password123})$ is well-known. + \item Attacker doesn't even need to compute hashes for common passwords. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Salted password hashing}{The proper approach} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{Salted Hash Authentication}{ + For a user with password $P$, the server stores: + \begin{itemize} + \item A random salt $S$ (unique per user) + \item The hash value $h = H(S \| P)$ + \end{itemize} + To verify a login with password $P'$, the server checks if $H(S \| P') == h$. + } + \end{column} + \begin{column}{0.5\textwidth} + \begin{tcolorbox}[colback=black!5!white,colframe=ciphergray] + \small + \textbf{Salted Hash Storage:} + + \vspace{0.2cm} + + \texttt{username: alice}\\ + \texttt{salt: 8a7b3c...}\\ + \texttt{hash: e8f74d...} + + \vspace{0.2cm} + + \texttt{username: bob}\\ + \texttt{salt: 2c9d5e...}\\ + \texttt{hash: 9f82e1...} + + \vspace{0.3cm} + + \textcolor{cipherprimary}{\textbf{Note:} \scriptsize Even if Alice and Bob have the same password, they'll have different hashes!} + \end{tcolorbox} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Benefits of salted hashing} + \begin{itemize}[<+->] + \item Prevents precomputation attacks: + \begin{itemize} + \item Rainbow tables become useless. + \item Attacker must compute hashes after server compromise. + \end{itemize} + \item Requires unique effort per user: + \begin{itemize} + \item Each password must be attacked individually. + \item Cracking 1,000 accounts requires 1,000 times the effort. + \end{itemize} + \item Same passwords produce different hashes: + \begin{itemize} + \item Identical passwords across users aren't visible. + \item Doesn't leak information about password reuse. + \end{itemize} + \item \textbf{Always salt your password hashes!} + \end{itemize} +\end{frame} + +\begin{frame}{Specialized password hashing functions}{Beyond regular hash functions} + \begin{itemize}[<+->] + \item Regular cryptographic hash functions (SHA-2, SHA-3) are designed to be \textbf{fast}. + \item But password hashing, slower is better! + \begin{itemize} + \item Makes attacks more expensive. + \item Users don't notice milliseconds of delay. + \item Attackers trying billions of guesses definitely notice. + \end{itemize} + \item Simple approach: Iterate the hash function thousands of times. + \begin{itemize} + \item $H(S, H(S, ... H(S,P)...))$ with many iterations. + \item \textbf{Obsolete examples}: PBKDF2. + \item \textbf{Modern examples}: Argon2, Scrypt + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{PBKDF2: Password-Based Key Derivation Function 2} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \definitionbox{PBKDF2}{ + \textbf{PBKDF2} (Password-Based Key Derivation Function 2) is a key derivation function that applies a pseudorandom function (like HMAC) to the input password along with a salt to produce a derived key. + } + \begin{itemize}[<+->] + \item Key components: + \begin{itemize} + \item \textbf{Password}: Secret input. + \item \textbf{Salt}: Provides randomization. + \item \textbf{Iteration count}: Controls computational cost. + \item \textbf{PRF}: Usually HMAC-SHA1 or HMAC-SHA256. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \begin{tcolorbox}[colback=black!5!white,colframe=ciphergray] + \small + \begin{align*} + U_1 & = PRF(Password, Salt || Int(1)) \\ + U_2 & = PRF(Password, U_1) \\ + U_3 & = PRF(Password, U_2) \\ + \vdots \\ + U_c & = PRF(Password, U_{c-1}) \\ + T_1 & = U_1 \oplus U_2 \oplus ... \oplus U_c \\ + \end{align*} + \end{tcolorbox} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Why not PBKDF2?}{Vulnerable to specialized hardware} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Problem}: Attackers can build specialized hardware. + \begin{itemize} + \item ASICs can compute hashes millions of times faster. + \item Iteration alone isn't enough protection. + \end{itemize} + \item \textbf{Solution}: Memory-hard functions + \begin{itemize} + \item Require significant amount of memory. + \item Hardware specialization offers less advantage. + \item Both attackers and defenders use similar memory tech. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{gpu_farm.jpg}{A GPU farm, likely built to mine Bitcoin, but which can also be used to do a lot of hashing really fast (Bitcoin mining is just calcualting a lot of SHA-256 hashes!)} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Blockchain and hash functions} + \begin{itemize}[<+->] + \item Bitcoin and blockchain technology rely heavily on hash functions: + \begin{itemize} + \item \textbf{Proof-of-work}: Finding partial hash collisions (leading zeros). + \item \textbf{Merkle trees}: Efficient verification of large datasets. + \item \textbf{Block chaining}: Each block contains the hash of the previous block. + \end{itemize} + \item Miners try to find inputs that produce hashes with specific properties. + \item The extreme computational cost of Bitcoin mining (~90 TWh/year) demonstrates hash function security. + \item Bitcoin mining consumes more electricity than many countries. + \end{itemize} +\end{frame} + +\begin{frame}{Scrypt: A memory-hard password hashing function} + \definitionbox{Scrypt}{ + \textbf{Scrypt} is a password-based key derivation function designed to be computationally and memory-intensive, making it resistant to hardware acceleration attacks. + } + \begin{itemize}[<+->] + \item Created by Colin Percival in 2009 specifically to make attacks costly. + \item Key components: + \begin{itemize} + \item \textbf{PBKDF2}: Initial and final mixing of password and salt. + \item \textbf{ROMix}: Core memory-hard function. + \item \textbf{BlockMix}: Based on Salsa20/8 core function. + \end{itemize} + \item{Parameters:} + \begin{itemize} + \item \texttt{N}: CPU/memory cost + \item \texttt{r}: Block size + \item \texttt{p}: Parallelization + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Why Scrypt is memory-hard} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item Scrypt enforces memory hardness through its ROMix function: + \begin{itemize} + \item Creates a large array of pseudorandom values (often many MB). + \item Each new value depends on previous values in unpredictable patterns. + \item Forces the entire array to be stored in memory during computation. + \end{itemize} + \item Memory hardness creates multiple benefits: + \begin{itemize} + \item GPUs/ASICs have limited memory per processing unit. + \item Memory is expensive and scales poorly on specialized hardware. + \item Time-memory tradeoffs are possible but highly unfavorable. + \item Using less memory makes computation exponentially slower. + \end{itemize} + \item Even with custom hardware, attackers face similar costs to defenders. + \item Proven to be maximally memory-hard!\footnote{\url{https://appliedcryptography.page/papers/scrypt-memory.pdf}} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Password cracking speeds}{The importance of slow hashing} + \begin{itemize}[<+->] + \item Modern hardware can compute hash functions at astonishing speeds. + \item A single high-end GPU can compute: + \begin{itemize} + \item MD5: 25+ billion hashes/second + \item SHA-1: 10+ billion hashes/second + \item SHA-256: 2+ billion hashes/second + \item bcrypt (cost 12): 20,000 hashes/second + \item Scrypt: <1,000 hashes/second + \end{itemize} + \item This is why specialized password hashing algorithms are essential. + \item The stark speed difference (billions vs. thousands) is a critical security factor. + \end{itemize} +\end{frame} + +\begin{frame}{Best practices for password hashing} + \begin{itemize}[<+->] + \item Use a dedicated password hashing function (not raw SHA-256). + \item Always use random, unique salts (at least 16 bytes). + \item Store salts alongside hashes - they don't need to be secret. + \item Consider modern memory-hard functions like Scrypt. + \begin{itemize} + \item Tune parameters based on your server capabilities. + \item Aim for 0.5-1 second processing time per hash. + \end{itemize} + \item Keep your hashing mechanism current: + \begin{itemize} + \item Cryptographic advice changes as attacks improve. + \item Be prepared to migrate to stronger algorithms. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{``Migrate to stronger algorithms?''} + \begin{itemize}[<+->] + \item Cryptographic algorithms have limited lifespans: + \begin{itemize} + \item New attacks emerge over time. + \item Computing power continuously increases. + \item Quantum computers threaten some algorithms. + \end{itemize} + \item \textbf{Protocol agility} refers to a system's ability to: + \begin{itemize} + \item Support multiple cryptographic algorithms. + \item Negotiate which algorithm to use. + \item Transition smoothly as algorithms are deprecated. + \end{itemize} + \item Challenges with protocol agility: + \begin{itemize} + \item Complexity leads to implementation errors. + \item Downgrade attacks target weakest supported option. + \item Backward compatibility vs. security tradeoffs. + \end{itemize} + \item We'll talk a lot more about all of this in Part 2 of the course. + \end{itemize} +\end{frame} + +\section{The Random Oracle Model} + +\begin{frame}{Hash functions can't be truly pseudorandom} + \begin{itemize}[<+->] + \item Any deterministic algorithm cannot produce truly random output. + \item Hash functions only statistically approximate pseudorandomness: + \begin{itemize} + \item They attempt to distribute outputs uniformly across their range, + \item They aim to make outputs appear uncorrelated with inputs, + \item But they remain deterministic functions. + \end{itemize} + \item But we analyze hash functions as if they were truly random oracles! + \begin{itemize} + \item This creates a gap between theory and implementation. + \item Implementations can only ever approximate ideal properties. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{The Random Oracle Model} + \definitionbox{Random Oracle Model}{ + The \textbf{Random Oracle Model} is a theoretical framework that models hash functions as truly random functions that can be queried by all parties. + } + \begin{itemize}[<+->] + \item A random oracle is an idealized black box that: + \begin{itemize} + \item Responds to new queries with truly random outputs. + \item Consistently returns the same output when queried with the same input. + \item Can be accessed by all parties (both honest and adversarial). + \end{itemize} + \item Provides a mathematical abstraction that's easier to analyze than actual hash functions + \end{itemize} +\end{frame} + +\begin{frame}{Using the Random Oracle Model} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Used to prove security of cryptographic protocols: + \begin{itemize} + \item Allows rigorous mathematical analysis. + \item Simplifies proofs that would otherwise be intractable. + \item Many important schemes are proven secure in this model. + \end{itemize} + \item Example: OAEP for RSA encryption. + \item Provides confidence in schemes before deployment. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Proving in the ROM:} + \begin{enumerate} + \item Replace hash function with random oracle + \item Show adversary has negligible advantage. + \item Conclude the scheme is secure (assuming the hash function behaves like a random oracle). + \end{enumerate} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Limitations of the Random Oracle Model} + \begin{columns} + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Gap between theory and practice}: + \begin{itemize} + \item No real hash function can perfectly implement a random oracle. + \item Schemes secure in the RO model might be insecure when implemented with real hash functions. + \end{itemize} + \item \textbf{Artificial counterexamples exist}: + \begin{itemize} + \item Researchers have constructed schemes that are: + \item Provably secure in the RO model, but, + \item Provably insecure with any real hash function.\footnote{\url{https://appliedcryptography.page/papers/rom-methodology.pdf}} + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/1-7.tex b/slides/1-7.tex new file mode 100644 index 0000000..3cf6cb6 --- /dev/null +++ b/slides/1-7.tex @@ -0,0 +1,1415 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 1: Provable Security} +\covertopicname{1.7: Hard Problems \&\\Diffie-Hellman} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{How it's made} + \bigimagewithcaption{fischer.png}{Fischer et al., The Challenges of Bringing Cryptography from Research Papers to Products: Results from an Interview Study with Experts, USENIX Security 2024} +\end{frame} + +\begin{frame}{Cryptographic building blocks} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Security goals} + \begin{itemize}[<+->] + \item \textbf{Confidentiality}: Data exchanged between Client and Server + is only known to those parties. + \item \textbf{Authentication}: If Server receives data from Client, + then Client sent it to Server. + \item \textbf{Integrity}: If Server modifies data owned by Client, + Client can find out. + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \textbf{Examples} + \begin{itemize}[<+->] + \item \textbf{Confidentiality}: When you send a private message on Signal, + only you and the recipient can read the content. + \item \textbf{Authentication}: When you receive an email from your boss, + you can verify it actually came from them. + \item \textbf{Integrity}: Your computer can verify that software update + downloads haven't been tampered with during transmission. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Security goals: more examples} + \begin{itemize}[<+->] + \item \textbf{TLS (HTTPS)} ensures that data exchanged between the client + and the server is confidential and that parties are authenticated. + \begin{itemize} + \item Allows you to log into gmail.com without your ISP learning your password. + \end{itemize} + \item \textbf{FileVault 2} ensures data confidentiality and integrity on + your MacBook. + \begin{itemize} + \item Prevents thieves from accessing your data if your MacBook is stolen. + \end{itemize} + \item \textbf{Signal} implements post-compromise security, an advanced security + goal. + \begin{itemize} + \item Allows a conversation to ``heal'' in the event of a temporary key + compromise. + \item More on that later in the course. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Why bother?} + \begin{itemize}[<+->] + \item Can't we just use access control? + \item Strictly speaking, usernames and passwords can be implemented + without cryptography\ldots + \item Server checks if the password matches, or if the IP address matches, + etc. before granting access. + \item What's so bad about that? + \end{itemize} + \definitionbox{The Problem with Traditional Access Control}{ + \begin{itemize}[<+->] + \item Requires trusting the server completely + \item No protection during transmission + \item No way to verify integrity + \item No way to establish trust between strangers + \end{itemize} + } +\end{frame} + +\begin{frame}[c]{The magic of cryptography} + \begin{center} + \Large\textbf{Cryptography lets us achieve what seems impossible} + \vspace{1cm} + \begin{itemize}[<+->] + \item Secure communication over insecure channels + \item Verification without revealing secrets + \item Proof of computation without redoing it + \end{itemize} + \end{center} +\end{frame} + +\section{Hard Problems} + +\begin{frame}{Hard problems} + \begin{itemize}[<+->] + \item Cryptography is largely about equating the security of a system to the + difficulty of solving a math problem that is thought to be computationally + very expensive. + \item With cryptography, we get security systems that we can literally + mathematically prove as secure (under assumptions). + \item Also, this allows for actual magic. + \begin{itemize}[<+->] + \item Alice and Bob meet for the first time in the same room as you. + \item You are listening to everything they are saying. + \item Can they exchange a secret without you learning it? + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Time for actual magic} + \bigimagewithcaption{dh.png}{} +\end{frame} + +\begin{frame}{No known feasible computation} + \begin{itemize}[<+->] + \item The discrete logarithm problem: + \begin{itemize} + \item Given a finite cyclic group $G$, a generator $g \in G$, and an element + $h \in G$, find the integer $x$ such that $g^{x}=h$ + \end{itemize} + \item In more concrete terms: + \begin{itemize} + \item Let $p$ be a large prime and let $g$ be a generator of the multiplicative + group $\mathbb{Z}_{p}^{*}$ (all nonzero integers modulo $p$). + + \item Given: + \begin{itemize} + \item $g \in \mathbb{Z}_{p}^{*}$, $h \in \mathbb{Z}_{p}^{*}$ + + \item Find $x \in \{0, 1, \ldots, p-2\}$ such that $g^{x} \equiv h \pmod + {p}$ + \end{itemize} + + \item This problem is believed to be computationally hard when $p$ is large + and $g$ is a primitive root modulo $p$. + \begin{itemize} + \item ``Believed to be'' = we don't know of any way to do it that doesn't + take forever, unless we have a strong, stable quantum computer (Shor's + algorithm) + \end{itemize} + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Time for more actual magic} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Zero-knowledge proofs} allow you to prove that you know + a secret without revealing any information about it. + \item They built ``zero-knowledge virtual machines'' where you can execute + an entire program that runs as a zero-knowledge proof. + \item ZKP battleship game: server proves to the players that its + output to their battleship guesses is correct, without revealing any + additional information (e.g. ship location). + \end{itemize} + \end{column} + + \begin{column}{0.4\textwidth} + \imagewithcaption{battleship.jpg}{Battleship board game. Source: Hasbro} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Hard problems} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Asymmetric Primitives} + \begin{itemize}[<+->] + \item Diffie-Hellman, RSA, ML-KEM, etc. + \item ``Asymmetric'' because there is a ``public key'' and a ``private + key'' for each party. + \item Algebraic, assume the hardness of mathematical problems (as seen + just now.) + \end{itemize} + \end{column} + + \begin{column}{0.5\textwidth} + \textbf{Symmetric Primitives} + \begin{itemize}[<+->] + \item AES, SHA-2, ChaCha20, HMAC\ldots + \item ``Symmetric'' because there is one secret key. + \item Not algebraic but unstructured, but on their understood + resistance to $n$ years of cryptanalysis. + \item Can act as substitutes for assumptions in security proofs! + \begin{itemize} + \item Example: hash function assumed to be a ``random oracle'' + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Hard problems} + \begin{itemize}[<+->] + \item Hard computational problems are the cornerstone of modern cryptography. + \item These are problems for which even the best algorithms wouldn't find a solution before the sun burns out. + \item They provide the security foundation for cryptographic schemes. + \item Without hard problems, most of our encryption systems would collapse. + \end{itemize} +\end{frame} + +\begin{frame}{The rise of computational complexity theory} + \definitionbox{Computational Complexity Theory}{Complexity theory provides the mathematical framework to understand what makes problems ``hard''.} + \begin{itemize} + \item In the 1970s, rigorous study of hard problems led to computational complexity theory. + \item This field has had dramatic impacts beyond cryptography: + \begin{itemize} + \item \textbf{Economics}: Computational complexity of finding Nash equilibria in game theory. + \item \textbf{Physics}: Simulating quantum many-body systems with exponential complexity. + \item \textbf{Biology}: Protein folding prediction and DNA sequence alignment algorithms. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Computational problems} + \definitionbox{Computational Problem}{ + A question that can be answered by performing a computation. + \begin{itemize} + \item \textbf{Decision problems}: Questions with ``yes'' or ``no'' answers + \begin{itemize} + \item Example: ``Is 217 a prime number?'' + \end{itemize} + \item \textbf{Search problems}: Questions that require finding a specific value + \begin{itemize} + \item Example: ``How many instances of \textit{`i'}s appear in \textit{`incomprehensibilities'}?'' + \end{itemize} + \end{itemize} + } + \begin{itemize}[<+->] + \item Computational problems form the foundation of theoretical computer science. + \item Different types of problems require different algorithmic approaches. + \item The difficulty of solving these problems is central to cryptography. + \end{itemize} +\end{frame} + +\begin{frame}{Computational hardness} + \definitionbox{Computational Hardness}{ + The property of computational problems for which no algorithm exists that can solve the problem in a reasonable amount of time. + \begin{itemize} + \item Also called \textbf{intractable problems}. + \item Hardness is independent of the computing device used. + \item All standard computing models are equivalent in terms of what they can compute efficiently. + \item \textbf{Exception}: Quantum computers for certain problems. + \end{itemize} + } + \begin{itemize}[<+->] + \item Hardness is a fundamental concept in computational complexity theory. + \item Cryptography deliberately uses hard problems to create security. + \item What's ``hard'' should remain hard regardless of hardware advances. + \end{itemize} +\end{frame} + +\begin{frame}{Measuring algorithm complexity} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize}[<+->] + \item To evaluate computational hardness, we need to measure an algorithm's running time. + \item We typically use \textbf{asymptotic analysis} to express complexity. + \item Common notation: + \begin{itemize} + \item $O(n)$: Linear time. + \item $O(n^2)$: Quadratic time. + \item $O(2^n)$: Exponential time. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \imagewithcaption{complexity.png}{Complexity classes growth. Source: Serious Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Measuring algorithm complexity} + \begin{itemize} + \item To evaluate computational hardness, we need to measure an algorithm's running time. + \item We typically use \textbf{asymptotic analysis} to express complexity. + \item Common notation: + \begin{itemize} + \item $O(n)$: Linear time. + \item $O(n^2)$: Quadratic time. + \item $O(2^n)$: Exponential time. + \end{itemize} + \item We care about how the running time grows as the input size increases. + \item \textbf{Example}: An algorithm that takes $n^2$ operations for input size $n$ becomes impractical as $n$ grows large. + \end{itemize} +\end{frame} + +\begin{frame}{Categorizing computational hardness} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Easy Problems} + \begin{itemize}[<+->] + \item Solvable in polynomial time. + \item \textbf{Examples}: Sorting, searching. + \item Running time: $O(n^c)$ for some constant $c$ + \item Generally scales reasonably with input size. + \item Class P (Polynomial time). + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Hard Problems} + \begin{itemize}[<+->] + \item No known polynomial-time solution. + \item \textbf{Example}: Factorizing product of two large primes. + \item Running time: Often exponential, e.g., $O(2^n)$ + \item Becomes impractical quickly as input grows. + \item Includes NP-hard, NP-complete classes. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Hard problems in practice} + \begin{itemize} + \item Public-key cryptography relies on specific hard problems: + \begin{itemize} + \item RSA: Integer factorization problem. + \item Diffie-Hellman: Discrete logarithm problem. + \end{itemize} + \item Cryptography leverages these problems to maximize security assurance, + \item The security of these schemes depends on the continued hardness of these problems. + \end{itemize} +\end{frame} + +\begin{frame}{Quantum vulnerability of hard problems} + \begin{itemize}[<+->] + \item The hard problems we rely on today (factoring, discrete logarithm) are vulnerable to quantum computers. + \item Shor's algorithm (1994) can efficiently solve both problems on a sufficiently powerful quantum computer. + \item This has motivated the search for \textbf{``post-quantum''} hard problems: + \begin{itemize}[<+->] + \item Lattice-based cryptography (e.g., ML-KEM, formerly CRYSTALS-Kyber). + \item Hash-based cryptography. + \item Code-based cryptography. + \item Multivariate cryptography. + \item Isogeny-based cryptography. + \end{itemize} + \item NIST is currently standardizing post-quantum cryptographic algorithms to replace our vulnerable systems. + \end{itemize} +\end{frame} + +\begin{frame}{What is NIST?} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{NIST} stands for the National Institute of Standards and Technology. + \item It's a U.S. government agency that develops technology standards. + \item In cryptography, NIST: + \begin{itemize} + \item Sets security standards used worldwide. + \item Evaluates and approves cryptographic algorithms. + \item Currently leading the standardization of post-quantum cryptography. + \end{itemize} + \item When NIST standardizes an algorithm, it often becomes the global industry standard. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{nist_peanut.png}{NIST's ``Standard Reference Peanut Butter'', available for only \$1,217 USD!} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Funny things standardized by NIST} + \begin{itemize}[<+->] + \item \textbf{Standard Reference Peanut Butter}: for calibrating food testing equipment. + \item \textbf{The ``Odor Unit''}: for standardizing measurements of smell intensity in environmental monitoring. + \item \textbf{The Standard Banana Equivalent Dose (BED)}: for comparing radiation exposure levels to the natural radiation in a banana. + \item \textbf{Toilet Paper Testing}: for measuring strength, absorbency, and softness of toilet paper products. + \end{itemize} +\end{frame} + +\begin{frame}{Cryptographic algorithms standardized by NIST} + \begin{itemize}[<+->] + \item \textbf{AES (Advanced Encryption Standard)}: Selected in 2001 to replace DES, now the worldwide standard for symmetric encryption. + \item \textbf{SHA-2 and SHA-3 (Secure Hash Algorithms)}: Cryptographic hash functions used for digital signatures and data integrity. + \item \textbf{DSA and ECDSA}: Digital Signature Algorithms based on the discrete logarithm problem. + \item \textbf{Triple DES}: An interim standard before AES that enhanced the security of the original DES. + \item \textbf{ML-KEM and ML-DSA}: Recently standardized post-quantum public-key cryptography and signature schemes. + \end{itemize} +\end{frame} + +\begin{frame}{Why hard problems matter} + \begin{itemize} + \item Hard problems \textbf{create asymmetry between legitimate users and attackers}. + \item Easy in one direction, difficult in the reverse. + \item Example: Easy to multiply large primes, hard to factor the product. + \item This asymmetry is what enables secure communication! + \end{itemize} +\end{frame} + +\begin{frame}{What are complexity classes?} + \definitionbox{Complexity Class}{ + A group of computational problems that share similar resource requirements (time, memory, etc.). + } + \begin{itemize}[<+->] + \item \textbf{Example}: All problems solvable in $O(n^2)$ time form one class. + \item Different classes represent different levels of computational difficulty. + \item Understanding these classes helps us categorize cryptographic problems. + \end{itemize} +\end{frame} + +\begin{frame}{TIME complexity classes} + \begin{itemize}[<+->] + \item \textbf{TIME}$(f(n))$ = class of problems solvable in time $O(f(n))$ + \item Examples: + \begin{itemize} + \item \textbf{TIME}$(n^2)$ = problems solvable in $O(n^2)$ time + \item \textbf{TIME}$(n^3)$ = problems solvable in $O(n^3)$ time + \item \textbf{TIME}$(2^n)$ = problems solvable in $O(2^n)$ time + \end{itemize} + \item \textbf{Key insight}: If you can solve a problem in $O(n^2)$ time, you can also solve it in $O(n^3)$ time. + \item Therefore: \textbf{TIME}$(n^2) \subseteq$ \textbf{TIME}$(n^3) \subseteq$ \textbf{TIME}$(n^4) \subseteq \ldots$ + \end{itemize} +\end{frame} + +\begin{frame}{The class P (Polynomial time)} + \definitionbox{Class P}{ + The union of all \textbf{TIME}$(n^k)$ classes for all constants $k$. + \begin{itemize} + \item P = \textbf{TIME}$(n) \cup$ \textbf{TIME}$(n^2) \cup$ \textbf{TIME}$(n^3) \cup \ldots$ + \item Contains all problems solvable in polynomial time. + \item Generally considered ``efficiently solvable''. + \end{itemize} + } + \begin{itemize}[<+->] + \item Most practical algorithms we use daily are in class P. + \item Examples: Sorting, searching, basic arithmetic. + \item Cryptography often relies on problems \textbf{not} in P! + \end{itemize} +\end{frame} + +\begin{frame}{SPACE complexity classes} + \begin{itemize}[<+->] + \item Time isn't everything—memory usage matters too! + \item A single memory access can be orders of magnitude slower than CPU operations. + \item \textbf{SPACE}$(f(n))$ = class of problems solvable using $O(f(n))$ bits of memory + \item Examples: + \begin{itemize} + \item \textbf{SPACE}$(n)$ = problems using $O(n)$ memory + \item \textbf{SPACE}$(n^2)$ = problems using $O(n^2)$ memory + \end{itemize} + \item \textbf{PSPACE} = union of all \textbf{SPACE}$(n^k)$ for constants $k$ + \end{itemize} +\end{frame} + +\begin{frame}{Relationship between TIME and SPACE} + \begin{itemize}[<+->] + \item \textbf{Key insight}: Any algorithm running in time $f(n)$ uses at most $f(n)$ memory. + \item Why? You can write at most one bit per time unit. + \item Therefore: \textbf{TIME}$(f(n)) \subseteq$ \textbf{SPACE}$(f(n))$ + \item This gives us: $P \subseteq PSPACE$ + \item \textbf{Important}: Low memory doesn't guarantee fast execution! + \begin{itemize} + \item Example: Brute-force key search uses little memory but takes forever. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{The class NP (Nondeterministic Polynomial time)} + \definitionbox{Class NP}{ + The class of decision problems for which you can \textbf{verify} a solution in polynomial time, even if finding the solution is hard. + } + \begin{itemize}[<+->] + \item \textbf{Key insight}: Easy to check, hard to find! + \item Given a potential solution, you can run a polynomial-time algorithm to verify if it's correct. + \item You don't need to find the solution efficiently—only verify it efficiently. + \item \textbf{Relationship}: $P \subseteq NP$ (if you can solve it quickly, you can certainly verify it quickly) + \end{itemize} +\end{frame} + +\begin{frame}{NP: A cryptographic example} + \textbf{Problem}: Given plaintext $P$ and ciphertext $C$, does there exist a key $K$ such that $C = E(K, P)$? + \begin{itemize}[<+->] + \item \textbf{Finding the solution}: Could take exponential time (brute-force key search) + \item \textbf{Verifying a candidate solution}: Given a potential key $K_0$: + \begin{enumerate} + \item Compute $E(K_0, P)$ + \item Check if $E(K_0, P) = C$ + \item Return ``yes'' if they match, ``no'' otherwise + \end{enumerate} + \item This verification runs in polynomial time! + \item Therefore, this key recovery problem is in NP. + \end{itemize} +\end{frame} + +\begin{frame}{What's NOT in NP?} + \begin{itemize}[<+->] + \item \textbf{Known-ciphertext attacks}: You only have $E(K, P)$ values for random unknown plaintexts $P$. + \begin{itemize} + \item How do you verify if candidate key $K_0$ is correct? + \item You don't know what the plaintexts should be! + \item Can't express this as a decision problem with efficient verification. + \end{itemize} + \item \textbf{Proving absence of solutions}: ``Does there exist NO solution to this problem?'' + \begin{itemize} + \item To verify ``no solution exists,'' you might need to check all possible inputs. + \item If there are exponentially many inputs, this takes exponential time. + \item Therefore, proving non-existence is generally not in NP. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{NP-complete problems} + \definitionbox{NP-Complete Problems}{ + The hardest decision problems in the class NP. + \begin{itemize} + \item No known polynomial-time algorithms exist for worst-case instances. + \item If any NP-complete problem can be solved efficiently, then \textbf{all} problems in NP can be solved efficiently. + \end{itemize} + } + \begin{itemize}[<+->] + \item Discovered in the 1970s during the development of complexity theory. + \item \textbf{Remarkable discovery}: All NP-complete problems are fundamentally equally hard! + \item Examples: Boolean satisfiability (SAT), traveling salesman problem, graph coloring. + \end{itemize} +\end{frame} + +\begin{frame}{Why are NP-complete problems equally hard?} + \begin{itemize}[<+->] + \item \textbf{Key insight}: You can \textit{reduce} any NP-complete problem to any other NP-complete problem. + \item \textbf{Reduction}: Transform one problem into another in polynomial time. + \begin{itemize} + \item If you can solve problem B efficiently, you can solve problem A efficiently too. + \end{itemize} + \item \textbf{Mathematical equivalence}: Different NP-complete problems may look completely different but are fundamentally the same from a computational perspective. + \item \textbf{Consequence}: Solving any single NP-complete problem efficiently would solve \textit{all} problems in NP efficiently! + \begin{itemize} + \item This would prove that P = NP (one of the biggest open questions in computer science). + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{The remarkable equivalence of NP-complete problems} + \begin{center} + \Large\textbf{These problems look completely different...} + \vspace{0.5cm} + + \begin{columns}[c] + \begin{column}{0.33\textwidth} + \textbf{Boolean Logic}\\ + \small Can you set variables to make this formula true?\\ + $(x_1 \lor \neg x_2) \land (x_2 \lor x_3) \land \ldots$ + \end{column} + \begin{column}{0.33\textwidth} + \textbf{Travel Planning}\\ + \small What's the shortest route visiting all cities exactly once? + \end{column} + \begin{column}{0.33\textwidth} + \textbf{Sudoku Puzzles}\\ + \small Can you fill this 9×9 grid following the rules? + \end{column} + \end{columns} + \vspace{0.5cm} + + \Large\textbf{...but they're computationally identical!} + \end{center} +\end{frame} + +\begin{frame}{Concrete examples of equivalent problems} + \begin{itemize}[<+->] + \item \textbf{3-SAT} (Boolean satisfiability): Given a logical formula, can you set the variables to make it true? + \begin{itemize} + \item Example: $(x_1 \lor \neg x_2 \lor x_3) \land (\neg x_1 \lor x_2 \lor \neg x_3) \land \ldots$ + \end{itemize} + \item \textbf{Traveling Salesman Problem}: Given cities and distances, what's the shortest route visiting each city exactly once? + \begin{itemize} + \item Looks like a geometry/optimization problem! + \end{itemize} + \item \textbf{Graph Coloring}: Can you color a graph's vertices with $k$ colors so no adjacent vertices share a color? + \begin{itemize} + \item Looks like a combinatorial puzzle! + \end{itemize} + \item \textbf{Subset Sum}: Given a set of integers, is there a subset that sums to exactly $k$? + \begin{itemize} + \item Looks like an arithmetic problem! + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{The magic of reductions} + \definitionbox{Problem Reduction}{ + A polynomial-time transformation that converts any instance of problem A into an equivalent instance of problem B. + } + \begin{itemize}[<+->] + \item You can transform \textbf{any} Sudoku puzzle into a Boolean logic formula! + \begin{itemize} + \item The Sudoku has a solution $\Leftrightarrow$ the formula is satisfiable + \end{itemize} + \item You can transform \textbf{any} traveling salesman instance into a graph coloring problem! + \item You can transform \textbf{any} Boolean formula into a subset sum problem! + \item These transformations preserve the ``yes/no'' answer and run in polynomial time. + \item \textbf{Mind-blowing consequence}: Solve Sudoku efficiently = solve all of theoretical computer science! + \end{itemize} +\end{frame} + +\begin{frame}{Real-world impact of this equivalence} + \begin{itemize}[<+->] + \item \textbf{Good news}: Any algorithmic breakthrough on one NP-complete problem immediately applies to thousands of others! + \begin{itemize} + \item Better SAT solvers $\Rightarrow$ better protein folding, circuit design, AI planning... + \end{itemize} + \item \textbf{Sobering reality}: 50+ years of computer science research suggests these problems are fundamentally hard. + \begin{itemize} + \item Despite massive incentives (millions in prize money, practical applications worth billions) + \end{itemize} + \item \textbf{Cryptographic relevance}: We rely on NP-complete problems being hard for certain security models. + \begin{itemize} + \item Though most practical cryptography uses different hard problems (factoring, discrete log) + \end{itemize} + \item \textbf{Universal truth}: The computational universe has these deep, hidden connections that unite seemingly unrelated problems. + \end{itemize} +\end{frame} + +\begin{frame}{Fun fact: Nintendo games are NP-hard!} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Games proven NP-hard\footnote{\url{https://appliedcryptography.page/papers/nintendo-hard.pdf}}}: + \begin{itemize} + \item Super Mario Bros. 1–3, The Lost Levels, Super Mario World + \item Donkey Kong Country 1–3 + \item All classic Legend of Zelda games + \item All classic Metroid games + \item All classic Pokémon role-playing games + \end{itemize} + \item \textbf{The catch}: ``Generalized versions'' with arbitrarily large levels. + \begin{itemize} + \item Real Nintendo levels are designed to be solvable by humans. + \item But the \textbf{mathematical structure} of these games is inherently complex. + \end{itemize} + \item \textbf{Cool insight}: Video games naturally encode complex computational problems! + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The P vs. NP Problem} + \definitionbox{The P vs. NP Problem}{ + One of the most important unsolved problems in computer science and mathematics. + \begin{itemize} + \item \textbf{Question}: Does P = NP? + \item \textbf{Translation}: Are there problems that are easy to verify but fundamentally hard to solve? + \end{itemize} + } + \begin{itemize}[<+->] + \item If you could solve \textbf{any} NP-complete problem in polynomial time, then you could solve \textbf{all} NP problems in polynomial time. + \item This would mean P = NP. + \item \textbf{Intuition says}: Surely some problems are easy to check but hard to find! + \item \textbf{Example}: Brute-force key recovery seems inherently exponential-time... + \item \textbf{Reality}: No one has proved this mathematically! + \end{itemize} +\end{frame} + +\begin{frame}{The million-dollar question} + \begin{itemize}[<+->] + \item The \textbf{Clay Mathematics Institute} offers \$1,000,000 for solving P vs. NP. + \item One of seven ``Millennium Prize Problems''. + \item Renowned complexity theorist Scott Aaronson called it \textit{``one of the deepest questions that human beings have ever asked''}. + \item \textbf{To win}: Prove either $P = NP$ or $P \neq NP$. + \item Over 50 years of research, no solution yet! + \end{itemize} +\end{frame} + +\begin{frame}{What if P = NP?} + \begin{center} + \Large\textbf{The cryptographic apocalypse scenario} + \end{center} + \begin{itemize}[<+->] + \item If P = NP, then \textbf{any easily checked solution would also be easy to find}. + \item \textbf{Symmetric cryptography} would be completely broken: + \begin{itemize} + \item Key recovery becomes polynomial-time. + \item AES, ChaCha20, all symmetric ciphers become useless. + \end{itemize} + \item \textbf{Hash functions} would be invertible in polynomial time: + \begin{itemize} + \item Finding preimages becomes easy. + \item Digital signatures, password storage, all broken. + \end{itemize} + \item \textbf{All of modern cryptography} would collapse overnight! + \item \textbf{But also}: We could solve protein folding, optimize supply chains perfectly, solve climate modeling... + \end{itemize} +\end{frame} + +\begin{frame}{Why we don't panic} + \begin{itemize}[<+->] + \item \textbf{Overwhelming consensus}: Most complexity theorists believe $P \neq NP$. + \item \textbf{Intuitive reasoning}: Problems that look hard actually \textbf{are} hard. + \item \textbf{The structure of reality}: Easy-to-verify but hard-to-solve problems seem fundamental to the universe. + \item \textbf{50+ years of evidence}: Despite massive incentives, no polynomial-time algorithms found for NP-complete problems. + \item \textbf{Current belief}: P is a strict subset of NP, with NP-complete problems outside P. + \end{itemize} + \definitionbox{The Challenge}{ + \begin{itemize} + \item \textbf{Proving $P = NP$}: Need only one polynomial-time algorithm for one NP-complete problem + \item \textbf{Proving $P \neq NP$}: Must prove no such algorithm can \textbf{ever} exist—much harder! + \end{itemize} + } +\end{frame} + +\begin{frame}{Why NP-complete problems don't work for cryptography} + \begin{itemize}[<+->] + \item \textbf{Tempting idea}: Base cryptography on NP-complete problems for provable security! + \item \textbf{The dream}: Prove that breaking some cipher is NP-hard. + \begin{itemize} + \item Security would be guaranteed as long as $P \neq NP$. + \end{itemize} + \item \textbf{Reality is disappointing}: NP-complete problems are hard in the \textbf{worst case}, not the \textbf{average case} + \begin{itemize} + \item The structure that makes them hard can make specific instances easy. + \item Cryptography needs problems that are hard for \textbf{random} instances. + \end{itemize} + \item \textbf{What we actually use}: Problems that are probably \textbf{not} NP-hard. + \begin{itemize} + \item Factoring, discrete logarithm, lattice problems. + \item Believed hard on average, but not proven NP-complete. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{NP-complete vs. NP-hard} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{NP-Complete Problems} + \begin{itemize}[<+->] + \item Must be decision problems (yes/no answers) + \item You can verify solutions in polynomial time + \item \textbf{Examples}: 3-SAT, graph coloring, subset sum + \item The ``sweet spot'' of hardness + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{NP-Hard Problems} + \begin{itemize}[<+->] + \item Can be any type of problem (optimization, etc.) + \item May not have polynomial-time verification + \item \textbf{Examples}: Traveling salesman optimization, halting problem + \item Can be even harder than NP-complete! + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Average-case vs. worst-case hardness} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Worst-case hardness (NP-complete)} + \begin{itemize}[<+->] + \item Some instances of the problem are very hard. + \item Other instances might be easy. + \item \textbf{Example}: 3-SAT has hard instances, but also trivial ones. + \item Not suitable for cryptography. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Average-case hardness (Crypto)} + \begin{itemize}[<+->] + \item Random instances are typically hard. + \item Few (if any) easy instances. + \item \textbf{Example}: Factoring random large integers. + \item Perfect for cryptographic applications. + \end{itemize} + \end{column} + \end{columns} + \vspace{0.5cm} + \definitionbox{Hard Problems for Cryptography}{ + We need problems where almost every instance is hard, not just the worst ones. + } +\end{frame} + +\section{Diffie-Hellman} + +\begin{frame}{Time for actual magic} + \bigimagewithcaption{dh.png}{} +\end{frame} + +\begin{frame}{The key exchange problem} + \begin{itemize}[<+->] + \item Alice and Bob want to communicate securely over the internet. + \item They've never met before and share no secrets. + \item How can they establish a shared secret key for encryption? + \item Traditional approach: meet in person, exchange keys physically. + \item \textbf{Problem}: This doesn't scale for the internet! + \end{itemize} + \definitionbox{The Challenge}{ + Create a shared secret between two parties who have never communicated before, even when an eavesdropper can see everything they send to each other. + } +\end{frame} + +\begin{frame}{The magic of Diffie-Hellman} + \begin{itemize}[<+->] + \item Whitfield Diffie and Martin Hellman solved this ``impossible'' problem. + \item Their solution came one year \textbf{before} RSA (1977). + \item Uses the \textbf{discrete logarithm problem} as its foundation. + \item Allows two strangers to create a shared secret in public! + \end{itemize} + \vspace{0.5cm} + \begin{center} + \Large\textbf{This was the birth of modern cryptography} + \end{center} +\end{frame} + +\begin{frame}{What makes discrete logarithm hard?} + \begin{itemize}[<+->] + \item Remember: we need problems that are easy in one direction, hard in reverse. + \item \textbf{Easy direction}: Given $g$ and $x$, compute $g^x \bmod p$ + \begin{itemize} + \item Example: $2^{10} \bmod 17 = 1024 \bmod 17 = 4$ + \end{itemize} + \item \textbf{Hard direction}: Given $g$, $p$, and $g^x \bmod p$, find $x$ + \begin{itemize} + \item Example: Given $g = 2$, $p = 17$, and result $= 4$, find $x = 10$ + \end{itemize} + \item For small numbers, this is easy. For huge numbers (thousands of bits), it's computationally infeasible! + \end{itemize} +\end{frame} + +\begin{frame}{A simple example} + Let's work with small numbers to see the pattern: + \vspace{0.5cm} + \begin{itemize}[<+->] + \item Let $p = 17$ (a prime) and $g = 2$ (a generator) + \item \textbf{Computing powers is easy}: + \begin{itemize} + \item $2^1 \bmod 17 = 2$ + \item $2^2 \bmod 17 = 4$ + \item $2^3 \bmod 17 = 8$ + \item $2^4 \bmod 17 = 16$ + \item $2^5 \bmod 17 = 15$ + \end{itemize} + \item \textbf{Finding the exponent is harder}: + \begin{itemize} + \item Given result $15$, can you quickly find that the exponent was $5$? + \item With small numbers: yes, by trying all possibilities + \item With 2048-bit numbers: practically impossible! + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Mathematical groups: the foundation} + \definitionbox{What is a Mathematical Group?}{ + A set of elements with an operation that follows specific rules. + \begin{itemize} + \item Think of it as a \textbf{mathematical playground} with consistent rules. + \item For cryptography, we use $\mathbb{Z}_p^*$: numbers $\{1, 2, 3, \ldots, p-1\}$ with multiplication mod $p$. + \end{itemize} + } + \begin{itemize}[<+->] + \item \textbf{Example}: $\mathbb{Z}_5^* = \{1, 2, 3, 4\}$ with multiplication mod 5 + \begin{itemize} + \item $3 \times 4 = 12 \bmod 5 = 2$ + \item $2 \times 3 = 6 \bmod 5 = 1$ + \end{itemize} + \item The ``rules'' ensure the math works consistently for cryptography. + \end{itemize} +\end{frame} + +\begin{frame}{Group rules (simplified)} + For our cryptographic group $\mathbb{Z}_p^*$, these rules always hold: + \begin{itemize}[<+->] + \item \textbf{Closure}: Multiplying any two elements gives another element in the group + \begin{itemize} + \item In $\mathbb{Z}_5^*$: $2 \times 3 = 1$ (still in the group!) + \end{itemize} + \item \textbf{Identity}: There's a special element (1) that doesn't change others + \begin{itemize} + \item $1 \times 4 = 4$, $1 \times 2 = 2$, etc. + \end{itemize} + \item \textbf{Inverses}: Every element has a ``partner'' that multiplies to 1 + \begin{itemize} + \item In $\mathbb{Z}_5^*$: $2 \times 3 = 1$, so 2 and 3 are inverses + \end{itemize} + \item \textbf{Associativity}: $(a \times b) \times c = a \times (b \times c)$ + \end{itemize} + \vspace{0.5cm} + \textbf{Why care?} These rules guarantee that our cryptographic operations will behave predictably! +\end{frame} + +\begin{frame}{Generators: the special elements} + \definitionbox{Generator}{ + An element $g$ whose powers $g^1, g^2, g^3, \ldots$ produce every element in the group. + } + \begin{itemize}[<+->] + \item In $\mathbb{Z}_5^*$, let's try $g = 2$: + \begin{itemize} + \item $2^1 \bmod 5 = 2$ + \item $2^2 \bmod 5 = 4$ + \item $2^3 \bmod 5 = 3$ + \item $2^4 \bmod 5 = 1$ + \end{itemize} + \item We got $\{2, 4, 3, 1\}$ - that's all elements! So $g = 2$ is a generator. + \item \textbf{Generators are crucial}: They let us express every group element as a power of $g$. + \end{itemize} +\end{frame} + +\begin{frame}{The discrete logarithm problem (DLP)} + \definitionbox{Discrete Logarithm Problem}{ + Given $g$, $p$, and $h = g^x \bmod p$, find the secret exponent $x$. + } + \begin{itemize}[<+->] + \item \textbf{``Discrete''} because we work with integers, not real numbers + \item \textbf{``Logarithm''} because we're finding the exponent (like $\log_2(8) = 3$) + \item \textbf{Example}: Given $g = 2$, $p = 17$, $h = 8$, find $x$ such that $2^x \equiv 8 \pmod{17}$ + \begin{itemize} + \item Answer: $x = 3$ (since $2^3 = 8$) + \item Easy with small numbers, hard with large ones! + \end{itemize} + \item For cryptographic-sized numbers (2048+ bits), no efficient algorithm is known. + \end{itemize} +\end{frame} + +\begin{frame}{DLP vs. factoring: equally hard} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Factoring Problem} + \begin{itemize}[<+->] + \item Given $N = p \times q$, find $p$ and $q$ + \item Used in RSA (1977) + \item Well-known, intuitive + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Discrete Logarithm} + \begin{itemize}[<+->] + \item Given $g^x \bmod p$, find $x$ + \item Used in Diffie-Hellman (1976) + \item Less intuitive, more mathematical + \end{itemize} + \end{column} + \end{columns} + \vspace{1cm} + \begin{itemize}[<+->] + \item \textbf{Security equivalence}: $n$-bit factoring $\approx$ $n$-bit discrete logarithm + \item Both are vulnerable to Shor's quantum algorithm + \item Both are \textbf{not} known to be NP-hard + \item Algorithms for both problems share similar techniques + \end{itemize} +\end{frame} + +\begin{frame}{Diffie-Hellman: the mathematical version} + \textbf{Setup}: Alice and Bob agree on public values $g$ (generator) and $p$ (large prime) + \vspace{0.5cm} + \begin{enumerate}[<+->] + \item \textbf{Alice}: Chooses secret $a$, computes $A = g^a \bmod p$, sends $A$ to Bob + \item \textbf{Bob}: Chooses secret $b$, computes $B = g^b \bmod p$, sends $B$ to Alice + \item \textbf{Alice}: Computes shared secret $S = B^a \bmod p = (g^b)^a \bmod p = g^{ab} \bmod p$ + \item \textbf{Bob}: Computes shared secret $S = A^b \bmod p = (g^a)^b \bmod p = g^{ab} \bmod p$ + \end{enumerate} + \vspace{0.5cm} + \textbf{Result}: Alice and Bob both have $S = g^{ab} \bmod p$ without ever sharing $a$ or $b$! +\end{frame} + +\begin{frame}{Diffie-Hellman example with small numbers} + \textbf{Public parameters}: $g = 2$, $p = 17$ + \vspace{0.5cm} + \begin{enumerate}[<+->] + \item \textbf{Alice}: Picks secret $a = 6$ + \begin{itemize} + \item Computes $A = 2^6 \bmod 17 = 64 \bmod 17 = 13$ + \item Sends $A = 13$ to Bob + \end{itemize} + \item \textbf{Bob}: Picks secret $b = 10$ + \begin{itemize} + \item Computes $B = 2^{10} \bmod 17 = 1024 \bmod 17 = 4$ + \item Sends $B = 4$ to Alice + \end{itemize} + \item \textbf{Both compute shared secret}: + \begin{itemize} + \item Alice: $S = 4^6 \bmod 17 = 4096 \bmod 17 = 9$ + \item Bob: $S = 13^{10} \bmod 17 = \ldots = 9$ + \end{itemize} + \end{enumerate} + \textbf{Shared secret}: $S = 9$ (which equals $2^{6 \times 10} \bmod 17$) +\end{frame} + +\begin{frame}{The computational Diffie-Hellman (CDH) problem} + \definitionbox{Computational Diffie-Hellman (CDH) Problem}{ + Given $g^a \bmod p$ and $g^b \bmod p$, compute the shared secret $g^{ab} \bmod p$ without knowing the secret values $a$ and $b$. + } + \begin{itemize}[<+->] + \item \textbf{Motivation}: Even if an eavesdropper captures the public values $g^a$ and $g^b$, they shouldn't be able to determine the shared secret $g^{ab}$. + \item \textbf{Example}: Given $A = 13$ and $B = 4$ from our earlier example, can you compute $S = 9$? + \begin{itemize} + \item Without knowing $a = 6$ and $b = 10$, this becomes very difficult! + \end{itemize} + \item \textbf{Real-world relevance}: This is exactly what an attacker faces when trying to break Diffie-Hellman. + \end{itemize} +\end{frame} + +\begin{frame}{CDH vs. DLP: the relationship} + \begin{itemize}[<+->] + \item \textbf{Key insight}: If you can solve DLP, then you can also solve CDH. + \begin{itemize} + \item Given $g^a$ and $g^b$, use DLP to find $a$ and $b$ + \item Then compute $g^{ab}$ directly + \end{itemize} + \item \textbf{Mathematical relationship}: DLP is \textbf{at least as hard} as CDH. + \begin{itemize} + \item CDH $\leq$ DLP (CDH reduces to DLP) + \end{itemize} + \item \textbf{Open question}: Is CDH at least as hard as DLP? + \begin{itemize} + \item We don't know if solving CDH allows you to solve DLP! + \item Maybe there's a clever way to compute $g^{ab}$ without finding $a$ and $b$ + \end{itemize} + \item \textbf{Security assumption}: We assume CDH is hard even if it's easier than DLP. + \end{itemize} +\end{frame} + +\begin{frame}{The decisional Diffie-Hellman (DDH) problem} + \definitionbox{Decisional Diffie-Hellman (DDH) Problem}{ + Given $g^a \bmod p$, $g^b \bmod p$, and a value $X$ that is either: + \begin{itemize} + \item $g^{ab} \bmod p$ (the real shared secret), or + \item $g^c \bmod p$ for some random $c$ + \end{itemize} + ...determine which one $X$ is (each choice has probability 1/2). + } + \begin{itemize}[<+->] + \item \textbf{Why do we need this?} Indistinguishability! + \begin{itemize} + \item What if an attacker can compute the first 32 bits of $g^{ab}$? + \item CDH isn't completely broken, but the attacker learned something. + \item This partial information might compromise application security. + \end{itemize} + \item \textbf{DDH ensures}: The shared secret $g^{ab}$ is \textbf{indistinguishable} from a random group element. + \end{itemize} +\end{frame} + +\begin{frame}{DDH vs. CDH: the hierarchy} + \begin{itemize}[<+->] + \item \textbf{Key relationship}: If you can solve CDH, then you can solve DDH. + \begin{itemize} + \item Given $(g^a, g^b, X)$, use CDH to compute $g^{ab}$ + \item Check if $X = g^{ab}$; if yes, then $X$ is the real shared secret + \end{itemize} + \item \textbf{Hardness hierarchy}: DDH $\leq$ CDH $\leq$ DLP + \begin{itemize} + \item DDH is fundamentally \textbf{easier} than CDH. + \item CDH is (probably) easier than DLP. + \end{itemize} + \item \textbf{Surprising fact}: DDH is \textbf{not hard} in certain groups! + \begin{itemize} + \item In $\mathbb{Z}_p^*$, DDH can be broken using pairing-based techniques. + \item But CDH remains hard in the same group. + \end{itemize} + \item \textbf{Solution}: Use elliptic curve groups where DDH is believed hard. + \end{itemize} +\end{frame} + +\begin{frame}{Why DDH matters in cryptography} + \begin{itemize}[<+->] + \item \textbf{Indistinguishability}: DDH ensures that shared secrets ``look random''. + \begin{itemize} + \item Critical for encryption schemes and key derivation. + \item Prevents attackers from learning partial information. + \end{itemize} + \item \textbf{Security proofs}: Many cryptographic protocols prove security under DDH. + \begin{itemize} + \item ElGamal encryption. + \item Cramer-Shoup cryptosystem. + \item Various authenticated key exchange protocols. + \end{itemize} + \item \textbf{Real-world impact}: Even though DDH is ``weaker'' than CDH, it's one of the most studied and used assumptions. + \begin{itemize} + \item Provides stronger security guarantees for applications. + \item Enables more sophisticated cryptographic constructions. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Real-world Diffie-Hellman} + \begin{itemize}[<+->] + \item \textbf{TLS/HTTPS}: Your browser uses Diffie-Hellman to establish secure connections. + \item \textbf{Signal}: Uses elliptic-curve Diffie-Hellman for key exchange. + \item \textbf{SSH}: Secure shell connections use Diffie-Hellman for key agreement. + \item \textbf{VPNs}: Many VPN protocols rely on Diffie-Hellman for establishing tunnels. + \end{itemize} + \vspace{0.5cm} + \definitionbox{Modern Diffie-Hellman Variants}{ + \begin{itemize} + \item \textbf{Elliptic Curve Diffie-Hellman (ECDH)}: Same idea, different mathematical group. + \item \textbf{Post-quantum alternatives}: New key exchange methods for the quantum era. + \end{itemize} + \vspace{0.1em} + \begin{center} + More on both of the above in future course topics! + \end{center} + } +\end{frame} + +\begin{frame}{Diffie-Hellman key exchange in practice} + \begin{center} + \Large\textbf{How does this actually work in the real world?} + \end{center} + \vspace{0.5cm} + \begin{enumerate}[<+->] + \item \textbf{Parameter generation}: Choose secure values for $p$ and $g$ + \begin{itemize} + \item $p$ must be a large prime (2048+ bits) + \item $g$ must be a generator of a large subgroup + \end{itemize} + \item \textbf{Key generation}: Each party picks a random secret + \begin{itemize} + \item Alice picks $a$ randomly from $\{1, 2, \ldots, p-2\}$ + \item Bob picks $b$ randomly from $\{1, 2, \ldots, p-2\}$ + \end{itemize} + \item \textbf{Public key computation}: Each party computes their public value + \item \textbf{Key exchange}: Public values are sent over the network + \item \textbf{Shared secret derivation}: Each party computes the final shared secret + \end{enumerate} +\end{frame} + +\begin{frame}{TLS handshake: Diffie-Hellman in action} + \textbf{When you visit https://gmail.com, here's what happens:} + \vspace{0.5cm} + \begin{enumerate}[<+->] + \item \textbf{Client Hello}: Your browser says ``I want to talk securely'' + \item \textbf{Server Hello}: Gmail's server responds with its certificate and DH parameters + \begin{itemize} + \item Includes $p$, $g$, and server's public value $g^b \bmod p$ + \end{itemize} + \item \textbf{Client Key Exchange}: Your browser generates its own secret $a$ and sends $g^a \bmod p$ + \item \textbf{Secret computation}: Both sides compute $g^{ab} \bmod p$ + \item \textbf{Key derivation}: The shared secret is used to derive encryption keys + \item \textbf{Secure communication}: All further messages are encrypted with these keys + \end{enumerate} + \vspace{0.5cm} + \textbf{Result}: Your password is encrypted before leaving your computer! +\end{frame} + +\begin{frame}{Signal's double ratchet: DH everywhere} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{itemize}[<+->] + \item \textbf{Initial key exchange}: Uses X3DH (Extended Triple DH) + \begin{itemize} + \item Combines \textbf{three} DH key exchanges for security. + \item Works even when recipient is offline (\textit{``asynchronous''} protocol).\footnote{Everything on this slide will be covered in much more detail later in the course.} + \end{itemize} + \item \textbf{Ongoing communication}: Uses Double Ratchet + \begin{itemize} + \item New DH key exchange for every message! + \item Provides ``forward secrecy'' and ``post-compromise security''. + \item If your phone gets compromised today, yesterday's messages remain secure. + \item If your phone recovers from compromise, tomorrow's messages are secure again. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.3\textwidth} + \imagewithcaption{signal.jpg}{Signal uses DH key exchange dozens, hundreds of times per conversation.} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The dark side: unauthenticated Diffie-Hellman} + \begin{center} + \Large\textbf{But there's a serious problem...} + \end{center} + \vspace{0.5cm} + \begin{itemize}[<+->] + \item \textbf{The vulnerability}: Basic DH has no authentication + \begin{itemize} + \item Alice can't verify she's talking to Bob + \item Bob can't verify he's talking to Alice + \end{itemize} + \item \textbf{The attack}: Man-in-the-middle (MITM) + \begin{itemize} + \item Mallory sits between Alice and Bob + \item Alice does DH with Mallory, thinking it's Bob + \item Bob does DH with Mallory, thinking it's Alice + \item Mallory can read and modify everything! + \end{itemize} + \item \textbf{Real-world impact}: This attack is practical and devastating! + \end{itemize} +\end{frame} + +\begin{frame}{Man-in-the-middle attack on DH} + \textbf{How Mallory breaks ``secure'' communication:} + \vspace{0.5cm} + \begin{enumerate}[<+->] + \item \textbf{Alice $\rightarrow$ Mallory}: Alice sends $g^a$ (thinking it goes to Bob) + \item \textbf{Mallory $\rightarrow$ Bob}: Mallory sends $g^m$ (Bob thinks it's from Alice) + \item \textbf{Bob $\rightarrow$ Mallory}: Bob sends $g^b$ (thinking it goes to Alice) + \item \textbf{Mallory $\rightarrow$ Alice}: Mallory sends $g^m$ (Alice thinks it's from Bob) + \item \textbf{Result}: + \begin{itemize} + \item Alice and Mallory share secret $g^{am}$ + \item Bob and Mallory share secret $g^{bm}$ + \item Alice and Bob don't share any secret! + \end{itemize} + \item \textbf{Communication}: Alice encrypts with $g^{am}$, Mallory decrypts, reads/modifies, re-encrypts with $g^{bm}$ for Bob + \end{enumerate} + \vspace{0.5cm} + \textbf{Alice and Bob never know they've been compromised!} +\end{frame} + +\begin{frame}{Why MITM attacks succeed} + \begin{itemize}[<+->] + \item \textbf{Public values look random}: $g^a$ and $g^m$ are indistinguishable. + \begin{itemize} + \item Both appear to be random group elements. + \item No way to tell if they come from the intended party. + \end{itemize} + \item \textbf{No identity verification}: DH only establishes a shared secret. + \begin{itemize} + \item Doesn't prove who you're sharing it with! + \item Like agreeing on a secret handshake with someone wearing a mask. + \end{itemize} + \item \textbf{Active vs. passive attacks}: + \begin{itemize} + \item DH protects against \textbf{passive} eavesdropping. + \item Does nothing against \textbf{active} manipulation. + \end{itemize} + \item \textbf{Historical impact}: This attack has compromised real systems for decades. + \end{itemize} +\end{frame} + +\begin{frame}{Solution: Authenticated Key Exchange} + \definitionbox{Authenticated Key Exchange (AKE)}{ + Key exchange that verifies the identity of the parties involved, preventing man-in-the-middle attacks. + } + \begin{itemize}[<+->] + \item \textbf{Core idea}: Combine DH with authentication mechanisms + \item \textbf{Common approaches}: + \begin{itemize} + \item \textbf{Digital signatures}: Sign the DH public values (TLS). + \item \textbf{Pre-shared keys}: Use existing shared secrets (IPsec). + \item \textbf{Certificates}: Use a trusted third party (Certificate Authority in HTTPS). + \item \textbf{Password-based}: Derive authentication from passwords (SRP protocols). + \end{itemize} + \item \textbf{Goal}: Ensure that Alice and Bob can verify they're really talking to each other. + \end{itemize} +\end{frame} + +\begin{frame}{TLS: authenticated DH with certificates} + \textbf{How HTTPS prevents MITM attacks:} + \begin{enumerate}[<+->] + \item \textbf{Server authentication}: Gmail sends its certificate along with $g^b$ + \begin{itemize} + \item Certificate proves ``this DH value really came from gmail.com'' + \item Signed by a trusted Certificate Authority (CA) + \end{itemize} + \item \textbf{Certificate verification}: Your browser checks: + \begin{itemize} + \item Is the signature valid? + \item Is the CA trusted? + \item Does the certificate match ``gmail.com''? + \item Has the certificate expired? + \end{itemize} + \item \textbf{If verification passes}: You know you're really talking to Gmail + \item \textbf{If verification fails}: Browser shows scary warnings! + \end{enumerate} + \textbf{Result}: MITM attacks become much harder (but not impossible!) +\end{frame} + +\begin{frame}{Signal: authenticated DH with fingerprints} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{itemize}[<+->] + \item \textbf{The bootstrapping problem}: How do Alice and Bob initially authenticate? + \begin{itemize} + \item No pre-existing certificates. + \item No trusted third parties. + \end{itemize} + \item \textbf{Signal's solution}: Security numbers (fingerprints) + \begin{itemize} + \item Each conversation gets a unique 60-digit number. + \item Derived from both parties' long-term identity keys. + \end{itemize} + \item \textbf{Manual verification}: Users compare numbers out-of-band. + \begin{itemize} + \item Read over the phone\ldots + \item Show in person\ldots + \item Send via different app\ldots + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.3\textwidth} + \imagewithcaption{signal_verification.png}{Signal security number verification screen.} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{SSH: authenticated DH with host keys} + \textbf{How SSH prevents server impersonation:} + \begin{itemize}[<+->] + \item \textbf{First connection}: Server presents its ``host key'' along with DH public value + \begin{itemize} + \item SSH shows you a fingerprint: \texttt{SHA256:ABC123...} + \item You're supposed to verify this out-of-band (but nobody does!) + \end{itemize} + \item \textbf{Trust on first use (TOFU)}: Client remembers the host key + \begin{itemize} + \item Stored in \texttt{\~{}/.ssh/known\_hosts} + \end{itemize} + \item \textbf{Subsequent connections}: Client checks if host key matches + \begin{itemize} + \item If different, gives you a heart attack: \texttt{WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!} + \item If same: Connection proceeds normally + \end{itemize} + \item \textbf{User authentication}: Usually with passwords or public keys + \end{itemize} + \textbf{Weakness}: TOFU is vulnerable on the very first connection! +\end{frame} + +\begin{frame}{Modern implementations: elliptic curves} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Traditional DH} + \begin{itemize}[<+->] + \item Uses $\mathbb{Z}_p^*$ (integers mod $p$) + \item Requires 2048+ bit numbers + \item Slower computations + \item Larger public keys + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Elliptic Curve DH (ECDH)} + \begin{itemize}[<+->] + \item Uses elliptic curve groups + \item 256-bit keys ≈ 2048-bit traditional DH + \item Much faster computations + \item Smaller public keys, less bandwidth + \end{itemize} + \end{column} + \end{columns} + \vspace{0.5cm} + \begin{itemize}[<+->] + \item \textbf{Popular curves}: P-256, P-384, X25519, X448 + \item \textbf{Same security}: Based on elliptic curve discrete logarithm problem + \item \textbf{Real-world adoption}: ECDH is now standard in TLS, Signal, etc. + \item \textbf{Performance matters}: Especially important for mobile devices and IoT + \end{itemize} +\end{frame} + +\begin{frame}{The quantum threat to Diffie-Hellman} + \begin{center} + \Large\textbf{All DH variants are doomed...} + \end{center} + \vspace{0.1cm} + \begin{itemize}[<+->] + \item \textbf{Shor's algorithm} (1994) can break DH on quantum computers. + \begin{itemize} + \item Solves discrete logarithm in polynomial time. + \item Works for both traditional DH and ECDH. + \end{itemize} + \item \textbf{Timeline concerns}: + \begin{itemize} + \item Large quantum computers don't exist yet. + \item But adversaries might store encrypted data now, decrypt later. + \item ``Harvest now, decrypt later'' attacks. + \end{itemize} + \item \textbf{Post-quantum key exchange}: New algorithms under development. + \begin{itemize} + \item ML-KEM (based on lattice problems) + \item SIDH/SIKE (based on isogenies, but recently broken!) + \item Code-based and hash-based alternatives + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Lessons from 50 years of Diffie-Hellman} + \begin{itemize}[<+->] + \item \textbf{Elegant mathematics}: Simple idea with profound implications. + \begin{itemize} + \item Two numbers raised to secret powers in a mathematical group. + \end{itemize} + \item \textbf{Security requires more than math}: Authentication is crucial. + \begin{itemize} + \item Pure DH is vulnerable to active attacks. + \item Real systems need identity verification. + \end{itemize} + \item \textbf{Efficiency drives adoption}: Elliptic curves made DH practical everywhere. + \begin{itemize} + \item Performance improvements enable new applications. + \end{itemize} + \item \textbf{Future challenges}: Quantum computers will force reinvention. + \begin{itemize} + \item But the core insight—shared secrets from public exchanges—will survive. + \end{itemize} + \item \textbf{Cryptography is a living field}: Continuous evolution and adaptation. + \end{itemize} +\end{frame} + +\begin{frame}{From hard problems to real-world security} + \begin{center} + \Large\textbf{The journey we've traced} + \end{center} + \vspace{0.5cm} + \begin{enumerate}[<+->] + \item \textbf{Mathematical insight}: Discrete logarithm is hard to compute. + \item \textbf{Cryptographic innovation}: Diffie-Hellman key exchange leverages this hardness. + \item \textbf{Real-world impact}: Secure communication for billions of people daily. + \end{enumerate} + \vspace{1cm} + \textbf{This is the power of applied cryptography}: transforming abstract mathematical problems into tools that help people and protect our digital lives. +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/1-8.tex b/slides/1-8.tex new file mode 100644 index 0000000..8446377 --- /dev/null +++ b/slides/1-8.tex @@ -0,0 +1,1300 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 1: Provable Security} +\covertopicname{1.8: Elliptic Curves \&\\Digital Signatures} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\section{Elliptic Curves: Theory} + +\begin{frame}{Elliptic-curve cryptography} + \begin{itemize}[<+->] + \item \textbf{Revolutionary introduction (1985):} Elliptic Curve Cryptography (ECC) transformed public-key cryptography. + \item \textbf{Superior efficiency:} More powerful than RSA and classical Diffie-Hellman. + \begin{itemize} + \item ECC with 256-bit key $\approx$ RSA with 4,096-bit key (security). + \item Significantly smaller key sizes for equivalent security. + \end{itemize} + \item \textbf{Mathematical foundation:} Operations on points of elliptic curves. + \begin{itemize} + \item Many curve types: simple/sophisticated, efficient/inefficient, secure/insecure. + \end{itemize} + \item \textbf{Adoption timeline:} + \begin{itemize} + \item Early 2000s: Standardization bodies. + \item 2005: OpenSSL support. + \item 2011: OpenSSH support. + \end{itemize} + \item \textbf{Current applications:} HTTPS, mobile phones, blockchain (Bitcoin, Ethereum). + \item \textbf{Based on ECDLP:} Elliptic Curve Discrete Logarithm Problem. + \end{itemize} +\end{frame} + +\begin{frame}{Why elliptic curve cryptography matters} + \begin{itemize}[<+->] + \item \textbf{Key size efficiency:} ECC provides equivalent security with much smaller keys. + \begin{itemize} + \item 256-bit ECC key $\simeq$ 4,096-bit RSA key $\simeq$ 15,360-bit finite field DH. + \item Exponential security advantage as key sizes increase. + \end{itemize} + \item \textbf{Performance benefits:} + \begin{itemize} + \item Faster key generation, signing, and verification. + \item Lower computational overhead. + \item Reduced memory usage. + \end{itemize} + \item \textbf{Bandwidth efficiency:} Smaller certificates, signatures, and key exchanges. + \item \textbf{Mobile and IoT devices:} Critical for resource-constrained environments. + \begin{itemize} + \item Limited battery life. + \item Constrained processing power. + \item Minimal storage capacity. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{ECDH vs. finite field Diffie-Hellman} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Traditional Finite Field DH:} + \begin{itemize}[<+->] + \item Works in multiplicative group $\mathbb{Z}_p^*$ + \item Security based on discrete log in $\mathbb{Z}_p^*$ + \item Requires large primes (2048+ bits) + \item Key exchange: $g^{ab} \bmod p$ + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Elliptic Curve DH (ECDH):} + \begin{itemize}[<+->] + \item Works on elliptic curve group + \item Security based on ECDLP\footnote{Elliptic-curve discrete logarithm problem} + \item Requires smaller keys (256 bits) + \item Key exchange: $a \cdot (b \cdot G)$ + \end{itemize} + \end{column} + \end{columns} + \vspace{0.5cm} + \textbf{ECDH advantages:} + \begin{itemize} + \item \textbf{Efficiency:} 10-40x faster than finite field DH for equivalent security. + \item \textbf{Scalability:} Performance gap widens with higher security levels. + \item \textbf{Standards compliance:} Widely adopted (TLS 1.3, Signal Protocol, etc.) + \end{itemize} +\end{frame} + +\begin{frame}{Why finite field DH attacks don't work on ECDH} + \begin{itemize}[<+->] + \item \textbf{Different mathematical structures:} + \begin{itemize} + \item Finite field DH: multiplicative group $\mathbb{Z}_p^*$ with multiplication. + \item ECDH: elliptic curve group with point addition (geometrically defined). + \end{itemize} + \item \textbf{Index calculus attack limitation:} + \begin{itemize} + \item Works on finite fields: factorize $g^x$ using small primes. + \item Fails on elliptic curves: no equivalent of ``small primes'' for points. + \item Elliptic curve points cannot be ``factorized'' in the same way. + \end{itemize} + \item \textbf{Subexponential vs. exponential algorithms:} + \begin{itemize} + \item Finite field DL: subexponential algorithms exist (index calculus variants). + \item ECDLP: only exponential algorithms known (Pollard's rho, brute force). + \end{itemize} + \item \textbf{Algebraic structure protection:} + \begin{itemize} + \item Elliptic curve addition is more ``rigid'' than modular multiplication. + \item Geometric constraints prevent many algebraic manipulation attacks. + \end{itemize} + \item \textbf{Result:} ECDH requires exponentially more work to break $\rightarrow$ smaller key sizes. + \end{itemize} +\end{frame} + +\begin{frame}{Very intuitively} + \begin{columns} + \begin{column}{0.5\textwidth} + \imagewithcaption{clock_13.jpg}{Finite-field Diffie-Hellman's structure allows for certain mathematically efficient attacks.} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{persistence_of_memory.jpg}{Let's make that structure ``weirder'' using elliptic curves and avoid these attacks. Source: Salvador Dali} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{What is an elliptic curve?} + \begin{columns} + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Definition:} An elliptic curve is a curve on a plane—a set of points with $x$- and $y$-coordinates. + \item \textbf{Curve equations:} A curve's equation defines all the points that belong to that curve. + \item \textbf{Examples of curves:} + \begin{itemize}[<+->] + \item $y = 3$: horizontal line with vertical coordinate 3 + \item $y = ax + b$: straight lines (with fixed $a$, $b$) + \item $x^2 + y^2 = 1$: circle of radius 1 centered on origin + \end{itemize} + \item \textbf{Key concept:} Points on a curve are $(x, y)$ pairs that satisfy the curve's equation. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{elliptic_curve_real.png}{An elliptic curve with the equation $y^2 = x^3 - 4x$.\\Source: Serious Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{What is an elliptic curve?} + \begin{columns} + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Weierstrass form:} In cryptography, elliptic curves typically have equation: + $$y^2 = x^3 + ax + b$$ + \item \textbf{Shape parameters:} Constants $a$ and $b$ define the shape of the curve. + \item \textbf{Example:} The elliptic curve $y^2 = x^3 - 4x$ + \begin{itemize} + \item Here: $a = 0$ and $b = -4$ + \item Creates a characteristic symmetric curve + \end{itemize} + \item \textbf{Geometric properties:} Elliptic curves have special addition properties that make them useful for cryptography. + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{elliptic_curve_real.png}{An elliptic curve with the equation $y^2 = x^3 - 4x$.\\Source: Serious Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Elliptic curves over real numbers vs. integers} + \begin{columns} + \begin{column}{0.5\textwidth} + \imagewithcaption{elliptic_curve_real.png}{Elliptic curve over the real numbers (includes negative numbers, decimals)...} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{elliptic_curve_integers.png}{Same elliptic curve over the integers (only whole positive numbers)} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Adding two points on an elliptic curve} + \begin{columns} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Point addition follows a simple geometric process: + \begin{itemize} + \item Draw the line that connects points $P$ and $Q$. + \item Find the other point where this line intersects the curve. + \item $R$ is the reflection of this intersection point with respect to the $x$-axis. + \end{itemize} + \item \textbf{Result:} Point $P + Q$ has the same $x$-coordinate as the intersection but the inverse $y$-coordinate. + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{elliptic_curve_add.png}{Adding two points on an elliptic curve.\\Source: Serious Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Doubling a point on an elliptic curve} + \begin{columns} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Point doubling:} When $P = Q$, adding $P$ and $Q$ is equivalent to computing $P + P = 2P$. + \item \textbf{Geometric process:} + \begin{itemize} + \item Can't draw a line between $P$ and itself. + \item Instead, draw the line tangent to the curve at point $P$. + \item Find where this tangent line intersects the curve. + \item $2P$ is the reflection of this intersection point with respect to the $x$-axis. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{elliptic_curve_double.png}{Doubling a point on an elliptic curve.\\Source: Serious Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Remember this?}{We need an equivalent for elliptic curves} + \begin{itemize}[<+->] + \item The discrete logarithm problem: + \begin{itemize} + \item Given a finite cyclic group $G$, a generator $g \in G$, and an element + $h \in G$, find the integer $x$ such that $g^{x}=h$ + \end{itemize} + \item In more concrete terms: + \begin{itemize} + \item Let $p$ be a large prime and let $g$ be a generator of the multiplicative + group $\mathbb{Z}_{p}^{*}$ (all nonzero integers modulo $p$). + \item Given: + \begin{itemize} + \item $g \in \mathbb{Z}_{p}^{*}$, $h \in \mathbb{Z}_{p}^{*}$ + + \item Find $x \in \{0, 1, \ldots, p-2\}$ such that $g^{x} \equiv h \pmod + {p}$ + \end{itemize} + \item This problem is believed to be computationally hard when $p$ is large + and $g$ is a primitive root modulo $p$. + \begin{itemize} + \item ``Believed to be'' = we don't know of any way to do it that doesn't + take forever, unless we have a strong, stable quantum computer (Shor's + algorithm) + \end{itemize} + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Group structure of elliptic curves} + We need to define all these operations so that our elliptic curve have a group structure, allowing us to then use them as a new basis for Diffie-Hellman, and then do DH using point addition instead of modular multiplication. + \begin{itemize}[<+->] + \item \textbf{Closure property:} If points $P$ and $Q$ belong to a curve, then $P + Q$ also belongs to the curve. + \item \textbf{Associativity:} $(P + Q) + R = P + (Q + R)$ for any points $P$, $Q$, and $R$. + \item \textbf{Identity element:} The \emph{point at infinity} $\mathcal{O}$ such that $P + \mathcal{O} = P$ for any $P$. + \item \textbf{Inverse elements:} Every point $P = (x_P, y_P)$ has an inverse $-P = (x_P, -y_P)$ such that $P + (-P) = \mathcal{O}$. + \item Great! We have a group structure! + \end{itemize} +\end{frame} + +\begin{frame}{Elliptic curves over finite fields} + \begin{itemize}[<+->] + \item \textbf{Practical implementation:} Most elliptic curve cryptosystems work with coordinates modulo a prime $p$. + \begin{itemize} + \item Coordinates are numbers in the finite field $\mathbb{Z}_p$. + \item Same geometric operations, but computed modulo $p$. + \end{itemize} + \item \textbf{Security foundation:} Security depends on the \emph{cardinality} (number of points) on the curve. + \begin{itemize} + \item Analogous to how RSA security depends on the size of numbers used. + \item More points $\rightarrow$ harder discrete logarithm problem. + \end{itemize} + \item \textbf{Curve cardinality:} The number of points depends on: + \begin{itemize} + \item The specific curve equation (parameters $a$ and $b$). + \item The prime modulus $p$. + \item Can be computed using specialized algorithms. + \end{itemize} + \item \textbf{Why finite fields?} Infinite precision real numbers are impractical for computers. + \begin{itemize} + \item Finite field arithmetic is exact and efficient. + \item Discrete structure enables cryptographic security. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{The elliptic curve discrete logarithm problem (ECDLP)} + \begin{itemize}[<+->] + \item \textbf{Remember the original DLP:} Given $g$, $h$, and prime $p$, find $x$ such that $g^x \equiv h \pmod{p}$. + \item \textbf{ECDLP is the elliptic curve version:} + \begin{itemize} + \item Given an elliptic curve and a base point $G$ on that curve, + \item Given another point $H$ on the same curve, + \item Find the integer $k$ such that $k \cdot G = H$. + \end{itemize} + \item \textbf{Why is this hard?} + \begin{itemize} + \item Easy direction: Given $k$ and $G$, computing $k \cdot G$ is efficient. + \item Hard direction: Given $G$ and $H = k \cdot G$, finding $k$ is very difficult. + \item No known efficient algorithms (except with quantum computers). + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Diffie-Hellman key agreement over elliptic curves} + \begin{itemize}[<+->] + \item \textbf{Classical Diffie-Hellman recap:} + \begin{itemize} + \item Alice picks secret $a$, computes $A = g^a$, sends $A$ to Bob + \item Bob picks secret $b$, computes $B = g^b$, sends $B$ to Alice + \item Both compute shared secret: $A^b = B^a = g^{ab}$ + \end{itemize} + \item \textbf{Elliptic Curve Diffie-Hellman (ECDH):} + \begin{itemize} + \item Alice picks secret $a$, computes $A = a \cdot G$, sends $A$ to Bob + \item Bob picks secret $b$, computes $B = b \cdot G$, sends $B$ to Alice + \item Both compute shared secret: $a \cdot B = b \cdot A = ab \cdot G$ + \end{itemize} + \item \textbf{Key differences:} + \begin{itemize} + \item Exponentiation $g^x$ $\rightarrow$ Scalar multiplication $x \cdot G$ + \item Modular arithmetic $\rightarrow$ Elliptic curve point operations + \item Generator $g$ $\rightarrow$ Base point $G$ + \end{itemize} + \end{itemize} +\end{frame} + +\section{Digital Signatures} +\begin{frame}{Digital signatures with elliptic curves} + \begin{itemize}[<+->] + \item \textbf{Why elliptic curve signatures?} Same advantages as ECDH: + \begin{itemize} + \item Smaller signatures for equivalent security. + \item Faster generation and verification. + \item Better performance on mobile/IoT devices. + \end{itemize} + \item \textbf{Two main approaches:} + \begin{itemize} + \item \textbf{ECDSA:} Elliptic Curve Digital Signature Algorithm (1990s). + \item \textbf{EdDSA:} Edwards-curve Digital Signature Algorithm (2011). + \end{itemize} + \item \textbf{Real-world adoption:} + \begin{itemize} + \item ECDSA: Bitcoin, Ethereum, TLS, SSH. + \item Ed25519: OpenSSH, Signal Protocol, many modern systems. + \end{itemize} + \item \textbf{Key insight:} Replace RSA's modular exponentiation with elliptic curve point multiplication. + \end{itemize} +\end{frame} + +\begin{frame}{ECDSA: The established standard} + \begin{itemize}[<+->] + \item \textbf{Elliptic Curve Digital Signature Algorithm (ECDSA):} + \begin{itemize} + \item NIST standardized in the early 1990s. + \item Elliptic curve version of the Digital Signature Algorithm (DSA). + \item Widely adopted in blockchain and web security. + \end{itemize} + \item \textbf{Key components:} + \begin{itemize} + \item Private key: secret number $d$ + \item Public key: elliptic curve point $P = d \cdot G$ + \item Base point $G$ on agreed elliptic curve + \end{itemize} + \item \textbf{Security foundation:} Based on ECDLP hardness. + \item \textbf{Signature format:} Two numbers $(r, s)$ + \begin{itemize} + \item For 256-bit curves: 512-bit total signature size. + \item Much smaller than equivalent RSA signatures. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{ECDSA signature generation} + \begin{columns} + \begin{column}{0.6\textwidth} + \textbf{Input:} Message $M$, private key $d$ + \begin{enumerate}[<+->] + \item \textbf{Hash the message:} $h = \text{Hash}(M)$ + \begin{itemize} + \item Use SHA-256, SHA-3, or similar + \item Interpret hash as number $h \in [0, n-1]$ + \end{itemize} + \item \textbf{Generate random nonce:} Pick random $k \in [1, n-1]$ + \item \textbf{Compute signature point:} $k \cdot G = (x, y)$ + \item \textbf{Calculate $r$:} $r = x \bmod n$ + \item \textbf{Calculate $s$:} $s = \frac{h + rd}{k} \bmod n$ + \item \textbf{Output signature:} $(r, s)$ + \end{enumerate} + \end{column} + \begin{column}{0.4\textwidth} + \textbf{Critical requirement:} + \begin{itemize}[<+->] + \item Random $k$ must be: + \begin{itemize} + \item Cryptographically random + \item Different for every signature + \item Never reused + \end{itemize} + \item \textbf{Reusing $k$ = private key exposure!} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{ECDSA signature verification} + \begin{columns} + \begin{column}{0.6\textwidth} + \textbf{Input:} Message $M$, signature $(r, s)$, public key $P$ + \begin{enumerate}[<+->] + \item \textbf{Hash the message:} $h = \text{Hash}(M)$ + \item \textbf{Compute modular inverse:} $w = \frac{1}{s} \bmod n$ + \item \textbf{Calculate verification values:} + \begin{itemize} + \item $u = h \cdot w \bmod n$ + \item $v = r \cdot w \bmod n$ + \end{itemize} + \item \textbf{Compute verification point:} $Q = u \cdot G + v \cdot P$ + \item \textbf{Check signature:} Accept if $Q_x = r$ + \end{enumerate} + \end{column} + \begin{column}{0.4\textwidth} + \textbf{Why this works:} + \begin{itemize}[<+->] + \item Mathematical relationship: + \begin{align*} + Q & = u \cdot G + v \cdot P \\ + & = u \cdot G + v \cdot d \cdot G \\ + & = (u + vd) \cdot G + \end{align*} + \item When signature is valid: + $$u + vd = k \bmod n$$ + \item So $Q = k \cdot G$, giving $Q_x = r$ + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{EdDSA: The modern alternative} + \begin{itemize}[<+->] + \item \textbf{Background:} Built on Schnorr signatures (1989). + \begin{itemize} + \item Schnorr's patent prevented adoption until 2008. + \item Edwards-curve DSA developed by Bernstein et al. (2011). + \end{itemize} + \item \textbf{Key advantages over ECDSA:} + \begin{itemize} + \item \textbf{Deterministic:} No random number generation during signing. + \item \textbf{Faster:} Both signing and verification. + \item \textbf{Simpler:} Cleaner mathematical structure. + \item \textbf{Safer:} Eliminates randomness-related vulnerabilities. + \end{itemize} + \item \textbf{Design philosophy:} Avoid the pitfalls that plague ECDSA. + \item \textbf{Most popular instance:} Ed25519 (based on Curve25519). + \end{itemize} +\end{frame} + +\begin{frame}{EdDSA signature generation} + \textbf{Key insight:} Derive everything deterministically from private key and message. + \begin{columns} + \begin{column}{0.7\textwidth} + \textbf{Input:} Message $M$, private key $k$ (byte string) + \begin{enumerate}[<+->] + \item \textbf{Expand private key:} $a \parallel h = \text{Hash}(k)$ + \begin{itemize} + \item $a$: actual signing scalar (first 256 bits) + \item $h$: randomness source (last 256 bits) + \end{itemize} + \item \textbf{Compute public key:} $A = a \cdot B$ (precomputed) + \item \textbf{Generate nonce deterministically:} $r = \text{Hash}(h \parallel M)$ + \item \textbf{Compute signature point:} $R = r \cdot B$ + \item \textbf{Compute signature scalar:} $S = r + \text{Hash}(R, A, M) \times a$ + \item \textbf{Output signature:} $(R, S)$ + \end{enumerate} + \end{column} + \begin{column}{0.3\textwidth} + \textbf{Benefits:} + \begin{itemize}[<+->] + \item No randomness needed + \item Same message = same signature + \item Immune to bad RNG + \item Faster (no modular inverse) + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{EdDSA signature verification} + \begin{columns} + \begin{column}{0.6\textwidth} + \textbf{Input:} Message $M$, signature $(R, S)$, public key $A$ + \begin{enumerate}[<+->] + \item \textbf{Verify equation:} Check if: + $$S \cdot B = R + \func{hash}{R, A, M} \cdot A$$ + \item \textbf{Accept signature if equation holds} + \end{enumerate} + \vspace{0.5cm} + \textbf{Why this works:} + \begin{itemize}[<+->] + \item From signing: $S = r + \func{hash}{R, A, M} \times a$ + \item So: $S \cdot B = (r + \func{hash}{R, A, M} \times a) \cdot B$ + \item $= r \cdot B + \func{hash}{R, A, M} \times a \cdot B$ + \item $= R + \func{hash}{R, A, M} \times A$ + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \textbf{Performance benefits:} + \begin{itemize}[<+->] + \item No modular inverse computation + \item Two scalar multiplications (like ECDSA) + \item Simpler arithmetic + \item Better constant-time implementation + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Ed25519: The practical implementation} + \begin{itemize}[<+->] + \item \textbf{Ed25519 = EdDSA + specific parameters:} + \begin{itemize} + \item Twisted Edwards curve based on Curve25519 + \item SHA-512 as hash function + \item Optimized base point for efficiency + \end{itemize} + \item \textbf{Performance characteristics:} + \begin{itemize} + \item Signing: ~40-90 microseconds (modern CPUs) + \item Verification: ~100-200 microseconds + \item 64-byte signatures (512 bits) + \end{itemize} + \item \textbf{Security level:} ~128 bits (equivalent to 3072-bit RSA) + \item \textbf{Adoption milestones:} + \begin{itemize} + \item 2011: Initial specification + \item 2017: RFC 8032 standardization + \item 2023: Added to NIST FIPS 186-5 + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{ECDSA vs. Ed25519: The comparison} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{ECDSA:} + \begin{itemize}[<+->] + \item \textbf{Pros:} + \begin{itemize} + \item Established standard (1990s) + \item Wide library support + \item Blockchain industry standard + \end{itemize} + \item \textbf{Cons:} + \begin{itemize} + \item Requires secure randomness + \item Slower verification + \item Complex implementation + \item Vulnerable to bad RNG + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Ed25519:} + \begin{itemize}[<+->] + \item \textbf{Pros:} + \begin{itemize} + \item Deterministic signing + \item Faster performance + \item Simpler implementation + \item Better security properties + \end{itemize} + \item \textbf{Cons:} + \begin{itemize} + \item Newer standard + \item Some validation inconsistencies + \item Less blockchain adoption + \end{itemize} + \end{itemize} + \end{column} + \end{columns} + \vspace{0.5cm} + \textbf{Recommendation:} Use Ed25519 for new projects unless ECDSA is specifically required. +\end{frame} + +\section{Elliptic Curves: Practice} + +\begin{frame}{Choosing the right elliptic curve} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Not all elliptic curves are created equal:} The mathematical structure of the curve directly impacts cryptographic security. + \item \textbf{Security implications:} Poor curve choice can make ECDLP much easier to solve. + \item \textbf{In practice:} You'll use established curves, but understanding what makes a curve safe helps you: + \begin{itemize} + \item Choose among available options. + \item Better understand associated risks. + \item Evaluate new curve proposals. + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{safecurves.png}{Elliptic curves have many distinct and complex security criteria.\\Source: \url{https://safecurves.cr.yp.to}} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Criteria for safe elliptic curves} + \begin{itemize}[<+->] + \item \textbf{Group order security:} The number of points on the curve shouldn't factor into small numbers. + \begin{itemize} + \item If the order has small factors, ECDLP becomes much easier. + \item Attackers can use algorithms like Pohlig-Hellman to exploit small factors. + \end{itemize} + \item \textbf{Addition formula consistency:} Unified addition laws are preferred. + \begin{itemize} + \item Some curves require different formulas for $P + Q$ vs. $P + P$ (doubling). + \item Timing differences between these operations can leak information. + \item Secure curves use the same formula for all additions. + \end{itemize} + \item \textbf{Parameter transparency:} The origin of curve parameters should be clearly explained. + \begin{itemize} + \item Unknown parameter origins raise suspicion of backdoors. + \item ``Nothing up my sleeve'' numbers increase trust. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{NIST curves: The establishment standard} + \begin{itemize}[<+->] + \item \textbf{Official standardization:} NIST standardized several curves in FIPS 186 (2000). + \begin{itemize} + \item ``Recommended Elliptic Curves for Federal Government Use'' + \item Five prime curves working modulo prime numbers. + \item Ten binary polynomial curves (rarely used today). + \end{itemize} + \item \textbf{Most popular: P-256} + \begin{itemize} + \item Works modulo $p = 2^{256} - 2^{224} + 2^{192} + 2^{96} - 1$ + \item Equation: $y^2 = x^3 - 3x + b$ (256-bit $b$ parameter) + \item Other sizes: P-192, P-224, P-384, P-521 (yes, 521 not 512!) + \end{itemize} + \item \textbf{Wide adoption:} Used in TLS, government systems, many commercial applications. + \end{itemize} +\end{frame} + +\begin{frame}{The NIST controversy: Suspicious constants} + \begin{itemize}[<+->] + \item \textbf{The problem:} Only the NSA knows the true origin of the $b$ coefficient in NIST curves. + \item \textbf{NSA's explanation:} $b$ results from hashing a ``random-looking'' constant with SHA-1. + \begin{itemize} + \item P-256's $b$ comes from: \texttt{c49d3608 86e70493 6a6678e1 139d26b7 819f7e90} + \item But why this particular constant? Nobody knows. + \end{itemize} + \item \textbf{Community response:} + \begin{itemize} + \item Most experts don't believe the curves hide backdoors. + \item But the lack of transparency creates suspicion. + \item Led to development of alternative curves with transparent parameters. + \end{itemize} + \item \textbf{Post-Snowden era:} Increased scrutiny of NSA-designed cryptographic standards. + \end{itemize} +\end{frame} + +\begin{frame}{Curve25519: The performance revolution} + \begin{itemize}[<+->] + \item \textbf{Created by Daniel J. Bernstein (2006):} Motivated by performance and security concerns. + \item \textbf{Performance advantages:} + \begin{itemize} + \item Faster than NIST curves. + \item Shorter keys for equivalent security. + \item Optimized for software implementation. + \end{itemize} + \item \textbf{Security improvements:} + \begin{itemize} + \item No suspicious constants—all parameters have clear origins. + \item Unified addition formula (same for $P + Q$ and $P + P$). + \item Resistant to timing attacks. + \end{itemize} + \item \textbf{Mathematical form:} $y^2 = x^3 + 486662x^2 + x$ + \begin{itemize} + \item Works modulo $2^{255} - 19$ (closest prime to $2^{255}$). + \item Coefficient 486662 is the smallest integer satisfying security criteria. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Curve25519: From rebel to standard} + \begin{itemize}[<+->] + \item \textbf{Widespread adoption:} + \begin{itemize} + \item WhatsApp end-to-end encryption + \item TLS 1.3 key exchange + \item OpenSSH connections + \item Signal Protocol + \item Many cryptocurrency systems + \end{itemize} + \item \textbf{Official recognition:} Added to NIST-approved curves in February 2023. + \begin{itemize} + \item SP 800-186: ``Recommendations for Discrete Logarithm-based Cryptography'' + \item Took 17 years for official government approval! + \end{itemize} + \item \textbf{Trust through transparency:} Clear parameter origins make Curve25519 more trustworthy than NIST curves. + \item \textbf{Related: Ed25519} for digital signatures using the same curve. + \end{itemize} +\end{frame} + +\begin{frame}{Other curves in the ecosystem} + \begin{itemize}[<+->] + \item \textbf{Legacy national standards:} + \begin{itemize} + \item \textbf{ANSSI curves (France):} Constants of unknown origin, no unified addition. + \item \textbf{Brainpool curves (Germany):} Similar issues to ANSSI curves. + \end{itemize} + \item \textbf{Modern alternatives:} + \begin{itemize} + \item \textbf{Curve41417:} Variant of Curve25519 with higher security (~200 bits). + \item \textbf{Ed448-Goldilocks:} 448-bit curve (RFC 8032, 2014). + \item \textbf{Aranha et al. curves:} Six high-security curves (rarely used). + \end{itemize} + \item \textbf{Ristretto initiative:} Technique for safe point representation. + \begin{itemize} + \item Constructs prime-order groups from non-prime-order curves. + \item Eliminates certain structural risks. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Practical curve selection guidance} + \begin{itemize}[<+->] + \item \textbf{For new projects:} Use Curve25519/Ed25519 + \begin{itemize} + \item Excellent performance and security. + \item Transparent parameter generation. + \item Wide library support. + \item Now NIST-approved for government use. + \end{itemize} + \item \textbf{For government/compliance:} NIST P-256 is still widely accepted + \begin{itemize} + \item Required by some standards and regulations. + \item Well-audited implementations available. + \item Despite parameter concerns, no known weaknesses. + \end{itemize} + \item \textbf{Avoid:} Legacy curves with unknown parameter origins + \begin{itemize} + \item ANSSI, Brainpool curves. + \item Curves without unified addition laws. + \end{itemize} + \item \textbf{Future-proofing:} Consider post-quantum alternatives for long-term security. + \end{itemize} +\end{frame} + +\begin{frame}{How things can go wrong} + \begin{itemize}[<+->] + \item \textbf{ECC complexity brings risks:} More parameters than RSA create a larger attack surface. + \item \textbf{Implementation vulnerabilities:} + \begin{itemize} + \item Side-channel attacks on big-number arithmetic. + \item Timing attacks when computation time depends on secret values. + \item Point validation failures. + \end{itemize} + \item \textbf{Design-level vulnerabilities:} + \begin{itemize} + \item Bad randomness in signature generation. + \item Invalid curve attacks on key exchange. + \item Inconsistent validation rules across implementations. + \end{itemize} + \item Let's examine three major categories of ECC vulnerabilities. + \end{itemize} +\end{frame} + +\begin{frame}{ECDSA with bad randomness} + \begin{itemize}[<+->] + \item \textbf{ECDSA signing requires randomness:} Each signature uses a secret random number $k$. + $$s = \frac{h + rd}{k} \bmod n$$ + \item \textbf{The catastrophic mistake:} Reusing the same $k$ for two different messages. + \item \textbf{Attack scenario:} If $k$ is reused: + \begin{itemize} + \item Attacker gets: $s_1 = \frac{h_1 + rd}{k}$ and $s_2 = \frac{h_2 + rd}{k}$ + \item Compute: $s_1 - s_2 = \frac{h_1 - h_2}{k}$ + \item Recover randomness: $k = \frac{h_1 - h_2}{s_1 - s_2}$ + \item Recover private key: $d = \frac{sk - h}{r}$ + \end{itemize} + \item \textbf{Why this is devastating:} Complete private key recovery from just two signatures. + \item \textbf{Prevention:} Always use cryptographically secure random number generation. + \end{itemize} +\end{frame} + +\begin{frame}{Case study: PlayStation 3 hack (2010)} + \begin{itemize}[<+->] + \item \textbf{The vulnerability:} Sony's PlayStation 3 reused the same $k$ value to sign different games. + \item \textbf{Discovery:} fail0verflow team at 27th Chaos Communication Congress. + \item \textbf{Attack process:} + \begin{itemize} + \item Collected ECDSA signatures from multiple PS3 games. + \item Noticed identical $r$ values (indicating same $k$). + \item Applied the mathematical attack to recover Sony's signing key. + \end{itemize} + \item \textbf{Consequences:} + \begin{itemize} + \item Attackers could sign any program to run on PS3. + \item Homebrew software and piracy became possible. + \item Sony had to revoke and update their entire signing infrastructure. + \end{itemize} + \item \textbf{Lesson:} Even major companies can make fundamental cryptographic mistakes. + \end{itemize} +\end{frame} + +\begin{frame}{Invalid curve attacks} + \begin{itemize}[<+->] + \item \textbf{The vulnerability:} ECDH implementations that don't validate input points. + \item \textbf{Mathematical insight:} Point addition formulas don't use the $b$ coefficient: + $$P + Q \text{ only depends on coordinates of } P, Q \text{ and coefficient } a$$ + \item \textbf{Attack scenario:} + \begin{itemize} + \item Alice and Bob agree on curve and base point $G$. + \item Bob sends legitimate public key $bG$. + \item Alice sends point $P$ from a \emph{different, weaker} curve. + \item Bob computes ``shared secret'' $bP$ on the wrong curve. + \end{itemize} + \item \textbf{Why this works:} Addition formulas work the same way on the wrong curve. + \item \textbf{Attacker's advantage:} Choose $P$ from a curve with weak discrete logarithm. + \end{itemize} +\end{frame} + +\begin{frame}{Invalid curve attack: The mathematics} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Attacker's strategy:} Choose point $P$ with small order on a weak curve. + \begin{itemize} + \item Small order means $kP = \mathcal{O}$ for relatively small $k$. + \item Bob computes $bP$, which also has small order. + \end{itemize} + \item \textbf{Attack execution:} + \begin{itemize} + \item Bob believes he computed shared secret $bP$. + \item He hashes $bP$ and uses result as encryption key. + \item Since $bP$ belongs to small subgroup, attacker can brute-force it. + \end{itemize} + \item \textbf{Real-world example:} Found in TLS-ECDH implementations (2015). + \begin{itemize} + \item Paper: ``Practical Invalid Curve Attacks on TLS-ECDH''\footnote{\url{https://appliedcryptography.page/papers/invalid-curve.pdf}} + \item Jager, Schwenk, and Somorovsky + \end{itemize} + \item \textbf{Prevention:} Always validate that points satisfy the correct curve equation. + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Invalid curve attack prevention} + \begin{itemize}[<+->] + \item \textbf{Point validation:} Before using any received point $P = (x, y)$: + $$\text{Check: } y^2 \stackrel{?}{=} x^3 + ax + b \pmod{p}$$ + \item \textbf{Additional checks:} + \begin{itemize} + \item Verify point is not the point at infinity. + \item Ensure coordinates are in valid range $[0, p-1]$. + \item Check point has correct order (belongs to right subgroup). + \end{itemize} + \item \textbf{Implementation note:} Many libraries now perform validation automatically. + \item \textbf{Defense in depth:} Use curves with prime order (like Curve25519). + \begin{itemize} + \item Eliminates small subgroup attacks entirely. + \item Even invalid points can't exploit subgroup structure. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Why most elliptic curves aren't prime order} + \begin{itemize}[<+->] + \item \textbf{Mathematical reality:} The number of points on a curve is rarely prime. + \begin{itemize} + \item For curve $y^2 = x^3 + ax + b$ over $\mathbb{F}_p$, the number of points is close to $p$. + \item Hasse's theorem: $|n - (p + 1)| \leq 2\sqrt{p}$ where $n$ is the number of points. + \item Getting exactly a prime number is statistically unlikely. + \end{itemize} + \item \textbf{Curve25519's structure:} Has $8 \times \ell$ points where $\ell$ is a large prime. + \begin{itemize} + \item Factor of 8 comes from the curve's mathematical structure. + \item Designers chose parameters to minimize cofactor while optimizing performance. + \item Trade-off: Accept small cofactor for better arithmetic efficiency. + \end{itemize} + \item \textbf{Why not search for prime-order curves?} + \begin{itemize} + \item Finding curves with prime order is computationally expensive. + \item Prime-order curves often have less efficient arithmetic. + \item Small cofactors (like 4 or 8) are manageable with proper protocols. + \end{itemize} + \item \textbf{Security implication:} Non-prime order enables small subgroup attacks if not handled carefully. + \end{itemize} +\end{frame} + +\begin{frame}{Understanding elliptic curve subgroups} + \begin{itemize}[<+->] + \item \textbf{What is a subgroup?} A subset of curve points that forms its own group. + \begin{itemize} + \item Contains the identity element (point at infinity $\mathcal{O}$). + \item Closed under addition: if $P, Q$ in subgroup, then $P + Q$ also in subgroup. + \item Every element has an inverse within the subgroup. + \end{itemize} + \item \textbf{Why do subgroups exist?} Most elliptic curves don't have prime order. + \begin{itemize} + \item If curve has $n$ points and $n = p \times q$, subgroups can exist. + \item Points of order $p$ form a subgroup of size $p$. + \item Points of order $q$ form a subgroup of size $q$. + \end{itemize} + \item \textbf{Example: Curve25519's structure} + \begin{itemize} + \item Total points: $8 \times \ell$ where $\ell$ is a large prime. + \item Has a subgroup of order 8 (small!). + \item Has a subgroup of order $\ell$ (large, secure). + \item Every point belongs to one of these subgroups. + \end{itemize} + \item \textbf{Security implication:} Attackers try to push operations into small subgroups where discrete log is easy. + \end{itemize} +\end{frame} + +\begin{frame}{Small subgroup attacks} + \begin{itemize}[<+->] + \item \textbf{How it works:} + \begin{itemize} + \item Attacker sends a point $P$ of small order (e.g., order 8). + \item Victim computes secret scalar multiplication: $s \cdot P$. + \item Result $s \cdot P$ also has small order (at most 8). + \item Attacker can brute-force to find $s \bmod 8$. + \end{itemize} + \item \textbf{Information leakage:} Each exchange reveals bits of the secret. + \begin{itemize} + \item With order-8 point: Learn 3 bits of secret. + \item Repeat with different small-order points. + \item Combine using Chinese Remainder Theorem. + \item Eventually recover full secret. + \end{itemize} + \item \textbf{Real-world example:} Curve25519 without proper validation. + \begin{itemize} + \item Has points of order 1, 2, 4, 8, $\ell$, $2\ell$, $4\ell$, $8\ell$. + \item Unvalidated ECDH can leak secret key bits. + \end{itemize} + \item \textbf{Defense:} Validate points belong to correct subgroup or use protocols that eliminate the threat. + \end{itemize} +\end{frame} + +\begin{frame}{Invalid curve attacks vs. small subgroup attacks} + \begin{itemize}[<+->] + \item \textbf{Two distinct but related vulnerabilities:} + \begin{itemize} + \item Both exploit weak point validation. + \item Different mathematical foundations. + \item Different defense strategies. + \end{itemize} + \item \textbf{Invalid curve attacks:} + \begin{itemize} + \item Attacker sends point from a \emph{different curve} entirely. + \item Point satisfies $y^2 = x^3 + ax + b'$ with wrong $b'$ coefficient. + \item Exploits that addition formulas don't use $b$. + \item Defense: Verify $y^2 \stackrel{?}{=} x^3 + ax + b$ with correct $b$. + \end{itemize} + \item \textbf{Small subgroup attacks:} + \begin{itemize} + \item Attacker sends point from the \emph{correct curve}. + \item But point has small order (belongs to small subgroup). + \item Example: Point $P$ where $8P = \mathcal{O}$ instead of expected large order. + \item Defense: Verify point has correct order or use prime-order curves. + \end{itemize} + \item \textbf{Key insight:} Invalid curve = wrong equation; Small subgroup = wrong order. + \end{itemize} +\end{frame} + +\begin{frame}{Ed25519 validation inconsistencies} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Expectation:} One standard should mean identical behavior across implementations. + \item \textbf{Reality:} Ed25519 implementations have different validation criteria. + \item \textbf{The problem:} RFC 8032 doesn't fully specify validation requirements. + \begin{itemize} + \item How to validate signature point $R$. + \item How to validate public key point $A$. + \item How to verify the signature equation. + \end{itemize} + \item \textbf{Research findings:} Henry de Valence analyzed 15 Ed25519 implementations.\footnote{\url{https://hdevalence.ca/blog/2020-10-04-its-25519am/}} + \begin{itemize} + \item Each had different validation criteria. + \item Same signature could be valid in one implementation, invalid in another. + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Real-world impact of validation differences} + \begin{itemize}[<+->] + \item \textbf{Consensus failures:} In blockchain networks: + \begin{itemize} + \item Some nodes accept a signature, others reject it. + \item Breaks consensus protocol assumptions. + \item Can lead to network splits or transaction inconsistencies. + \end{itemize} + \item \textbf{Interoperability issues:} Systems using different libraries may disagree. + \item \textbf{Security implications:} Inconsistent validation can enable attacks. + \begin{itemize} + \item Malleability attacks. + \item Signature forgery in edge cases. + \end{itemize} + \item \textbf{The solution:} Standardization efforts like ZIP-215 (Zcash) aim to: + \begin{itemize} + \item Specify exact validation rules. + \item Ensure all implementations behave identically. + \item Prevent consensus failures. + \end{itemize} + \item \textbf{Lesson:} Cryptographic standards must be completely unambiguous. + \end{itemize} +\end{frame} + +\begin{frame}{Library selection: The ecosystem landscape} + \begin{itemize}[<+->] + \item \textbf{Don't implement ECC from scratch:} Cryptographic implementations require years of hardening. + \item \textbf{Rust ecosystem:} + \begin{itemize} + \item \texttt{ring}: Fast, audited, used by major companies. + \item \texttt{p256}, \texttt{k256}: RustCrypto pure-Rust implementations. + \item \texttt{curve25519-dalek}: Ed25519/X25519 with extensive validation. + \end{itemize} + \item \textbf{Go ecosystem:} + \begin{itemize} + \item \texttt{crypto/elliptic}: Standard library (NIST curves). + \item \texttt{golang.org/x/crypto/curve25519}: Official X25519 implementation. + \item \texttt{filippo.io/edwards25519}: Modern Ed25519 with clear APIs. + \end{itemize} + \item \textbf{Selection criteria:} + \begin{itemize} + \item Active maintenance and security updates. + \item Independent security audits. + \item Constant-time guarantees. + \item Clear documentation and examples. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Performance considerations in practice} + \begin{itemize}[<+->] + \item \textbf{Scalar multiplication is the bottleneck:} Operations like $k \cdot G$ dominate runtime. + \item \textbf{Precomputation strategies:} + \begin{itemize} + \item Store multiples of base point: $G, 2G, 4G, 8G, \ldots$ + \item Sliding window methods for arbitrary points. + \item Trade memory for speed. + \end{itemize} + \item \textbf{Coordinate systems matter:} + \begin{itemize} + \item Affine coordinates: Simple but require expensive modular inverse. + \item Jacobian coordinates: Avoid inverse, faster for repeated operations. + \item Montgomery ladders: Optimal for X25519-style protocols. + \end{itemize} + \item \textbf{Real-world impact:} + \begin{itemize} + \item TLS handshake time directly affects user experience. + \item Mobile devices: battery life and thermal constraints. + \item IoT devices: limited computational resources. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Constant-time implementation: Why it matters} + \begin{itemize}[<+->] + \item \textbf{The threat:} Attackers can measure timing differences to extract secrets. + \item \textbf{Vulnerable patterns in ECC:} + \begin{itemize} + \item Conditional branches based on secret bits + \item Variable-time modular arithmetic + \item Memory access patterns that depend on secret data + \end{itemize} + \item \textbf{Example: Scalar multiplication timing} + \begin{itemize} + \item Binary method: \texttt{if (bit == 1) result += point} + \item Timing reveals which bits are 1 vs 0 + \item After enough measurements, attacker recovers private key + \end{itemize} + \item \textbf{Defense:} Always perform the same operations regardless of secret values. + \item \textbf{Modern libraries handle this:} But you need to choose libraries that guarantee constant-time behavior. + \end{itemize} +\end{frame} + +\begin{frame}{Memory management and sensitive data} + \begin{itemize}[<+->] + \item \textbf{The problem:} Private keys in memory can be extracted by attackers. + \item \textbf{Attack vectors:} + \begin{itemize} + \item Memory dumps during crashes. + \item Swap files writing secrets to disk. + \item Cold boot attacks on RAM. + \item Process memory scanning. + \end{itemize} + \item \textbf{Defense strategies:} + \begin{itemize} + \item Zero memory immediately after use. + \item Use protected memory (mlock/VirtualLock). + \item Hardware security modules (HSMs) for high-value keys. + \item Minimize lifetime of secrets in memory. + \end{itemize} + \item \textbf{Language-specific considerations:} + \begin{itemize} + \item Rust: \texttt{zeroize} crate for secure memory clearing. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Testing elliptic curve implementations} + \begin{itemize}[<+->] + \item \textbf{Standard test vectors:} Use RFC and NIST test cases to verify correctness. + \item \textbf{Cross-implementation testing:} + \begin{itemize} + \item Generate signatures with one library, verify with another. + \item Perform ECDH with different implementations. + \item Ensure interoperability across programming languages. + \end{itemize} + \item \textbf{Edge case testing:} + \begin{itemize} + \item Point at infinity handling. + \item Invalid curve points. + \item Malformed signature formats. + \item Zero and maximum values. + \end{itemize} + \item \textbf{Property-based testing:} + \begin{itemize} + \item Verify mathematical properties: $P + Q = Q + P$ + \item Test with random inputs within valid ranges. + \item Ensure operations always produce valid outputs. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Real-world case study: WhatsApp's implementation} + \begin{itemize}[<+->] + \item \textbf{Challenge:} Secure messaging for 2+ billion users across diverse devices. + \item \textbf{Solution:} Signal Protocol with Curve25519 and Ed25519. + \item \textbf{Implementation details:} + \begin{itemize} + \item X25519 for key agreement (ECDH). + \item Ed25519 for identity key signatures. + \item Custom optimizations for mobile platforms. + \item Cross-platform C library for consistency. + \end{itemize} + \item \textbf{Engineering considerations:} + \begin{itemize} + \item Battery life optimization on mobile devices. + \item Constant-time implementation to prevent side-channel attacks. + \item Extensive testing across iOS, Android, and desktop platforms. + \item Regular security audits by external firms. + \end{itemize} + \item \textbf{Lessons:} Real world requires balancing security, performance, and compatibility. + \end{itemize} +\end{frame} + +\begin{frame}{Real-world case study: TLS 1.3 performance} + \begin{itemize}[<+->] + \item \textbf{Challenge:} Replace RSA key exchange with elliptic curve alternatives. + \item \textbf{Implementation impact:} + \begin{itemize} + \item X25519 ECDH: 40-100x faster than 2048-bit RSA key exchange. + \item Smaller certificates reduce network overhead. + \item Enables features like 0-RTT handshakes. + \end{itemize} + \item \textbf{Engineering challenges solved:} + \begin{itemize} + \item Constant-time implementation in BoringSSL. + \item Optimized assembly for common architectures. + \item Fallback implementations for edge cases. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Common implementation pitfalls} + \begin{itemize}[<+->] + \item \textbf{Pitfall 1: Poor random number generation} + \begin{itemize} + \item Using \texttt{rand()} instead of cryptographic RNG. + \item Not seeding random generators properly. + \item Reusing random values (PlayStation 3 scenario). + \end{itemize} + \item \textbf{Pitfall 2: Skipping input validation} + \begin{itemize} + \item Not checking if points are on the correct curve. + \item Accepting points at infinity without proper handling. + \item Missing range checks on coordinates. + \end{itemize} + \item \textbf{Pitfall 3: Side-channel vulnerabilities} + \begin{itemize} + \item Conditional operations based on secret data. + \item Variable memory access patterns. + \item Timing differences in error handling. + \end{itemize} + \item \textbf{Prevention:} Use audited libraries, follow security guidelines, test extensively. + \end{itemize} +\end{frame} + +\begin{frame}{Best practices for ECC implementation} + \begin{itemize}[<+->] + \item \textbf{Library selection:} + \begin{itemize} + \item Choose libraries with security audit history. + \item Prefer constant-time implementations. + \item Ensure active maintenance and updates. + \end{itemize} + \item \textbf{Development practices:} + \begin{itemize} + \item Use standard curves (avoid custom parameters). + \item Implement comprehensive input validation. + \item Clear sensitive data from memory. + \item Use secure random number generation. + \end{itemize} + \item \textbf{Testing and deployment:} + \begin{itemize} + \item Test with standard vectors and edge cases. + \item Perform interoperability testing. + \item Monitor for timing analysis vulnerabilities. + \item Plan for cryptographic agility (algorithm migration). + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Digital signatures: real-world adoption patterns} + \begin{itemize}[<+->] + \item \textbf{ECDSA dominance:} + \begin{itemize} + \item Bitcoin, Ethereum, most cryptocurrencies. + \item TLS certificates (still common). + \item Legacy enterprise systems. + \end{itemize} + \item \textbf{Ed25519 growth:} + \begin{itemize} + \item OpenSSH default since 2014. + \item Signal Protocol messaging. + \item Modern certificate authorities. + \item New blockchain projects (Solana, etc.) + \end{itemize} + \item \textbf{Migration considerations:} + \begin{itemize} + \item Interoperability with existing systems. + \item Library availability in your ecosystem. + \item Compliance requirements. + \item Performance requirements. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Digital signatures: practical implementation guidelines} + \begin{itemize}[<+->] + \item \textbf{For ECDSA implementations:} + \begin{itemize} + \item Use cryptographically secure random number generator. + \item Never reuse nonce values. + \item Implement constant-time operations. + \item Validate all input points. + \end{itemize} + \item \textbf{For Ed25519 implementations:} + \begin{itemize} + \item Follow RFC 8032 specification carefully. + \item Handle validation edge cases consistently. + \item Use established libraries (libsodium, etc.) + \end{itemize} + \item \textbf{General best practices:} + \begin{itemize} + \item Don't implement from scratch. + \item Use constant-time libraries. + \item Test with standard vectors. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Looking forward: Implementation challenges} + \begin{itemize}[<+->] + \item \textbf{Post-quantum transition:} ECC implementations need migration paths. + \begin{itemize} + \item Hybrid classical/post-quantum systems. + \item Algorithm negotiation mechanisms. + \item Backward compatibility requirements. + \item Discussed in a future class topic! + \end{itemize} + \item \textbf{Formal verification:} Mathematical proofs of implementation correctness. + \begin{itemize} + \item Projects like Cryspen's HAX and Libcrux generate verified code. + \item Higher assurance for critical applications. + \item Trade-off between verification effort and deployment flexibility. + \item Discussed in a future class topic! + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-1.tex b/slides/2-1.tex new file mode 100644 index 0000000..9ae5c60 --- /dev/null +++ b/slides/2-1.tex @@ -0,0 +1,2633 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.1: Transport Layer Security} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Why we're interested in TLS} + \begin{itemize}[<+->] + \item Encrypts all your web traffic (the \textbf{S} in HTTP\textbf{S}!) + \item Great way to introduce \textbf{authenticated key exchange}. + \item Great way to make you hate certificates and certificate authorities. + \item How TLS handles \textbf{authentication} and key exchange. + \item A comprehensive survey of \textbf{TLS 1.2 attacks}: + \begin{itemize} + \item POODLE (Padding Oracle On Downgraded Legacy Encryption) + \item Lucky Thirteen timing attack + \item SMACK (State Machine AttaCK) + \item FREAK (Factoring RSA Export Keys) + \item Logjam attack on Diffie-Hellman + \item And many more... + \end{itemize} + \item How these attacks informed the design of \textbf{TLS 1.3}. + \item Lessons learned for building secure protocols. + \end{itemize} +\end{frame} + +\begin{frame}{TLS attacks timeline (to 2015)} + \bigimagewithcaption{tls_attacks_timeline_2015.png}{TLS attacks up until 2015.} +\end{frame} + +\begin{frame}{TLS isn't very interesting} + \begin{itemize} + \item Too complicated for no good reason. + \item Doesn't accomplish properties as interesting as those of more modern protocols, or even Signal. + \item Certificate authorities. + \item Very important however to understand, basically a golden door into the world of protocols. + \end{itemize} +\end{frame} + +\begin{frame}{...and yet...} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Web browsing (HTTPS) + \item Email (IMAPS, POP3S, SMTPS) + \item Instant messaging (WhatsApp, Telegram) + \item Video conferencing (Zoom, Teams) + \item Online banking + \item Social media (Facebook, Twitter) + \item Cloud storage (Dropbox, Google Drive) + \item VPN connections + \item Mobile app communication + \item Medical devices + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item Streaming services (Netflix, Spotify) + \item IoT device communication + \item Remote desktop protocols + \item Voice over IP (VoIP) + \item Software updates + \item Database connections + \item Git repositories (GitHub, GitLab) + \item Real-time communication (WebRTC) + \item Cryptocurrency wallets + \item Smart home devices + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\section{Transport Layer Security} + +\begin{frame}{Primary applications that drove TLS development} + \begin{itemize}[<+->] + \item \textbf{E-commerce websites} + \begin{itemize} + \item Credit card numbers + \item Personal information + \item Purchase history + \end{itemize} + \item \textbf{Online banking} + \begin{itemize} + \item Account credentials + \item Financial transactions + \item Sensitive financial data + \end{itemize} + \item \textbf{General web browsing} + \begin{itemize} + \item User credentials + \item Private communications + \item Personal data protection + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Passive vs Active Attackers} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Passive Attacker} + \begin{itemize} + \item \textbf{Eavesdropping only} + \item Observes network traffic + \item Records all messages + \item Cannot modify or inject messages + \item Examples: + \begin{itemize} + \item ISP logging traffic + \item Government surveillance + \item WiFi sniffing + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Active Attacker} + \begin{itemize} + \item \textbf{Can modify/inject messages} + \item Intercepts and alters traffic + \item Can impersonate parties + \item Controls network routing + \item Examples: + \begin{itemize} + \item Man-in-the-middle attacks + \item Malicious WiFi hotspots + \item Compromised routers + \end{itemize} + \end{itemize} + \end{column} + \end{columns} + \begin{alertblock}{Protocol Design Impact} + Identity protection works against passive attackers, but active attackers can force identity revelation through protocol manipulation + \end{alertblock} +\end{frame} + +\begin{frame}{Key security goal: Defeating man-in-the-middle attacks} + \begin{itemize}[<+->] + \item \textbf{MITM attack scenario:} + \begin{enumerate} + \item Attacker intercepts encrypted traffic. + \item Decrypts the traffic to read content. + \item Re-encrypts and forwards to destination. + \end{enumerate} + \item \textbf{How TLS defeats MITM:} + \begin{itemize} + \item Server authentication using \textbf{certificates}. + \item Trusted \textbf{certificate authorities} (CAs). + \item Optional client authentication. + \end{itemize} + \item Without proper authentication, encryption alone is \textbf{not enough}! + \end{itemize} +\end{frame} + +\begin{frame}{Four requirements for wide TLS adoption} + \begin{itemize}[<+->] + \item \textbf{Efficiency} + \begin{itemize} + \item Minimize performance penalty vs. unencrypted connections. + \end{itemize} + \item \textbf{Interoperability} + \begin{itemize} + \item Work on any hardware and operating system. + \end{itemize} + \item \textbf{Extensibility} + \begin{itemize} + \item Support additional features and algorithms. + \end{itemize} + \item \textbf{Versatility} + \begin{itemize} + \item Not bound to specific applications. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Notice how we're mentioning design requirements now?} + \bigimagewithcaption{fischer.png}{Fischer et al., The Challenges of Bringing Cryptography from Research Papers to Products: Results from an Interview Study with Experts, USENIX Security 2024} +\end{frame} + +\begin{frame}{Notice how we're mentioning design requirements now?} + \begin{center} + \bigimagewithcaption{fischer_sectioned.png}{Fischer et al., The Challenges of Bringing Cryptography from Research Papers to Products: Results from an Interview Study with Experts, USENIX Security 2024} + \end{center} +\end{frame} + +\begin{frame}{Efficiency and interoperability} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Efficiency matters for:} + \begin{itemize}[<+->] + \item \textbf{Servers} + \begin{itemize} + \item Reduce hardware costs + \item Handle more connections + \end{itemize} + \item \textbf{Clients} + \begin{itemize} + \item Avoid perceptible delays + \item Preserve battery life + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Interoperability ensures:} + \begin{itemize}[<+->] + \item Works across different: + \begin{itemize} + \item Hardware platforms + \item Operating systems + \item Software implementations + \end{itemize} + \item Universal compatibility + \item No vendor lock-in + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Extensibility and versatility} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Extensibility allows:} + \begin{itemize}[<+->] + \item Adding new cryptographic algorithms + \item Supporting new features + \item Adapting to security threats + \item Protocol evolution over time + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Versatility means:} + \begin{itemize}[<+->] + \item Application-agnostic design + \item Like TCP: doesn't care about upper layers + \item Can secure any application protocol + \item Reusable security infrastructure + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The confusing SSL/TLS naming} + \begin{itemize}[<+->] + \item \textbf{1995}: Netscape develops SSL (Secure Sockets Layer). + \item \textbf{SSL 2.0 and SSL 3.0}: Both had serious security flaws. + \item \textbf{Confusing terminology}: People still call TLS ``SSL''. + \begin{itemize} + \item Even security experts do this! + \item ``SSL certificate'' really means ``TLS certificate'' + \end{itemize} + \item TLS = Transport Layer Security (SSL's successor) + \end{itemize} +\end{frame} + +\begin{frame}{TLS version evolution} + \begin{itemize}[<+->] + \item \textbf{TLS 1.0 (1999)} + \begin{itemize} + \item Least secure TLS version. + \item Still better than SSL 3.0. + \end{itemize} + \item \textbf{TLS 1.1 (2006)} + \begin{itemize} + \item Better, but includes weak algorithms. + \end{itemize} + \item \textbf{TLS 1.2 (2008)} + \begin{itemize} + \item Much better, but very complex. + \item High security only if configured correctly. + \item Supports vulnerable features (e.g., AES-CBC with padding oracles). + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{TLS 1.3: The great cleanup} + \begin{itemize}[<+->] + \item \textbf{Problem}: TLS 1.2 inherited decades of legacy features. + \begin{itemize} + \item Suboptimal security and performance. + \item Complex and error-prone configurations. + \item High risk of implementation bugs. + \end{itemize} + \item \textbf{Solution}: Complete redesign for TLS 1.3. + \begin{itemize} + \item Kept only the good parts. + \item Added modern security features. + \item Simplified the bloated design. + \end{itemize} + \item \textbf{Result}: TLS 1.3 is more secure, efficient, and simpler. + \item TLS 1.3 = ``mature TLS''. + \end{itemize} +\end{frame} + +\begin{frame}{Fantastic resource on understanding TLS}{And secure channel protocol design in general} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item The Illustrated TLS 1.2 connection: \url{https://tls12.xargs.org} + \item The Illustrated TLS 1.3 connection: \url{https://tls13.xargs.org} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{tls_illustrated}{} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{TLS architecture: Two main protocols} + \begin{itemize}[<+->] + \item \textbf{Handshake Protocol} + \begin{itemize} + \item Determines secret keys shared between client and server. + \item Handles authentication and key exchange. + \item Runs once at the beginning of a connection. + \end{itemize} + \item \textbf{Record Protocol} + \begin{itemize} + \item Describes how to use established keys to protect data. + \item Processes data packets called \textbf{records}. + \item Defines packet format for encapsulating higher-layer data. + \end{itemize} + \item Think of it as: handshake = setup, record = ongoing protection. + \end{itemize} +\end{frame} + +\begin{frame}{The TLS handshake: Basic flow} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{Step 1}: Client initiates secure connection. + \begin{itemize} + \item Sends \texttt{ClientHello} message. + \item Includes supported ciphers and other parameters. + \end{itemize} + \item \textbf{Step 2}: Server responds. + \begin{itemize} + \item Checks client's message and parameters. + \item Responds with \texttt{ServerHello} message. + \item Selects cipher suite and provides certificate. + \end{itemize} + \item \textbf{Step 3}: Key establishment. + \begin{itemize} + \item Both parties process each other's messages. + \item Establish session keys for encryption. + \end{itemize} + \item \textbf{Result}: Ready to exchange encrypted data! + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \imagewithcaption{tls_handshake.png}{TLS handshake overview.} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Critical step: Certificate validation} + \begin{itemize}[<+->] + \item \textbf{The crux of TLS security}: Server authenticates itself to client + \item \textbf{What is a certificate?} + \begin{itemize} + \item A public key + signature of that key + \begin{itemize} + \item Encoded in an insanely asinine byte format + \end{itemize} + \item Associated information (domain name, organization, etc.) + \item Essentially says: ``I am google.com, and my public key is [key]'' + \end{itemize} + \item \textbf{Certificate validation process}: + \begin{enumerate} + \item Browser receives certificate from server + \item Verifies the certificate's signature + \item If signature is valid \rightarrow certificate and public key are trusted + \item Browser proceeds with connection + \end{enumerate} + \end{itemize} +\end{frame} + +\begin{frame}{Certificate Authorities: The trust foundation} + \begin{itemize}[<+->] + \item \textbf{Problem}: How does the browser know which public key to use for verification? + \item \textbf{Solution}: Certificate Authorities (CAs) + \begin{itemize} + \item Public keys hardcoded in your browser/OS. + \item Trusted organizations that issue certificates. + \item Act as trusted third parties. + \end{itemize} + \item \textbf{CA's role}: + \begin{itemize} + \item Verify that public keys belong to claimed entities. + \item Sign certificates with their private keys. + \item Protect their private keys from compromise. + \end{itemize} + \item \textbf{Without CAs}: No way to distinguish legitimate servers from MITM attackers! + \end{itemize} +\end{frame} + +\begin{frame}{Traditional CA validation nightmare} + \begin{itemize}[<+->] + \item \textbf{Getting a certificate before 2015}: + \begin{itemize} + \item Contact a Certificate Authority (Verisign, Thawte, etc.). + \item Pay \$50-300+ per certificate per year. + \begin{itemize} + \item Completely arbitrary extortionate amounts. + \end{itemize} + \item Manual validation process takes days/weeks. + \end{itemize} + \item \textbf{Domain Validation (DV) process}: + \begin{enumerate} + \item Submit CSR (Certificate Signing Request). + \item CA sends email to \texttt{admin@domain.com}. + \item Click verification link in email. + \item Wait for manual review and approval. + \item Download and install certificate. + \end{enumerate} + \item \textbf{Extended Validation (EV) certificates}: + \begin{itemize} + \item Even more expensive (\$150-1000+/year). + \item Weeks of back-and-forth communication. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Let's Encrypt: revolution in TLS certificates (2015)} + \begin{itemize}[<+->] + \item \textbf{Game-changing}: + \begin{itemize} + \item \textbf{Free} certificates for everyone. + \item \textbf{Automated} issuance and renewal. + \item \textbf{90-day} certificate lifetime (encourages automation). + \item Open source, non-profit initiative. + \end{itemize} + \item \textbf{ACME protocol} (Automated Certificate Management Environment): + \begin{itemize} + \item Domain validation via HTTP or DNS challenges. + \item Prove control of domain programmatically. + \item Certificate issued in seconds, not days. + \item Automatic renewal before expiration. + \end{itemize} + \item \textbf{Impact on the web}: + \begin{itemize} + \item HTTPS adoption jumped from 40\% to 90\%+ of web traffic. + \item Eliminated cost barrier for small websites. + \item Made ``HTTPS everywhere'' a reality. + \end{itemize} + \item \textbf{Philosophy}: Encryption should be the default, not a luxury. + \end{itemize} +\end{frame} + +\begin{frame}{Let's Encrypt: active certificates} + \bigimagewithcaption{letsencrypt_certs.png}{Source: Let's Encrypt} +\end{frame} + +\begin{frame}{Let's Encrypt: certificates issued} + \bigimagewithcaption{letsencrypt_issuance.png}{Source: Let's Encrypt} +\end{frame} + +\begin{frame}{Percentage of HTTPS traffic in Firefox} + \bigimagewithcaption{letsencrypt_https.png}{Source: Let's Encrypt} +\end{frame} + +\begin{frame}{Certificate chains in practice} + \begin{itemize}[<+->] + \item \textbf{Real-world example}: Connecting to \texttt{www.google.com} + \item \textbf{Certificate chain structure}: + \begin{itemize} + \item \textbf{Certificate 0}: \texttt{www.google.com}'s certificate. + \item \textbf{Certificate 1}: Intermediate CA (Google Trust Services). + \item \textbf{Certificate 2}: Root CA (GlobalSign). + \end{itemize} + \item \textbf{Verification process}: + \begin{enumerate} + \item Check Google's signature on Certificate 0. + \item Check GlobalSign's signature on Certificate 1. + \item Trust GlobalSign's root certificate (pre-installed). + \end{enumerate} + \item \textbf{Chain of trust}: Each certificate vouches for the next. + \end{itemize} +\end{frame} + +\begin{frame}{Exploring certificates with OpenSSL} + \begin{itemize}[<+->] + \item \textbf{Connect and view certificate}: + \begin{itemize} + \item \texttt{openssl s\_client -connect www.google.com:443} + \item Shows certificate chain and raw certificate data + \end{itemize} + \item \textbf{Parse certificate details}: + \begin{itemize} + \item \texttt{openssl x509 -text -noout} + \item Reveals subject, issuer, validity dates, algorithms + \end{itemize} + \item \textbf{Certificate markers}: + \begin{itemize} + \item \texttt{s:} = subject (who the certificate is for) + \item \texttt{i:} = issuer (who signed the certificate) + \end{itemize} + \item Try this at home! Great way to understand the certificate ecosystem. + \end{itemize} +\end{frame} + +\begin{frame}{TLS Record Protocol: The data transport layer} + \begin{itemize}[<+->] + \item \textbf{What is the Record Protocol?} + \begin{itemize} + \item Transport protocol for all TLS data. + \item Agnostic to the meaning of transported data. + \item Makes TLS suitable for any application. + \end{itemize} + \item \textbf{Two main phases}: + \begin{enumerate} + \item \textbf{During handshake}: Carries handshake messages. + \item \textbf{After handshake}: Carries encrypted application data. + \end{enumerate} + \item \textbf{Key insight}: Like TCP, doesn't care about upper layers! + \end{itemize} +\end{frame} + +\begin{frame}{TLS Record: Basic structure} + \begin{itemize}[<+->] + \item \textbf{TLS Record = chunk of data ≤ 16KB} + \item \textbf{Simple header structure}: + \begin{itemize} + \item Only 3 fields (vs. 14 in IPv4, 13 in TCP) + \item 5-byte header + payload + \end{itemize} + \item \textbf{Visual representation}: + \end{itemize} + \pause + \begin{center} + \begin{tabular}{|c|c|c|c|} + \hline + \textbf{ContentType} & \textbf{ProtocolVersion} & \textbf{Length} & \textbf{Payload} \\ + \hline + 1 byte & 2 bytes & 2 bytes & ≤ 16KB \\ + \hline + \end{tabular} + \end{center} +\end{frame} + +\begin{frame}{TLS Record fields breakdown} + \begin{itemize}[<+->] + \item \textbf{Byte 1 - ContentType}: + \begin{itemize} + \item \texttt{22} = Handshake data + \item \texttt{23} = Encrypted application data + \item \texttt{21} = Alerts (error messages) + \end{itemize} + \item \textbf{Bytes 2-3 - ProtocolVersion}: + \begin{itemize} + \item Always \texttt{03 01} (historical reasons) + \item Same across TLS versions (confusing!) + \end{itemize} + \item \textbf{Bytes 4-5 - Length}: + \begin{itemize} + \item 16-bit integer encoding payload length + \item Maximum: $2^{14}$ bytes = 16KB + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{ContentType: What's in this record?} + \begin{center} + \begin{tabular}{|c|c|l|} + \hline + \textbf{Value} & \textbf{Name} & \textbf{Contains} \\ + \hline + 21 & Alert & Error messages, warnings \\ + \hline + 22 & Handshake & \parbox[t]{3cm}{ClientHello, ServerHello, \\Certificate, etc.} \\ + \hline + 23 & Application Data & \parbox[t]{3cm}{Encrypted user data \\(HTTP, email, etc.)} \\ + \hline + \end{tabular} + \end{center} + \pause + \begin{itemize} + \item \textbf{Key point}: ContentType tells receiver how to process the payload. + \item \textbf{During handshake}: Mostly type 22 records. + \item \textbf{After handshake}: Mostly type 23 records. + \end{itemize} +\end{frame} + +\begin{frame}{Encrypted records (ContentType = 23)} + \begin{itemize}[<+->] + \item \textbf{When ContentType = 23}: + \begin{itemize} + \item Payload is encrypted and authenticated. + \item Contains: ciphertext + authentication tag. + \end{itemize} + \item \textbf{How does receiver know how to decrypt?} + \begin{itemize} + \item Cipher and key established during handshake. + \item ``Magic of TLS'': if you receive encrypted data, you already have the key! + \end{itemize} + \item \textbf{Decryption process}: + \begin{enumerate} + \item Verify authentication tag. + \item Decrypt ciphertext. + \item Process decrypted application data. + \end{enumerate} + \end{itemize} +\end{frame} + +\begin{frame}{Nonces: Ensuring unique encryption} + \begin{itemize}[<+->] + \item \textbf{Problem}: Each record needs a unique nonce for encryption. + \item \textbf{TLS solution}: Derive nonces from sequence numbers. + \begin{itemize} + \item Each party maintains 64-bit sequence number. + \item Incremented for each new record. + \item Starts at 0, goes 1, 2, 3, ... + \end{itemize} + \item \textbf{Nonce derivation}: + \begin{itemize} + \item Client: \texttt{sequence\_number $\oplus$ client\_write\_iv} + \item Server: \texttt{sequence\_number $\oplus$ server\_write\_iv} + \end{itemize} + \item \textbf{No nonce reuse}: Different IVs and keys per direction. + \end{itemize} +\end{frame} + +\begin{frame}{Example: Sequence numbers in action} + \begin{center} + \textbf{Client sending records:} + \begin{tabular}{|c|c|} + \hline + \textbf{Record \#} & \textbf{Sequence Number} \\ + \hline + 1st record & 0 \\ + \hline + 2nd record & 1 \\ + \hline + 3rd record & 2 \\ + \hline + \end{tabular} + \end{center} + \pause + \begin{center} + \textbf{Client receiving records:} + \begin{tabular}{|c|c|} + \hline + \textbf{Record \#} & \textbf{Sequence Number} \\ + \hline + 1st record & 0 \\ + \hline + 2nd record & 1 \\ + \hline + 3rd record & 2 \\ + \hline + \end{tabular} + \end{center} + \pause + \begin{itemize} + \item \textbf{Safe to reuse numbers}: Different keys and IVs per direction! + \end{itemize} +\end{frame} + +\begin{frame}{Zero padding example} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Without padding:} + \begin{itemize} + \item Short message \rightarrow\ small ciphertext + \item Long message \rightarrow\ large ciphertext + \item Attacker learns message sizes + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{With padding:} + \begin{itemize} + \item Short message + padding \rightarrow\ large ciphertext + \item Long message + padding \rightarrow\ large ciphertext + \item All messages look the same size! + \end{itemize} + \end{column} + \end{columns} + \pause + \begin{center} + \textbf{Trade-off}: Security vs. bandwidth efficiency + \end{center} +\end{frame} + +\begin{frame}{TLS: the handshake protocol} + \begin{itemize}[<+->] + \item \textbf{The crux of TLS}: Process to establish shared secret keys. + \item \textbf{Goal}: Initiate secure communications between client and server. + \item \textbf{Key outcome}: Both parties agree on: + \begin{itemize} + \item TLS version to use + \item Cipher suite for encryption + \item Shared secret keys for protection + \end{itemize} + \item \textbf{Interoperability requirement}: Any TLS 1.3 client must work with any TLS 1.3 server. + \begin{itemize} + \item Achieved through standardized message formats. + \item Works regardless of implementation or programming language. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{TLS: the handshake protocol} + \bigimagewithcaption{tls_13_handshake}{TLS 1.3 handshake protocol. Source: Serious Cryptography} +\end{frame} + +\begin{frame}{Client vs. Server: Different roles in the handshake} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Client's role:} + \begin{itemize}[<+->] + \item \textbf{Proposes} configurations + \item Lists supported TLS versions + \item Lists supported cipher suites + \item Orders preferences (most preferred first) + \item Generates Diffie-Hellman key pair + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Server's role:} + \begin{itemize}[<+->] + \item \textbf{Chooses} final configuration + \item Selects TLS version to use + \item Picks cipher suite from client's list + \item Should follow client's preferences + \item Responds with its own DH public key + \end{itemize} + \end{column} + \end{columns} + \pause + \begin{center} + \textbf{Think of it like ordering at a restaurant:}\\ + Client: ``Here's what I like...'' \quad Server: ``We'll go with this option.'' + \end{center} +\end{frame} + +\begin{frame}{ClientHello: ``I want to establish a TLS connection''} + \begin{itemize}[<+->] + \item \textbf{Client's opening message to server} + \item \textbf{Key contents}: + \begin{itemize} + \item List of supported cipher suites (in order of preference) + \item Diffie-Hellman public key (generated just for this session!) + \item 32-byte random value + \item Optional extensions and parameters + \end{itemize} + \item \textbf{Critical security detail}: DH private key stays with client. + \item \textbf{Format requirement}: Must follow exact byte format from TLS 1.3 spec. + \begin{itemize} + \item Ensures any server can parse any client's message. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{ServerHello: ``Here's what we'll use and who I am''} + \begin{itemize}[<+->] + \item \textbf{Server's response}: Packed with crucial information! + \item \textbf{Configuration decisions}: + \begin{itemize} + \item Selected cipher suite (from client's list) + \item Server's Diffie-Hellman public key + \item 32-byte random value + \end{itemize} + \item \textbf{Authentication materials}: + \begin{itemize} + \item Certificate (contains server's public key) + \item Signature of ClientHello + ServerHello contents + \item MAC of all the above information + \end{itemize} + \item \textbf{Crypto magic}: MAC uses key derived from DH shared secret! + \end{itemize} +\end{frame} + +\begin{frame}{Client verification: ``Can I trust this server?''} + \begin{itemize}[<+->] + \item \textbf{When client receives ServerHello}: + \item \textbf{Step 1}: Certificate validation + \begin{itemize} + \item Check certificate chain to trusted CA + \item Verify certificate hasn't expired + \item Confirm certificate matches domain name + \end{itemize} + \item \textbf{Step 2}: Signature verification + \begin{itemize} + \item Use certificate's public key to verify signature + \item Ensures server controls the private key + \end{itemize} + \item \textbf{Step 3}: Derive shared secrets + \begin{itemize} + \item Compute DH shared secret: $g^{ab} \bmod p$ + \item Derive symmetric keys from shared secret + \end{itemize} + \item \textbf{Step 4}: MAC verification + \begin{itemize} + \item Verify MAC using derived symmetric key + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{All checks pass: Ready for encrypted communication!} + \begin{center} + \textbf{After successful verification:} + \end{center} + \begin{itemize}[<+->] + \item Client is confident it's talking to the legitimate server. + \item Both parties have the same shared secret keys. + \item Ready to send encrypted application data! + \item \textbf{Security guarantees achieved}: + \begin{itemize} + \item \textbf{Confidentiality}: Traffic is encrypted + \item \textbf{Integrity}: Traffic is authenticated + \item \textbf{Authentication}: Server identity verified + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Real-world example: Visiting \texttt{aub.edu.lb}} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Step 1}: Browser sends ClientHello + \begin{itemize}[<+->] + \item Lists supported ciphers + \item Includes DH public key + \item Adds random nonce + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Step 2}: Server responds + \begin{itemize}[<+->] + \item Sends ServerHello + \item Provides certificate for ``\texttt{aub.edu.lb}'' + \item Includes signature and MAC + \end{itemize} + \end{column} + \end{columns} + \pause + \begin{center} + \textbf{Step 3}: Browser verification + \end{center} + \begin{itemize}[<+->] + \item Certificate validated using browser's built-in CA certificates + \item Must be signed by trusted certificate authority + \item Certificate must match domain name: ``\texttt{aub.edu.lb}'' + \item All cryptographic checks must pass + \end{itemize} + \pause + \begin{center} + \textbf{Step 4}: Browser requests initial page over encrypted channel! + \end{center} +\end{frame} + +\begin{frame}{Security guarantees after successful TLS handshake} + \begin{itemize}[<+->] + \item \textbf{All communications are encrypted and authenticated} + \item \textbf{What an eavesdropper can see}: + \begin{itemize} + \item Client IP address + \item Server IP address + \item Encrypted content (but can't read it!) + \item Traffic patterns and timing + \end{itemize} + \item \textbf{What an eavesdropper CANNOT do}: + \begin{itemize} + \item Read the underlying plaintext + \item Modify messages without detection + \item Impersonate either party + \end{itemize} + \item \textbf{Authentication guarantee}: If messages are tampered with, receiving party will detect it! + \item \textbf{Bottom line}: Enough security for most applications. + \end{itemize} +\end{frame} + +\begin{frame}{Forward Secrecy: Protecting past communications} + \begin{itemize}[<+->] + \item \textbf{The problem}: What if a server's private key is compromised? + \begin{itemize} + \item Attacker could decrypt \textbf{all past} TLS sessions. + \item Years of stored encrypted traffic becomes readable. + \item Example: NSA's alleged collection of encrypted internet traffic. + \end{itemize} + \item \textbf{Forward secrecy (Perfect Forward Secrecy - PFS)}: + \begin{itemize} + \item Ensures past sessions remain secure even if long-term keys are compromised. + \item Each session uses unique, \textbf{ephemeral keys}. + \begin{itemize} + \item \textit{ephemeral: ``lasting a very short time''} + \end{itemize} + \item Session keys are deleted after use. + \end{itemize} + \item \textbf{Security guarantee}: ``Even if you compromise me today, you can't read yesterday's traffic.'' + \item \textbf{Critical for}: Journalists, activists, whistleblowers, ordinary citizens + \end{itemize} +\end{frame} + +\begin{frame}{How TLS achieves forward secrecy} + \begin{itemize}[<+->] + \item \textbf{Ephemeral Diffie-Hellman key exchange}: + \begin{itemize} + \item Server generates fresh DH key pair for each session. + \item Client generates fresh DH key pair for each session. + \item Shared secret computed: $g^{ab} \bmod p$ (then deleted!). + \end{itemize} + \item \textbf{Key lifecycle}: + \begin{enumerate} + \item Generate ephemeral keys for handshake. + \item Derive session keys from ephemeral shared secret. + \item \textbf{Delete ephemeral private keys immediately}. + \item Use session keys for encrypted communication. + \item Delete session keys when connection ends. + \end{enumerate} + \item \textbf{Server's long-term private key}: Only used to \textbf{sign} the handshake + \begin{itemize} + \item Not used to derive session keys directly. + \item Compromising it doesn't reveal past session keys. + \end{itemize} + \item \textbf{Result}: Each TLS session is cryptographically independent. + \end{itemize} +\end{frame} + +\begin{frame}{How things can go wrong with TLS} + \begin{itemize}[<+->] + \item \textbf{Common TLS failure scenarios:} + \begin{itemize} + \item Even with the most secure ciphers, TLS can be compromised + \item Security relies on assumptions about honest behavior + \end{itemize} + \item \textbf{Key assumption}: All three parties behave honestly + \begin{itemize} + \item Client + \item Server + \item Certificate Authority (CA) + \end{itemize} + \item \textbf{Reality check}: What if one party is compromised? + \item \textbf{Implementation matters}: Poor TLS implementations create vulnerabilities + \end{itemize} +\end{frame} + +\begin{frame}{Compromised Certificate Authority} + \begin{itemize}[<+->] + \item \textbf{Root CAs}: Organizations that browsers trust to validate certificates + \item \textbf{Normal process}: + \begin{itemize} + \item CA verifies legitimacy of certificate owner. + \item CA signs certificate with their private key. + \item Browser trusts CA's signature. + \end{itemize} + \item \textbf{Attack scenario}: CA's private key is compromised + \begin{itemize} + \item Attacker can create certificates for \textbf{any domain}. + \item No approval needed from actual domain owner. + \item Can impersonate legitimate servers. + \end{itemize} + \item \textbf{Attack capabilities}: + \begin{itemize} + \item Create fake certificates for \texttt{google.com}, \texttt{instagram.com}, etc. + \item Intercept user credentials and communications. + \item Man-in-the-middle attacks become trivial. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Real-world example: DigiNotar} + \begin{itemize}[<+->] + \item \textbf{What happened}: + \begin{itemize} + \item Dutch certificate authority DigiNotar was hacked. + \item Attackers gained access to CA's private keys. + \item Created fake certificates for Google services. + \end{itemize} + \item \textbf{Impact}: + \begin{itemize} + \item Users unknowingly connected to malicious servers. + \item Credentials and communications intercepted. + \item Trust in entire CA system questioned. + \end{itemize} + \item \textbf{Aftermath}: + \begin{itemize} + \item DigiNotar went bankrupt. + \item All major browsers removed DigiNotar certificates. + \item Led to improved CA monitoring and transparency. + \end{itemize} + \item \textbf{Lesson}: CAs are high-value targets for attackers! + \end{itemize} +\end{frame} + +\begin{frame}{Real-world example: Kazakhstan government certificate} + \begin{columns}[c] + \begin{column}{0.8\textwidth} + \begin{itemize}[<+->] + \item \textbf{2015}: Kazakhstan government creates ``national security certificate'' + \begin{itemize} + \item Root certificate that could enable MITM attacks. + \item Would allow government to intercept HTTPS traffic. + \item Required manual installation on users' devices. + \end{itemize} + \item \textbf{July 2019}: Government mandates certificate installation + \begin{itemize} + \item ISPs instructed users to install ``Qaznet Trust Certificate''. + \item Issued by state CA: Qaznet Trust Network. + \item Initial targets: Google, Facebook, Twitter. + \end{itemize} + \item \textbf{August 2019}: Browser vendors fight back + \begin{itemize} + \item Mozilla (Firefox) and Google (Chrome) block the certificate. + \item Apple (Safari) joins the blocking effort. + \item Microsoft reiterates certificate not in trusted root store. + \end{itemize} + \item \textbf{December 2020}: Government tries again, browsers block again + \end{itemize} + \end{column} + \begin{column}{0.2\textwidth} + \imagewithcaption{tls_borat.jpg}{} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Kazakhstan case: Lessons for TLS security} + \begin{itemize}[<+->] + \item \textbf{Government-level MITM attempts are real} + \begin{itemize} + \item Nation-states can create sophisticated infrastructure. + \item Legal pressure on ISPs and users. + \item ``National security'' justifications. + \end{itemize} + \item \textbf{Browser vendors as guardians}: + \begin{itemize} + \item Coordinate to protect users from malicious CAs. + \item Can override user certificate installations. + \item Technical measures against political pressure. + \end{itemize} + \item \textbf{Certificate transparency importance}: + \begin{itemize} + \item Public logs make rogue certificates detectable. + \item Community monitoring of CA behavior. + \item Enables coordinated responses to threats. + \end{itemize} + \item \textbf{Bottom line}: Even governments can't easily break modern TLS + \end{itemize} +\end{frame} + +\begin{frame}{Certificate Transparency} + \begin{itemize}[<+->] + \item \textbf{The problem}: CAs can issue certificates without anyone knowing. + \begin{itemize} + \item Rogue certificates for targeted attacks. + \item Compromised CAs issuing malicious certificates. + \item No way to detect misbehavior after the fact. + \end{itemize} + \item \textbf{Certificate Transparency (CT) solution} (2013): + \begin{itemize} + \item CAs must submit all certificates to public logs. + \item Logs are cryptographically append-only. + \item Anyone can monitor logs for suspicious certificates. + \end{itemize} + \item \textbf{How it works}: + \begin{enumerate} + \item CA issues certificate and submits to CT logs. + \item Log returns Signed Certificate Timestamp (SCT). + \item Certificate includes SCT as proof of logging. + \item Browsers reject certificates without valid SCTs. + \end{enumerate} + \item \textbf{Result}: CA misbehavior becomes publicly detectable! + \end{itemize} +\end{frame} + +\begin{frame}{Example: How Let's Encrypt uses CT} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{The Static CT API}: Evolution of Certificate Transparency. + \begin{itemize} + \item Logs represented as simple flat files (``tiles''). + \item Download log data just like downloading files. + \item CDN-friendly, cheaper to operate. + \end{itemize} + \item \textbf{Key advantages}: + \begin{itemize} + \item 10x+ cheaper to operate (~\$10k/year vs traditional logs). + \item More reliable (simpler architecture). + \item Easier to download and share data. + \end{itemize} + \item \textbf{Sunlight}: + \begin{itemize} + \item Open source CT implementation used by Let's Encrypt.\footnote{\url{https://letsencrypt.org/2025/06/11/reflections-on-a-year-of-sunlight/}} + \item \url{https://sunlight.dev} + \end{itemize} + \item \textbf{Status}: Chrome and Safari now accepting Static CT API logs! + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Critical examination: Are browser vendors truly neutral?} + \begin{itemize}[<+->] + \item \textbf{Browser vendors as gatekeepers}: + \begin{itemize} + \item Google (Chrome), Mozilla (Firefox), Apple (Safari), Microsoft (Edge). + \item Unilateral power to accept/reject certificates. + \item Who watches the watchers? + \end{itemize} + \item \textbf{Political and economic pressures}: + \begin{itemize} + \item Companies have business interests and government relations. + \item What if a government pressures Google/Apple directly? + \item Corporate decisions affecting global internet security. + \end{itemize} + \item \textbf{The CA model's fundamental problems}: + \begin{itemize} + \item \textbf{Single point of failure}: Any CA can issue certificates for any domain. + \item \textbf{Asymmetric trust}: Must trust \textbf{all} CAs, not just one. + \item \textbf{Centralized control}: Small number of entities control global trust. + \item \textbf{Economic incentives}: CAs profit from issuing more certificates. + \end{itemize} + \item \textbf{Question}: Is this the best we can do for global internet security? + \end{itemize} +\end{frame} + +\begin{frame}{Thinking beyond: Decentralized trust alternatives} + \begin{itemize}[<+->] + \item \textbf{Why consider alternatives?} + \begin{itemize} + \item Reduce single points of failure. + \item Eliminate centralized gatekeepers. + \item Increase transparency and auditability. + \end{itemize} + \item \textbf{Blockchain-based certificate systems}: + \begin{itemize} + \item Certificates recorded on public blockchain. + \item Cryptographic proof of certificate history. + \item Examples: Namecoin, Ethereum Name Service (ENS) + \item \textbf{Trade-offs}: Scalability, energy consumption, governance. + \end{itemize} + \item \textbf{Web of Trust models}: + \begin{itemize} + \item Users vouch for each other's identities (like PGP). + \item Decentralized reputation systems. + \item \textbf{Trade-offs}: User complexity, bootstrap problem + \end{itemize} + \item \textbf{DNS-based alternatives}: DANE (DNS-based Authentication of Named Entities) + \item \textbf{Your turn}: What other models could work? What are the trade-offs? + \end{itemize} +\end{frame} + +\begin{frame}{Compromised Server} + \begin{itemize}[<+->] + \item \textbf{Worst-case scenario}: Server is fully controlled by attacker + \item \textbf{What the attacker gains}: + \begin{itemize} + \item Session keys (server is TLS termination point) + \item All transmitted data \textbf{before} encryption + \item All received data \textbf{after} decryption + \item Server's private key + \end{itemize} + \item \textbf{Attack capabilities}: + \begin{itemize} + \item Read all user communications in plaintext + \item Impersonate the legitimate server + \item Use private key to create malicious servers + \end{itemize} + \item \textbf{Bottom line}: TLS won't save you if the server is compromised! + \end{itemize} +\end{frame} + +\begin{frame}{Server compromise: Mitigation strategies} + \begin{itemize}[<+->] + \item \textbf{Good news}: High-profile services are well-protected + \begin{itemize} + \item Gmail, iCloud, major banks + \item Multiple layers of security + \end{itemize} + \item \textbf{Hardware Security Modules (HSMs)}: + \begin{itemize} + \item Store private keys in separate, tamper-resistant hardware + \item Even if server is compromised, keys may remain safe + \end{itemize} + \item \textbf{Key Management Systems (KMS)}: + \begin{itemize} + \item Centralized key storage and management + \item Limits exposure of private keys + \end{itemize} + \item \textbf{More common threats}: Web application vulnerabilities + \begin{itemize} + \item SQL injection, cross-site scripting (XSS) + \item Carried out \textbf{over} legitimate TLS connections + \item Independent of TLS security + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Compromised Client} + \begin{itemize}[<+->] + \item \textbf{Attack scenario}: Browser or client application is compromised + \item \textbf{What the attacker gains}: + \begin{itemize} + \item Session keys from compromised client + \item All decrypted data visible to client + \item Ability to modify client behavior + \end{itemize} + \item \textbf{Advanced attack}: Installing rogue CA certificates + \begin{itemize} + \item Add malicious CA to client's trusted store + \item Client silently accepts invalid certificates + \item Enables seamless man-in-the-middle attacks + \end{itemize} + \item \textbf{Scope difference}: + \begin{itemize} + \item Compromised CA/server: affects \textbf{all} clients + \item Compromised client: affects \textbf{only that} client + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Client compromise: Attack techniques} + \begin{itemize}[<+->] + \item \textbf{Malware installation}: + \begin{itemize} + \item Trojans, viruses, browser plugins + \item Can intercept data before encryption + \end{itemize} + \item \textbf{Certificate store manipulation}: + \begin{itemize} + \item Add attacker's CA certificate to trusted store + \item Modify certificate validation logic + \end{itemize} + \item \textbf{Browser hijacking}: + \begin{itemize} + \item Redirect traffic through attacker's proxy + \item Modify DNS settings + \end{itemize} + \item \textbf{Protection strategies}: + \begin{itemize} + \item Keep browsers and OS updated + \item Use reputable antivirus software + \item Certificate pinning (for developers) + \item Monitor certificate store changes + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{TLS security: A chain is only as strong as its weakest link} + \begin{center} + \textbf{Three points of failure in the TLS trust model:} + \end{center} + \begin{columns}[c] + \begin{column}{0.33\textwidth} + \textbf{Certificate Authority} + \begin{itemize} + \item Must protect private keys + \item Must verify identities correctly + \item Must not issue rogue certificates + \end{itemize} + \end{column} + \begin{column}{0.33\textwidth} + \textbf{Server} + \begin{itemize} + \item Must protect private keys + \item Must maintain secure infrastructure + \item Must handle session keys safely + \end{itemize} + \end{column} + \begin{column}{0.33\textwidth} + \textbf{Client} + \begin{itemize} + \item Must validate certificates properly + \item Must protect trusted CA store + \item Must remain malware-free + \end{itemize} + \end{column} + \end{columns} + \pause + \begin{center} + \textbf{Compromise any one component} \rightarrow\ \textbf{TLS security fails!} + \end{center} +\end{frame} + +\section{Attacks on TLS} + +\begin{frame}{TLS attacks timeline (to 2015)} + \bigimagewithcaption{tls_attacks_timeline_2015.png}{TLS attacks up until 2015.} +\end{frame} + +\begin{frame}{Lucky Thirteen (2013)} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Target}: TLS's CBC (Cipher Block Chaining) mode with HMAC + \item \textbf{The vulnerability}: Timing differences in MAC verification\footnote{\url{https://appliedcryptography.page/papers/lucky-thirteen.pdf}} + \begin{itemize} + \item TLS 1.0-1.2 used MAC-then-encrypt with CBC mode + \item Padding oracle attacks exploit timing differences + \item Different MAC verification procedures for valid vs. invalid padding + \end{itemize} + \item \textbf{Attack mechanism}: + \begin{enumerate} + \item Attacker modifies ciphertext to create invalid padding + \item Measures server response time + \item Timing differences reveal padding validity + \item Uses timing to guess plaintext byte-by-byte + \end{enumerate} + \item \textbf{Why ``Lucky Thirteen''?} Attack requires exactly 13 bytes of padding + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Lucky Thirteen: Technical details} + \begin{itemize}[<+->] + \item \textbf{CBC padding in TLS}: + \begin{itemize} + \item Messages padded to block boundary (16 bytes for AES) + \item Padding bytes contain length of padding + \item Example: \texttt{...data|05|05|05|05|05|05} (5 bytes padding) + \end{itemize} + \item \textbf{The timing leak}: + \begin{itemize} + \item \textbf{Valid padding}: MAC checked on message after padding removal + \item \textbf{Invalid padding}: TLS spec says to check MAC as if padding had zero-length + \item Different amounts of data processed creates timing difference + \end{itemize} + \item \textbf{Statistical attack}: + \begin{itemize} + \item Send thousands of modified ciphertexts + \item Measure response times + \item Statistical analysis reveals timing patterns + \end{itemize} + \item \textbf{Result}: Can decrypt HTTPS cookies, passwords, session tokens + \end{itemize} +\end{frame} + +\begin{frame}{Lucky Thirteen: Real-world impact} + \begin{itemize}[<+->] + \item \textbf{Affected systems}: All TLS 1.0-1.2 implementations using CBC + \begin{itemize} + \item OpenSSL, NSS, GnuTLS, SChannel + \item Millions of web servers worldwide + \end{itemize} + \item \textbf{Practical exploitation}: + \begin{itemize} + \item Requires man-in-the-middle position + \item Can extract secrets from encrypted sessions + \item Especially dangerous on shared networks (Wi-Fi) + \end{itemize} + \item \textbf{Mitigation attempts}: + \begin{itemize} + \item Constant-time implementations (hard to get right) + \item Prefer AEAD ciphers (AES-GCM) + \item Ultimately: abandon CBC mode entirely + \end{itemize} + \item \textbf{Legacy}: Demonstrated fundamental flaws in MAC-then-encrypt + \end{itemize} +\end{frame} + +\begin{frame}{POODLE (2014): Downgrade attacks strike} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Full name}: Padding Oracle On Downgraded Legacy Encryption\footnote{\url{https://appliedcryptography.page/papers/google-poodle.pdf}} + \item \textbf{Target}: SSL 3.0 (ancient protocol from 1996) + \item \textbf{The setup}: + \begin{itemize} + \item Browsers support SSL 3.0 for ``compatibility'' + \item Attacker forces downgrade from TLS to SSL 3.0 + \item SSL 3.0 has weaker padding validation + \end{itemize} + \item \textbf{Attack flow}: + \begin{enumerate} + \item Client attempts TLS 1.2 connection + \item Attacker blocks/corrupts TLS handshake + \item Client ``gracefully'' falls back to SSL 3.0 + \item Attacker exploits SSL 3.0 padding oracle + \end{enumerate} + \item \textbf{Discovered by}: Google Security Team + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{POODLE: The padding oracle vulnerability} + \begin{itemize}[<+->] + \item \textbf{SSL 3.0 padding flaw}: + \begin{itemize} + \item Padding bytes can contain \textbf{any values} + \item Only padding length is validated + \item Unlike TLS, which requires specific padding patterns + \end{itemize} + \item \textbf{Attack technique}: + \begin{itemize} + \item Replace last block of ciphertext with target block + \item If padding is valid, server processes message + \item If padding is invalid, server returns error + \item Use oracle to guess plaintext bytes + \end{itemize} + \item \textbf{Efficiency}: + \begin{itemize} + \item Extract one byte per 256 requests (on average) + \item Much faster than previous padding oracle attacks + \end{itemize} + \item \textbf{Practical impact}: Steal HTTP cookies, session tokens + \end{itemize} +\end{frame} + +\begin{frame}{POODLE: Industry response and lessons} + \begin{itemize}[<+->] + \item \textbf{Immediate response}: + \begin{itemize} + \item Major browsers disabled SSL 3.0 support + \item Server administrators configured to reject SSL 3.0 + \item ``Fallback SCSV'' mechanism introduced + \end{itemize} + \item \textbf{Fallback SCSV}: Cryptographic downgrade protection + \begin{itemize} + \item Client signals highest supported version + \item Server detects and rejects artificial downgrades + \item Prevents attacker-induced fallbacks + \end{itemize} + \item \textbf{Broader lessons}: + \begin{itemize} + \item Backward compatibility creates security risks + \item Legacy protocols should be completely removed + \item Graceful degradation can be graceful exploitation + \end{itemize} + \item \textbf{Long-term impact}: Accelerated retirement of old protocols + \end{itemize} +\end{frame} + +\begin{frame}{Triple Handshakes and Cookie Cutters (2014)} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Discovered by}: Inria Prosecco team (future TLS 1.3 verifiers!) + \item \textbf{Core problem}: TLS handshake can be \textbf{resumed} with different certificates\footnote{\url{https://appliedcryptography.page/papers/triple-handshakes.pdf}} + \begin{itemize} + \item Client connects to Server A, establishes session + \item Session can be resumed with Server B using different certificate + \item Client may not notice certificate change + \end{itemize} + \item \textbf{Attack scenario}: + \begin{itemize} + \item Attacker has certificate for \texttt{evil.com} + \item Tricks client into resuming session with \texttt{good.com} + \item Client thinks it's talking to \texttt{good.com} + \item Actually talking to attacker with \texttt{evil.com} certificate + \end{itemize} + \item \textbf{Impact}: Breaks TLS authentication guarantees + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Triple Handshakes: The technical attack} + \begin{itemize}[<+->] + \item \textbf{Session resumption vulnerability}: + \begin{itemize} + \item TLS allows resuming sessions with different certificates + \item Session keys remain the same + \item Client authentication context gets confused + \end{itemize} + \item \textbf{``Triple handshake'' attack}: + \begin{enumerate} + \item Handshake 1: Client \leftarrow\ Attacker (using evil certificate) + \item Handshake 2: Attacker \leftarrow\ Server (using good certificate) + \item Handshake 3: Client \leftarrow\ Server (resumed session, confused identity) + \end{enumerate} + \item \textbf{Result}: Client sends sensitive data to attacker + \item \textbf{Renegotiation attacks}: Similar issues with TLS renegotiation + \item \textbf{Cookie cutter}: Attacker can splice different handshakes together + \end{itemize} +\end{frame} + +\begin{frame}{Triple Handshakes: Fixes and prevention} + \begin{itemize}[<+->] + \item \textbf{Extended Master Secret (RFC 7627)}: + \begin{itemize} + \item Bind session keys to handshake transcript + \item Prevents session resumption with different handshakes + \item Master secret includes hash of all handshake messages + \end{itemize} + \item \textbf{Renegotiation Indication Extension}: + \begin{itemize} + \item Cryptographically bind renegotiated connections + \item Prevents injection of malicious handshakes + \end{itemize} + \item \textbf{TLS 1.3 solution}: + \begin{itemize} + \item Completely removes renegotiation + \item Simplified session resumption with PSK + \item Cannot resume with different certificates + \end{itemize} + \item \textbf{Significance}: Showed TLS state machine was more complex than realized + \end{itemize} +\end{frame} + +\begin{frame}{Heartbleed (2014): The bug that broke the internet} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Not a protocol flaw}: Implementation bug in OpenSSL\footnote{\url{https://appliedcryptography.page/papers/matter-heartbleed.pdf}} + \item \textbf{The vulnerability}: Buffer over-read in heartbeat extension + \begin{itemize} + \item Heartbeat: ``keep-alive'' mechanism for TLS + \item Client sends data + length field + \item Server echoes data back + \end{itemize} + \item \textbf{The bug}: No bounds checking on length field + \begin{itemize} + \item Send 1 byte of data, claim it's 64KB + \item Server copies 64KB from memory + \item Returns server's memory contents to attacker + \end{itemize} + \item \textbf{Impact}: Arbitrary memory disclosure + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Heartbleed: What attackers could steal} + \begin{itemize}[<+->] + \item \textbf{Server's private keys}: + \begin{itemize} + \item TLS private keys used for authentication + \item Allows impersonation of legitimate servers + \item Forward secrecy completely broken + \end{itemize} + \item \textbf{Session keys and user data}: + \begin{itemize} + \item Active TLS session keys + \item Usernames, passwords, session cookies + \item Credit card numbers, personal information + \end{itemize} + \item \textbf{Memory contents}: + \begin{itemize} + \item Random 64KB chunks of server memory + \item Could contain anything: keys, data, code + \item Repeated requests reveal more memory + \end{itemize} + \item \textbf{No evidence of exploitation}: Attack leaves no traces in logs + \end{itemize} +\end{frame} + +\begin{frame}{Heartbleed: The simple attack} + \begin{center} + \textbf{Normal heartbeat request:} + \end{center} + \begin{center} + \texttt{Type=1, Length=4, Data="PING"} + \end{center} + \begin{center} + Server responds: \texttt{"PING"} + \end{center} + \pause + \begin{center} + \textbf{Malicious heartbeat request:} + \end{center} + \begin{center} + \texttt{Type=1, Length=65535, Data="A"} + \end{center} + \begin{center} + Server responds: \texttt{"A" + 65534 bytes of memory} + \end{center} + \pause + \begin{itemize}[<+->] + \item \textbf{One line of C code}: \texttt{memcpy(bp, pl, payload);} + \item \textbf{Missing check}: \texttt{if (payload != 1 + 2 + hblen) error();} + \item \textbf{Lesson}: Simple bugs can have massive consequences + \end{itemize} +\end{frame} + +\begin{frame}{Heartbleed: Global impact and response} + \begin{itemize}[<+->] + \item \textbf{Affected systems}: + \begin{itemize} + \item 17\% of all SSL/TLS web servers (500,000+ sites) + \item Major services: Yahoo, Flickr, Stack Overflow + \item OpenSSL versions 1.0.1 through 1.0.1f + \end{itemize} + \item \textbf{Emergency response}: + \begin{itemize} + \item OpenSSL fixed within days + \item Mass certificate revocation and reissuance + \item Users advised to change all passwords + \end{itemize} + \item \textbf{Long-term consequences}: + \begin{itemize} + \item Increased funding for OpenSSL development + \item Core Infrastructure Initiative (CII) formed + \item Better security auditing of critical libraries + \end{itemize} + \item \textbf{Branding success}: First security vulnerability with logo and website + \end{itemize} +\end{frame} + +\begin{frame}{SMACK and FREAK: Two attacks from one paper (2015)} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Research by}: Inria Prosecco team (again!)\footnote{\url{https://appliedcryptography.page/papers/smack-tls.pdf}} + \item \textbf{Two major attack classes discovered}: + \begin{itemize} + \item \textbf{SMACK}: State Machine AttaCKs + \item \textbf{FREAK}: Factoring RSA Export Keys + \end{itemize} + \item \textbf{SMACK core insight}: TLS implementations have \textbf{state machines} + \begin{itemize} + \item Expected message sequence: ClientHello → ServerHello → Certificate → ... + \item Implementations track current state + \item But different implementations have different state machines! + \end{itemize} + \item \textbf{FREAK core insight}: Legacy export-grade RSA still supported + \begin{itemize} + \item 512-bit RSA keys can be factored in hours + \item Downgrade attacks force use of weak keys + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{SMACK: How state machine attacks work} + \begin{itemize}[<+->] + \item \textbf{Example scenario}: Web server with two TLS libraries + \begin{itemize} + \item Library A handles initial handshake + \item Library B handles application data + \end{itemize} + \item \textbf{Attack technique}: + \begin{enumerate} + \item Send duplicate or out-of-order handshake messages + \item Library A and Library B enter different states + \item Library A thinks handshake is complete + \item Library B thinks handshake is still in progress + \end{enumerate} + \item \textbf{Result}: + \begin{itemize} + \item Bypass authentication + \item Downgrade security parameters + \item Inject malicious data + \end{itemize} + \item \textbf{Discovery method}: Systematic testing with model checking + \end{itemize} +\end{frame} + +\begin{frame}{SMACK: How state machine attacks work} + \bigimagewithcaption{tls_smack.png}{} +\end{frame} + +\begin{frame}{FREAK: Factoring RSA Export Keys} + \begin{itemize}[<+->] + \item \textbf{Export-grade cryptography legacy}: + \begin{itemize} + \item 1990s US export restrictions required weak crypto + \item 512-bit RSA keys for international software + \item Restrictions lifted, but support remained in implementations + \end{itemize} + \item \textbf{FREAK attack flow}: + \begin{enumerate} + \item Client requests strong RSA key exchange + \item Attacker modifies ClientHello to request export-grade RSA + \item Server responds with 512-bit RSA parameters + \item Attacker factors 512-bit RSA key (8-10 hours) + \item Attacker can decrypt entire TLS session + \end{enumerate} + \item \textbf{Vulnerable systems}: 36.7\% of all browser-trusted sites + \item \textbf{Impact}: Complete compromise of TLS connections + \end{itemize} +\end{frame} + +\begin{frame}{When math was classified as weapons} + \begin{itemize}[<+->] + \item \textbf{US Export Administration Regulations (1970s-1990s)}: + \begin{itemize} + \item Cryptographic software classified as ``munitions'' + \item Same category as tanks, missiles, and fighter jets + \item Export required State Department license (like arms dealing!) + \end{itemize} + \item \textbf{The absurd reality}: + \begin{itemize} + \item Mathematical algorithms = weapons of war + \item Publishing crypto code = illegal arms export + \item Explaining RSA algorithm abroad = potential felony + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{When math was classified as weapons} + \begin{itemize}[<+->] + \item \textbf{Practical impact}: + \begin{itemize} + \item US software artificially weakened for international markets + \item 40-bit keys for ``export grade'' crypto (easily breakable) + \item Non-US developers gained competitive advantage + \end{itemize} + \item \textbf{The irony}: Trying to keep crypto weak made \textbf{everyone} less secure + \begin{itemize} + \item Dual-use problem: same algorithms protect banks and terrorists + \item Weak crypto created systemic vulnerabilities + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Bernstein v. United States} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{itemize}[<+->] + \item \textbf{Daniel J. Bernstein}: Graduate student at UC Berkeley (1990s) + \begin{itemize} + \item Developed ``Snuffle'' encryption algorithm + \item Wanted to publish academic paper and source code + \item Government: ``That's illegal arms export!'' + \end{itemize} + \item \textbf{The lawsuit}: Bernstein v. United States (1995-2003) + \begin{itemize} + \item Argued cryptographic code is protected speech + \item First Amendment covers mathematical expressions + \item Government can't censor academic research + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.3\textwidth} + \imagewithcaption{djb.jpg}{Daniel J. Bernstein} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Bernstein v. United States} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{itemize}[<+->] + \item \textbf{Key victories}: + \begin{itemize} + \item 1996: Court rules source code is speech + \item 1999: 9th Circuit affirms First Amendment protection + \item Export controls on publicly available crypto unconstitutional + \end{itemize} + \item \textbf{Legacy}: Opened floodgates for strong cryptography + \begin{itemize} + \item TLS, HTTPS, modern secure communications + \item Academic freedom in cryptographic research + \item Foundation for today's digital security + \end{itemize} + \item \textbf{Fun fact}: Bernstein later created Curve25519 (used in TLS 1.3!) + \end{itemize} + \end{column} + \begin{column}{0.3\textwidth} + \imagewithcaption{djb.jpg}{Daniel J. Bernstein} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{``The Crypto Wars''} + \begin{columns}[c] + \begin{column}{0.33\textwidth} + \imagewithcaption{export_1.jpg}{RSA tattoo} + \end{column} + \begin{column}{0.33\textwidth} + \imagewithcaption{export_2.jpg}{RSA t-shirt} + \end{column} + \begin{column}{0.33\textwidth} + \imagewithcaption{export_3.jpg}{Netscape ``not for export'' floppy} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{FREAK} + \bigimagewithcaption{tls_freak.png}{} +\end{frame} + +\begin{frame}{SMACK: Real vulnerabilities found} + \begin{itemize}[<+->] + \item \textbf{miTLS vs. OpenSSL}: + \begin{itemize} + \item Attacker can skip client authentication + \item Exploit differences in certificate validation + \end{itemize} + \item \textbf{NSS (Firefox) vulnerabilities}: + \begin{itemize} + \item Early application data acceptance + \item Certificate validation bypass + \end{itemize} + \item \textbf{Java JSSE attacks}: + \begin{itemize} + \item Premature transition to application data + \item Authentication bypass in specific configurations + \end{itemize} + \item \textbf{The root cause}: Complex state machines without formal verification + \item \textbf{Solution approach}: Model checking and formal verification + \begin{itemize} + \item Systematically test all possible message sequences + \item Verify implementations match specifications + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Logjam: When Diffie-Hellman goes wrong (2015)} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Research team}: 14 researchers from 10 institutions\footnote{\url{https://appliedcryptography.page/papers/imperfect-dh.pdf}} + \item \textbf{Target}: Diffie-Hellman key exchange in TLS + \item \textbf{Two main attacks}: + \begin{itemize} + \item \textbf{Logjam}: Downgrade to weak 512-bit DH groups + \item \textbf{Precomputation}: Break commonly used 1024-bit groups + \end{itemize} + \item \textbf{Context}: 1990s US export restrictions on cryptography + \begin{itemize} + \item ``Export-grade'' crypto limited to weak parameters + \item Legacy support for 512-bit DH groups remained + \end{itemize} + \item \textbf{Fundamental question}: Can we still break today's crypto by exploiting legacy weak parameters? + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Logjam: The downgrade attack} + \begin{itemize}[<+->] + \item \textbf{Attack flow}: + \begin{enumerate} + \item Client offers strong DH groups (2048-bit) + \item Attacker modifies ClientHello to request weak DH (512-bit) + \item Server responds with 512-bit DH parameters + \item Attacker breaks 512-bit DH in real-time + \item Attacker can now decrypt entire session + \end{enumerate} + \item \textbf{Breaking 512-bit DH}: + \begin{itemize} + \item Academic cluster: 7 minutes + \item Amazon EC2: under \$100 per connection + \item NSA-level resources: near real-time + \end{itemize} + \item \textbf{Vulnerable servers}: 8.4\% of top 1 million HTTPS sites + \item \textbf{The irony}: Export restrictions from 1990s still creating vulnerabilities in 2015 + \end{itemize} +\end{frame} + +\begin{frame}{Logjam: The downgrade attack} + \bigimagewithcaption{logjam_2.png}{} +\end{frame} + +\begin{frame}{Logjam: Precomputation attacks on 1024-bit groups} + \begin{itemize}[<+->] + \item \textbf{The number field sieve algorithm}: + \begin{itemize} + \item Most efficient known algorithm for breaking DH + \item Has expensive precomputation phase + \item Once precomputation is done, individual logs are cheaper + \end{itemize} + \item \textbf{Attack economics}: + \begin{itemize} + \item Precomputation for 1024-bit group: several months, millions of dollars + \item Individual discrete logs: 30 seconds + \item Amortized cost: profitable for high-value targets + \end{itemize} + \item \textbf{Widespread vulnerability}: + \begin{itemize} + \item 18\% of top 1M HTTPS sites use single 1024-bit group + \item 66\% of VPN servers use same group + \item 26\% of SSH servers use same group + \end{itemize} + \item \textbf{NSA implications}: Could explain some of NSA's cryptanalytic capabilities + \end{itemize} +\end{frame} + +\begin{frame}{Logjam: Precomputation attacks on 1024-bit groups} + \bigimagewithcaption{logjam_1.png}{} +\end{frame} + +\begin{frame}{Logjam: The ``well-known groups'' problem} + \begin{itemize}[<+->] + \item \textbf{Common practice}: Everyone uses the same DH parameters + \begin{itemize} + \item RFC 5114 specifies ``standard'' groups + \item Apache mod\_ssl ships with default parameters + \item Easier than generating custom parameters + \end{itemize} + \item \textbf{Concentration risk}: + \begin{itemize} + \item Breaking one group breaks many servers + \item Amortizes the cost of precomputation + \item Creates attractive targets for nation-state actors + \end{itemize} + \item \textbf{Timeline for 1024-bit groups}: + \begin{itemize} + \item 2015: Academic resources could break with significant effort + \item 2020: Within reach of well-funded adversaries + \item 2025: Potentially routine for state actors + \end{itemize} + \item \textbf{Recommendation}: Move to 2048-bit DH or elliptic curves + \end{itemize} +\end{frame} + +\begin{frame}{Logjam: Intelligence services exploit these issues!} + \bigimagewithcaption{logjam_3.png}{} +\end{frame} + +\begin{frame}{Logjam: Countermeasures and lessons} + \begin{itemize}[<+->] + \item \textbf{Immediate fixes}: + \begin{itemize} + \item Disable export-grade DH entirely + \item Upgrade to 2048-bit or larger DH groups + \item Prefer elliptic curve Diffie-Hellman (ECDH) + \end{itemize} + \item \textbf{Browser responses}: + \begin{itemize} + \item Reject connections with weak DH parameters + \item Implement warnings for short DH keys + \end{itemize} + \item \textbf{Broader lessons}: + \begin{itemize} + \item Legacy cryptography creates long-term vulnerabilities + \item Export restrictions had lasting negative security impact + \item Centralized parameters create systemic risks + \item Need to plan for cryptographic algorithm transitions + \end{itemize} + \item \textbf{Policy implications}: Demonstrated real-world harm from crypto restrictions + \end{itemize} +\end{frame} + +\begin{frame}{SWEET32: Birthday attacks on 64-bit block ciphers (2016)} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Researchers}: Karthikeyan Bhargavan and Gaëtan Leurent (Inria)\footnote{\url{https://appliedcryptography.page/papers/inria-sweet32.pdf}} + \item \textbf{Target}: 64-bit block ciphers (3DES, Blowfish) + \item \textbf{Core vulnerability}: Birthday paradox in block cipher usage + \begin{itemize} + \item 64-bit blocks $\rightarrow$ $2^{32}$ blocks before collisions + \item Long-lived TLS connections can encrypt that much data + \item Collision reveals information about plaintext + \end{itemize} + \item \textbf{Attack name}: \textbf{SWEET32} - birthday attacks on block ciphers + \item \textbf{Practical scenario}: HTTPS connections sending repetitive data + \begin{itemize} + \item JavaScript making repeated AJAX requests + \item Cookies or authentication tokens repeated in each request + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{SWEET32: The birthday attack mechanics} + \begin{itemize}[<+->] + \item \textbf{Birthday paradox}: + \begin{itemize} + \item For $n$-bit blocks, expect collision after $2^{n/2}$ blocks + \item 64-bit blocks: collision after $2^{32} = 4$ billion blocks + \item At 1 Mbps: 9 hours, at 10 Mbps: 1 hour + \end{itemize} + \item \textbf{Collision exploitation}: + \begin{itemize} + \item When same plaintext block encrypted twice → same ciphertext + \item Attacker identifies when collision occurs + \item Can deduce relationships between plaintext blocks + \end{itemize} + \item \textbf{Attack requirements}: + \begin{itemize} + \item Long-lived TLS connection + \item Ability to generate traffic (malicious JavaScript) + \item Repetitive plaintext content (cookies, tokens) + \end{itemize} + \item \textbf{Proof of concept}: Extracted HTTP cookies in 30 hours + \end{itemize} +\end{frame} + +\begin{frame}{SWEET32: Real-world impact and remediation} + \begin{itemize}[<+->] + \item \textbf{Vulnerable systems}: + \begin{itemize} + \item Legacy systems still using 3DES + \item Some VPN implementations + \item Older TLS configurations + \end{itemize} + \item \textbf{Attack limitations}: + \begin{itemize} + \item Requires very long connections + \item Needs repetitive plaintext patterns + \item Success rate depends on traffic patterns + \end{itemize} + \item \textbf{Countermeasures}: + \begin{itemize} + \item Migrate to 128-bit block ciphers (AES) + \item Implement connection limits (rekeying) + \item Disable 3DES in TLS configurations + \end{itemize} + \item \textbf{Browser responses}: Disabled 3DES by default + \item \textbf{Lesson}: Even ``theoretical'' attacks can become practical + \end{itemize} +\end{frame} + +\begin{frame}{Transcript Collision Attacks (2016)} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{Researchers}: Karthikeyan Bhargavan and Gaëtan Leurent (Inria)\footnote{\url{https://appliedcryptography.page/papers/inria-collisions.pdf}} + \item \textbf{Novel attack class}: Hash collision attacks on protocol transcripts + \item \textbf{Core idea}: + \begin{itemize} + \item Protocols hash their message transcripts for integrity + \item Find two different transcripts with same hash + \item Substitute one transcript for another + \end{itemize} + \item \textbf{Targets}: TLS, IKE (IPsec), SSH + \item \textbf{Hash collision research}: Building on advances in MD5 and SHA-1 + \begin{itemize} + \item Google's SHA-1 collision (SHAttered) published in 2017 + \item But collision attacks were becoming practical by 2016 + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Transcript Collision} + \bigimagewithcaption{tls_collision.png}{} +\end{frame} + +\begin{frame}{Transcript Collision: Attack on TLS} + \begin{itemize}[<+->] + \item \textbf{TLS transcript hashing}: + \begin{itemize} + \item TLS computes hash of all handshake messages + \item Used in Finished message for integrity verification + \item Older TLS versions used MD5 and SHA-1 + \end{itemize} + \item \textbf{Attack scenario}: + \begin{enumerate} + \item Attacker finds two handshake transcripts with same hash + \item First transcript: legitimate client-server handshake + \item Second transcript: attacker's malicious handshake + \item Attacker substitutes malicious transcript + \end{enumerate} + \item \textbf{Consequences}: + \begin{itemize} + \item Bypass authentication checks + \item Downgrade security parameters + \item Inject malicious content + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Transcript Collision: Cross-protocol attacks} + \begin{itemize}[<+->] + \item \textbf{Cross-protocol confusion}: + \begin{itemize} + \item Same hash function used in multiple protocols + \item IKE and TLS both use SHA-1 for transcript hashing + \item Attacker crafts messages that are valid in both protocols + \end{itemize} + \item \textbf{Attack example}: + \begin{itemize} + \item Client connects to TLS server + \item Attacker substitutes IKE handshake with same hash + \item Client's TLS stack processes IKE messages + \item Potential for memory corruption or bypass + \end{itemize} + \item \textbf{Mitigation strategies}: + \begin{itemize} + \item Use strong hash functions (SHA-256,SHA-384) + \item Protocol-specific message formats + \item Separate hash contexts for different protocols + \end{itemize} + \item \textbf{Lesson}: Hash collisions threaten more than just digital signatures + \end{itemize} +\end{frame} + +\begin{frame}{Qualys SSL Labs} + \begin{itemize} + \item Free online service to analyze TLS/SSL configuration. + \item Tests any public HTTPS server. + \item Provides detailed security assessment. + \item Available at: \url{https://www.ssllabs.com/ssltest/} + \end{itemize} +\end{frame} + +\section{How TLS 1.3 Transformed Protocol Design} + +\begin{frame}{TLS 1.3: The great cleanup} + \begin{itemize}[<+->] + \item \textbf{Problem}: TLS 1.2 inherited decades of legacy features. + \begin{itemize} + \item Suboptimal security and performance. + \item Complex and error-prone configurations. + \item High risk of implementation bugs. + \end{itemize} + \item \textbf{Solution}: Complete redesign for TLS 1.3. + \begin{itemize} + \item Kept only the good parts. + \item Added modern security features. + \item Simplified the bloated design. + \end{itemize} + \item \textbf{Result}: TLS 1.3 is more secure, efficient, and simpler. + \item TLS 1.3 = ``mature TLS''. + \end{itemize} +\end{frame} + +\begin{frame}{TLS 1.3: Learning from TLS 1.2's mistakes} + \begin{itemize}[<+->] + \item \textbf{TLS 1.2's legacy problem}: + \begin{itemize} + \item Decades of accumulated features and algorithms + \item Many insecure options still supported for compatibility + \item Complex configurations prone to errors + \end{itemize} + \item \textbf{TLS 1.3's philosophy}: \textbf{Remove everything dangerous} + \begin{itemize} + \item If it's been broken, remove it + \item If it's complex and error-prone, simplify it + \item If it's not needed, delete it + \end{itemize} + \item \textbf{Result}: A much cleaner, more secure protocol + \end{itemize} +\end{frame} + +\begin{frame}{TLS 1.3: Algorithmic spring cleaning} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{TLS 1.2 supported:} + \begin{itemize}[<+->] + \item MD5 (broken) + \item SHA-1 (broken) + \item RC4 (broken) + \item AES-CBC (padding oracles) + \item MAC-then-encrypt + \item Various weak ciphers + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{TLS 1.3 only allows:} + \begin{itemize}[<+->] + \item Strong hash functions only + \item Authenticated encryption + \item Modern, secure algorithms + \item No legacy cruft + \end{itemize} + \end{column} + \end{columns} + \pause + \begin{center} + \textbf{Philosophy}: ``If you can configure it wrong, remove the option!'' + \end{center} +\end{frame} + +\begin{frame}{Authenticated encryption: No more MAC-then-encrypt} + \begin{itemize}[<+->] + \item \textbf{TLS 1.2 approach}: MAC-then-encrypt + \begin{itemize} + \item Compute MAC over plaintext + \item Encrypt (plaintext + MAC) + \item Vulnerable to padding oracle attacks + \end{itemize} + \item \textbf{TLS 1.3 approach}: Authenticated encryption only + \begin{itemize} + \item AES-GCM, ChaCha20-Poly1305 + \item Encryption and authentication in one step + \item No padding oracle vulnerabilities + \end{itemize} + \item \textbf{Benefits}: + \begin{itemize} + \item More efficient (one cryptographic operation) + \item More secure (no composition attacks) + \item Simpler implementation + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Supported cryptographic algorithms} + \begin{itemize}[<+->] + \item \textbf{Authenticated Encryption} (only 3 algorithms): + \begin{itemize} + \item AES-GCM (128-bit or 256-bit keys) + \item AES-CCM (128-bit keys, slightly less efficient than GCM) + \item ChaCha20-Poly1305 (256-bit keys, from RFC 7539) + \end{itemize} + \item \textbf{Key Derivation Function (KDF)}: + \begin{itemize} + \item HKDF construction based on HMAC (RFC 5869) + \item Uses SHA-256 or SHA-384 hash functions + \end{itemize} + \item \textbf{Diffie-Hellman Key Exchange}: + \begin{itemize} + \item \textbf{Elliptic Curves}: 3 NIST curves + Curve25519 + Curve448 + \item \textbf{Integer Groups}: 2,048, 3,072, 4,096, 6,144, 8,192 bits (RFC 7919) + \end{itemize} + \item \textbf{Security note}: 2,048-bit DH provides $<$100-bit security + \begin{itemize} + \item Inconsistent with other 128-bit security choices + \item Still practically impossible to break + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{TLS 1.3 extensions and variations} + \begin{itemize}[<+->] + \item \textbf{TLS 1.3 supports many options}: + \begin{itemize} + \item Client certificate authentication + \item Preshared key handshakes + \item Various extensions for specific needs + \end{itemize} + \item \textbf{Client certificate authentication}: + \begin{itemize} + \item Server can require client to prove its identity + \item Mutual authentication (both parties verified) + \item Common in enterprise environments + \end{itemize} + \item \textbf{Preshared keys (PSK)}: + \begin{itemize} + \item Skip certificate verification + \item Use pre-established shared secrets + \item Faster handshake, but requires prior key distribution + \end{itemize} + \item \textbf{Flexibility}: TLS 1.3 adapts to different security requirements. + \end{itemize} +\end{frame} + +\begin{frame}{TLS 1.3: formal verification during the design phase} + \begin{itemize}[<+->] + \item \textbf{Revolutionary approach}: Protocol design meets formal methods + \begin{itemize} + \item Traditional approach: Design protocol \rightarrow\ implement \rightarrow\ find bugs \rightarrow\ patch + \item TLS 1.3 approach: Design protocol \rightarrow\ prove correctness \rightarrow\ implement + \end{itemize} + \item \textbf{Formal verification}: Mathematical proofs of security properties + \begin{itemize} + \item Prove protocol satisfies security requirements + \item Eliminate entire classes of implementation bugs + \item Higher confidence in security guarantees + \end{itemize} + \item \textbf{Industry-academia collaboration}: + \begin{itemize} + \item Inria's Prosecco team (France) + \item Microsoft Research Cambridge (Project Everest) + \item Direct input into IETF standardization process + \end{itemize} + \item \textbf{Result}: First cryptographic protocol with machine-checked security proofs \textit{as it was being designed!} + \end{itemize} +\end{frame} + +\begin{frame}{Inria Prosecco: Proving TLS 1.3 security} + \begin{itemize}[<+->] + \item \textbf{Team Prosecco} (Programming securely with cryptography): + \begin{itemize} + \item Led by Karthikeyan Bhargavan at Inria Paris + \item World-leading experts in cryptographic protocol analysis + \end{itemize} + \item \textbf{Key contributions to TLS 1.3}: + \begin{itemize} + \item Formal models of the handshake protocol + \item Machine-checked proofs of key security properties + \item Discovery and prevention of potential attacks + \end{itemize} + \item \textbf{Tools and methods}: + \begin{itemize} + \item ProVerif: Automated protocol verification tool + \item Symbolic analysis of cryptographic protocols + \item Found subtle issues before standardization + \end{itemize} + \item \textbf{Impact}: Security flaws caught during design, not after deployment + \end{itemize} +\end{frame} + +\begin{frame}{Project Everest: Verified cryptographic implementations} + \begin{itemize}[<+->] + \item \textbf{Project Everest}: Microsoft Research Cambridge initiative + \begin{itemize} + \item Goal: Provably secure, high-performance cryptographic code + \item From high-level specifications to assembly language + \end{itemize} + \item \textbf{\fstar programming language}: + \begin{itemize} + \item Functional language with dependent types + \item Enables specification and verification of code properties + \item Compiles to efficient C code + \end{itemize} + \item \textbf{\haclstar cryptographic library}: + \begin{itemize} + \item Verified implementations of crypto primitives + \item ChaCha20, Poly1305, Curve25519, etc. + \item Mathematical proofs of correctness and security + \end{itemize} + \item \textbf{miTLS}: Verified TLS implementation + \begin{itemize} + \item Reference implementation with security proofs + \item Demonstrates that formal verification scales to real protocols + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{ProVerif: Automated protocol verification} + \begin{itemize}[<+->] + \item \textbf{What is ProVerif?} + \begin{itemize} + \item Automated tool for analyzing cryptographic protocols. + \begin{itemize} + \item \url{https://proverif.inria.fr} + \end{itemize} + \item Developed by Bruno Blanchet at Inria Paris. + \item Uses symbolic model of cryptography. + \end{itemize} + \item \textbf{How ProVerif works}: + \begin{itemize} + \item Protocol modeled in applied pi-calculus. + \item Automated search for attacks and proofs. + \item Handles unbounded number of protocol sessions. + \end{itemize} + \item \textbf{TLS 1.3 verification with ProVerif}: + \begin{itemize} + \item Modeled complete TLS 1.3 handshake protocol. + \item Proved secrecy of session keys. + \item Proved forward secrecy properties. + \item Found potential attacks on early draft versions. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{\fstar: Functional programming with verification} + \begin{itemize}[<+->] + \item \textbf{What is \fstar?} + \begin{itemize} + \item Functional programming language with dependent types. + \item Developed by Microsoft Research and Inria. + \item Enables specification and proof of program properties. + \end{itemize} + \item \textbf{\fstar key features}: + \begin{itemize} + \item Static type system catches bugs at compile-time. + \item Can express and verify complex security properties. + \item Compiles to efficient C code via KreMLin compiler. + \end{itemize} + \item \textbf{TLS 1.3 implementation in \fstar}: + \begin{itemize} + \item \textbf{miTLS}: Complete TLS 1.3 stack with proofs. + \item \textbf{\haclstar}: Verified crypto library (ChaCha20, Poly1305, Curve25519). + \item \textbf{EverCrypt}: Agile crypto provider with algorithm selection. + \end{itemize} + \item \textbf{Real-world impact}: + \begin{itemize} + \item \haclstar integrated into Firefox, Python, Linux kernel. + \item Proves that verified code can be practical and fast. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Formal verification benefits for TLS 1.3} + \begin{itemize}[<+->] + \item \textbf{Design-time bug prevention}: + \begin{itemize} + \item Subtle protocol flaws caught before standardization. + \item Avoided costly post-deployment patches. + \item Higher confidence in initial design. + \end{itemize} + \item \textbf{Implementation guidance}: + \begin{itemize} + \item Formal specifications guide implementers. + \item Clear mathematical definitions of security properties. + \item Reduced ambiguity in standard documents. + \end{itemize} + \item \textbf{Security assurance}: + \begin{itemize} + \item Mathematical proofs complement traditional security analysis. + \item Machine-checked proofs eliminate human error. + \item Covers complex interaction between protocol components. + \end{itemize} + \item \textbf{Industry adoption}: + \begin{itemize} + \item \haclstar used in Firefox, Linux kernel. + \item Proves formal methods can produce practical code. + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Removing dangerous features: The CRIME attack example} + \begin{itemize}[<+->] + \item \textbf{TLS 1.2 feature}: Optional data compression + \begin{itemize} + \item Reduces bandwidth usage + \item Seemed like a good idea... + \end{itemize} + \item \textbf{The CRIME attack}: Compression leaks information + \begin{itemize} + \item Compressed length reveals patterns in plaintext + \item Attackers can inject data and observe compression ratios + \item Can extract secrets like authentication cookies + \end{itemize} + \item \textbf{TLS 1.3 solution}: Remove compression entirely + \begin{itemize} + \item No compression = no compression-based attacks + \item Security over efficiency + \end{itemize} + \item \textbf{Lesson}: Features that seem helpful can create vulnerabilities + \end{itemize} +\end{frame} + +\begin{frame}{Zero padding: Defeating traffic analysis} + \begin{itemize}[<+->] + \item \textbf{Traffic analysis attack}: + \begin{itemize} + \item Attackers observe encrypted traffic patterns. + \item Extract info from timing, message sizes, etc. + \item Ciphertext size ≈ plaintext size (reveals message length). + \end{itemize} + \item \textbf{TLS 1.3 solution}: Zero padding + \begin{itemize} + \item Add zeros to plaintext before encryption. + \item Inflates ciphertext size. + \item Hides true message length from observers. + \end{itemize} + \item \textbf{Example}: 100-byte message + 900 zero bytes = looks like 1000-byte message. + \end{itemize} +\end{frame} + +\begin{frame}{Downgrade protection: Preventing version rollback} + \begin{itemize}[<+->] + \item \textbf{Downgrade attack scenario}: + \begin{enumerate} + \item Client sends ClientHello supporting TLS 1.3 + \item Attacker modifies message to claim only TLS 1.2 support + \item Server responds with weaker TLS 1.2 connection + \item Attacker exploits TLS 1.2 vulnerabilities + \end{enumerate} + \item \textbf{TLS 1.3 defense}: Magic values in server random + \begin{itemize} + \item Server encodes connection type in first 8 bytes of random value + \item TLS 1.2: \texttt{44 4F 57 4E 47 52 44 01} + \item TLS 1.1: \texttt{44 4F 57 4E 47 52 44 00} + \item TLS 1.3: Random bytes (no pattern) + \end{itemize} + \item \textbf{Attack detection}: Client sees wrong pattern \rightarrow\ knows it's under attack! + \end{itemize} +\end{frame} + +\begin{frame}{The magic downgrade detection values} + \begin{center} + \textbf{What do those hex values spell?} + \end{center} + \pause + \begin{center} + \texttt{44 4F 57 4E 47 52 44 01} = ``\textbf{DOWNGRD}\textbackslash x01''\\ + \texttt{44 4F 57 4E 47 52 44 00} = ``\textbf{DOWNGRD}\textbackslash x00'' + \end{center} + \pause + \begin{itemize}[<+->] + \item \textbf{Clever engineering}: Human-readable sentinel values + \item \textbf{Easy debugging}: Hex dumps show ``DOWNGRD'' string + \item \textbf{Security through visibility}: Makes downgrade attempts obvious + \item \textbf{Cryptographic protection}: Random value is signed by server + \begin{itemize} + \item Attacker can't modify it without breaking signature + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Performance boost: Single round-trip handshake} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{TLS 1.2 handshake:} + \begin{itemize}[<+->] + \item Client \rightarrow\ Server: ClientHello + \item Client \leftarrow\ Server: ServerHello + Certificate + \item Client \rightarrow\ Server: Key exchange + \item Client \leftarrow\ Server: Finished + \item \textbf{2 round trips} before encrypted data + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{TLS 1.3 handshake:} + \begin{itemize}[<+->] + \item Client \rightarrow\ Server: ClientHello + Key exchange + \item Client \leftarrow\ Server: ServerHello + Certificate + Finished + \item \textbf{1 round trip} before encrypted data + \end{itemize} + \end{column} + \end{columns} + \pause + \begin{center} + \textbf{Performance impact}: Hundreds of milliseconds saved per connection + \end{center} +\end{frame} + +\begin{frame}{Why single round-trip matters} + \begin{itemize}[<+->] + \item \textbf{Real-world impact}: + \begin{itemize} + \item High-traffic servers: thousands of connections per second + \item Mobile networks: high latency connections + \item User experience: faster page loads + \end{itemize} + \item \textbf{Latency examples}: + \begin{itemize} + \item Local network: 1ms \rightarrow\ savings minimal + \item Cross-country: 50ms \rightarrow\ saves 50ms per connection + \item Satellite internet: 500ms \rightarrow\ saves 500ms per connection! + \end{itemize} + \item \textbf{Efficiency gain}: Client sends DH key exchange immediately + \begin{itemize} + \item No waiting for server's algorithm selection + \item Client predicts what server will choose + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Session resumption: Even faster connections} + \begin{itemize}[<+->] + \item \textbf{The idea}: Reuse keys from previous connections + \begin{itemize} + \item Client and server remember shared \textbf{preshared key (PSK)} + \item Skip certificate validation in subsequent connections + \item Combine PSK with fresh Diffie-Hellman exchange + \end{itemize} + \item \textbf{Security benefits}: + \begin{itemize} + \item Forward secrecy maintained (fresh DH keys) + \item Authentication via MAC instead of certificates + \end{itemize} + \item \textbf{Performance benefits}: + \begin{itemize} + \item Faster handshake + \item Less CPU usage (no certificate operations) + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{0-RTT} + \begin{itemize}[<+->] + \item \textbf{Zero Round-Trip Time (0-RTT)}: + \begin{itemize} + \item Client sends encrypted data in \textbf{first message} + \item No waiting for server response + \item Uses PSK from previous session + \end{itemize} + \item \textbf{Process}: + \begin{enumerate} + \item Client: ClientHello + PSK + DH key + \textbf{encrypted data} + \item Server: Processes everything, responds with MAC + \item Client: Verifies MAC, knows it's talking to right server + \end{enumerate} + \item \textbf{Performance impact}: Eliminates connection setup delay entirely + \item \textbf{Use case}: Perfect for frequently-visited websites + \end{itemize} +\end{frame} + +\begin{frame}{0-RTT security considerations} + \begin{itemize}[<+->] + \item \textbf{Replay attack vulnerability}: + \begin{itemize} + \item Attacker records 0-RTT data packet + \item Replays it to server later + \item Server can't distinguish replay from legitimate connection + \begin{itemize} + \item You can probably formally prove that this problem can't be completely solved without a round trip + \end{itemize} + \end{itemize} + \item \textbf{Mitigation strategies}: + \begin{itemize} + \item Server remembers recent 0-RTT messages + \item Applications design requests to be replay-safe + \item Don't use 0-RTT for sensitive operations + \end{itemize} + \item \textbf{Trade-off}: Performance vs. replay protection + \begin{itemize} + \item Perfect for browsing, reading content + \item Dangerous for payments, account changes + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{TLS 1.3: Summary of improvements} + \begin{itemize}[<+->] + \item \textbf{Security improvements}: + \begin{itemize} + \item Removed all weak algorithms and dangerous features + \item Authenticated encryption only + \item Downgrade protection + \end{itemize} + \item \textbf{Performance improvements}: + \begin{itemize} + \item Single round-trip handshake + \item Session resumption with PSK + \item 0-RTT for repeat connections + \end{itemize} + \item \textbf{Simplicity improvements}: + \begin{itemize} + \item Fewer configuration options + \item Standardized elliptic curve formats + \item Cleaner protocol design + \end{itemize} + \item \textbf{Result}: More secure, faster, and easier to implement correctly + \end{itemize} +\end{frame} + +\begin{frame}{The future of protocol design} + \begin{itemize}[<+->] + \item \textbf{TLS 1.3 as a model}: + \begin{itemize} + \item First major protocol with end-to-end formal verification + \item Demonstrates feasibility of formal methods at scale + \item Sets new standard for protocol security assurance + \end{itemize} + \item \textbf{Expanding to other protocols}: + \begin{itemize} + \item Signal Protocol (secure messaging) + \item WireGuard VPN protocol + \item Post-quantum cryptographic protocols + \end{itemize} + \item \textbf{Challenges ahead}: + \begin{itemize} + \item Scaling formal methods to larger, more complex protocols + \item Training developers in formal verification techniques + \item Balancing mathematical rigor with practical engineering + \end{itemize} + \item \textbf{Vision}: All security-critical protocols designed with formal verification + \begin{itemize} + \item Higher security guarantees for everyone + \item Fewer catastrophic vulnerabilities + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-10.tex b/slides/2-10.tex new file mode 100644 index 0000000..662a495 --- /dev/null +++ b/slides/2-10.tex @@ -0,0 +1,28 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.10: Creative Cryptography} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Slides not complete and may contain errors} + \begin{itemize} + \item This slide deck is not finished, may contain errors, and is missing important material. Do not rely on it yet. + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-2.tex b/slides/2-2.tex new file mode 100644 index 0000000..54836f9 --- /dev/null +++ b/slides/2-2.tex @@ -0,0 +1,974 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.2: The Story of RC4} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\section{About RC4} + +\begin{frame}{The Rise and Fall of RC4} + \begin{itemize}[<+->] + \item A cryptographic tale of triumph and tragedy + \begin{itemize}[<+->] + \item \textbf{Birth (1987):} Proprietary stream cipher at RSA Security + \item \textbf{Rise (1990s):} Became the world's most widely deployed stream cipher + \item \textbf{Golden Era (2000s):} Powered WEP, SSL, and TLS protocols globally + \item \textbf{Decline (2001-2015):} A series of devastating cryptanalytic breakthroughs + \item \textbf{Demise (2015):} Formal prohibition by IETF, browser vendors + \end{itemize} + \item This story teaches us about cryptographic lifecycle management, the importance of formal security analysis, and the challenges of maintaining backward compatibility + \end{itemize} +\end{frame} + +\begin{frame}{What is RC4?} + \begin{itemize}[<+->] + \item \textbf{RC4} (Rivest Cipher 4) is a stream cipher designed for speed and simplicity + \begin{itemize}[<+->] + \item \textbf{Stream cipher:} Encrypts data one byte at a time + \item \textbf{Variable key length:} Supports keys from 1 to 256 bytes + \item \textbf{Symmetric encryption:} Same key used for encryption and decryption + \end{itemize} + \item Key characteristics that made it popular: + \begin{itemize}[<+->] + \item Extremely fast in software (no complex operations) + \item Small memory footprint (only 256 bytes of state) + \item Simple implementation (just a few lines of code) + \end{itemize} + \item Used extensively in protocols like WEP (Wi-Fi), SSL/TLS, and SSH + \end{itemize} +\end{frame} + +\begin{frame}{Origins of RC4} + \begin{itemize}[<+->] + \item \textbf{1987:} Ron Rivest designs RC4 at RSA Security + \begin{itemize}[<+->] + \item Originally a trade secret, not published + \item ``RC'' stands for ``Ron's Code'' or ``Rivest Cipher'' + \item Designed for practical applications requiring fast encryption + \end{itemize} + \item \textbf{1994:} Algorithm anonymously posted to Cypherpunks mailing list + \begin{itemize}[<+->] + \item Source code leaked, breaking RSA's trade secret + \item Called ``Alleged RC4'' or ``ARCFOUR'' due to legal concerns + \item Quickly reverse-engineered and verified as authentic + \end{itemize} + \item \textbf{Impact of the leak:} + \begin{itemize}[<+->] + \item Made RC4 freely available to implementers worldwide + \item Led to its widespread adoption in internet protocols + \item Ironically helped RSA by making their cipher ubiquitous + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{RC4's Key Scheduling Algorithm (KSA)} + \begin{itemize}[<+->] + \item \textbf{Step 1:} Initialize the state array S with values 0 through 255 + \begin{itemize}[<+->] + \item \texttt{for i = 0 to 255: S[i] = i} + \end{itemize} + \item \textbf{Step 2:} Scramble the state array using the key + \begin{itemize}[<+->] + \item \texttt{j = 0} + \item \texttt{for i = 0 to 255:} + \item \texttt{\quad j = (j + S[i] + key[i mod keylength]) mod 256} + \item \texttt{\quad swap(S[i], S[j])} + \end{itemize} + \item \textbf{Purpose:} Create a pseudo-random permutation of 0-255 based on the key + \item The quality of this initial scrambling is crucial for security + \end{itemize} +\end{frame} + +\begin{frame}{$\mathsf{PRP}: F_{k}= X \rightarrow X$}{Reminder} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item \textbf{Bijective} (two-way) + \begin{itemize} + \item \textbf{Injective}: no two inputs map to same output (no + collisions) + \item \textbf{Surjective}: Every output has one corresponding input + \end{itemize} + \item ``Randomized'' + \item Relations between inputs not reflected in outputs + \end{itemize} + \end{column} + + \begin{column}{0.8\textwidth} + \begin{tikzpicture}[scale=0.38] + % Define colors + \definecolor{domaingreen}{RGB}{102, 170, 68} + \definecolor{rangegreen}{RGB}{102, 170, 68} + \definecolor{circlecolor}{RGB}{235, 137, 85} + \definecolor{purplearrow}{RGB}{160, 78, 160} + + % Input space (domain) X - made square + \draw[dashed, thick, domaingreen, fill=domaingreen] + (0,0) rectangle (8,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (4,-0.8) + {Size: fixed}; + \node[font=\normalsize] at (4,9) {Input space (domain) $X$}; + + % Output (range) Y - made square, same size as domain, moved left + \draw[thick, rangegreen, fill=rangegreen] (12,0) rectangle (20,8); + \node[text width=6.5cm, align=center, font=\normalsize] + at + (16,-0.8) + {Size: fixed}; + \node[font=\normalsize] at (16,9) {Output (range) $X$}; + % Input dots - adjusted positions for square domain + \filldraw[circlecolor] (2,7) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,7) -- (14.2,7.4); + \pause + \filldraw[circlecolor] (14.2,7.4) circle (0.3); + \pause + + \filldraw[circlecolor] (3,6) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,6) -- (18.6,5.3); + \pause + \filldraw[circlecolor] (18.6,5.3) circle (0.3); + \pause + + \filldraw[circlecolor] (2,5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,5) -- (13.8,4.2); + \pause + \filldraw[circlecolor] (13.8,4.2) circle (0.3); + \pause + + \filldraw[circlecolor] (4,3.5) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (4,3.5) -- (17.4,2.2); + \pause + \filldraw[circlecolor] (17.4,2.2) circle (0.3); + \pause + + \filldraw[circlecolor] (2,2) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (2,2) -- (16.1,6.7); + \pause + \filldraw[circlecolor] (16.1,6.7) circle (0.3); + \pause + + \filldraw[circlecolor] (3,1) circle (0.3); + \pause + \draw[-{Stealth[length=6mm, width=4mm]}, thick, purplearrow] + (3,1) -- (19.0,1.4); + \pause + \filldraw[circlecolor] (19.0,1.4) circle (0.3); + \end{tikzpicture} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Limitations of One-Time Pad}{Reminder} + \definitionbox{The Key Length Problem}{ + One-time pad is not a particularly useful encryption scheme in practice. + } + \begin{itemize}[<+->] + \item The key must be as long as the plaintext! + \item This creates a chicken-and-egg situation: + \begin{itemize}[<+->] + \item To privately send $n$ bits of information, + \item We must already privately share $n$ bits of information. + \end{itemize} + \item Impractical for most real-world applications. + \begin{itemize}[<+->] + \item Clearly this is not what we're doing when we use HTTPS, + \item or WhatsApp, or pay for something via a debit card... + \end{itemize} + \item We need encryption schemes where the key can be smaller than the message. + \end{itemize} +\end{frame} + +\begin{frame}{Idea: find a way to expand the key}{Reminder} + \begin{itemize}[<+->] + \item Given a key $k_s$ of size $\left|k_s\right| < \left|m\right|$, find a way to obtain $\left|k_e\right| \geq \left|m\right|$ + \item In the real world, we have two kinds of symmetric encryption schemes: + \begin{itemize}[<+->] + \item \textbf{Block ciphers}: AES, 3DES, etc. + \item \textbf{Stream ciphers}: ChaCha20, RC4, etc. + \end{itemize} + \item This is exactly what stream ciphers do! + \begin{itemize}[<+->] + \item Start with a small key $k_s$ of a fixed size $\left|k_s\right| = \lambda$, + \item Magically expand it to $k_e$ where $\left|k_e\right| \geq \left|m\right|$, + \item $\func{enc}{K, M} = K \oplus M$ + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{RC4's Pseudo-Random Generation Algorithm (PRGA)} + \begin{itemize}[<+->] + \item \textbf{Initialization:} Set counters \texttt{i = 0, j = 0} + \item \textbf{For each byte to encrypt:} + \begin{itemize}[<+->] + \item \texttt{i = (i + 1) mod 256} + \item \texttt{j = (j + S[i]) mod 256} + \item \texttt{swap(S[i], S[j])} + \item \texttt{K = S[(S[i] + S[j]) mod 256]} \quad ← keystream byte + \item \texttt{ciphertext = plaintext XOR K} + \end{itemize} + \item \textbf{Key insight:} The state array S is continuously modified + \begin{itemize}[<+->] + \item Each keystream byte depends on the entire previous history + \item Creates a very long period before repetition + \end{itemize} + \item \textbf{Decryption:} Identical process (XOR is self-inverse) + \end{itemize} +\end{frame} + +\begin{frame}{RC4's golden age (1990s-2000s)} + \begin{itemize}[<+->] + \item \textbf{The most widely deployed stream cipher in history} + \begin{itemize}[<+->] + \item Estimated to secure over 50\% of all SSL/TLS connections at its peak + \item Billions of devices worldwide relied on RC4 for encryption + \end{itemize} + \item \textbf{Ubiquitous protocol adoption:} + \begin{itemize}[<+->] + \item \textbf{WEP (1997):} Wi-Fi security standard used RC4 exclusively + \item \textbf{SSL 3.0/TLS 1.0 (1995-1999):} RC4 as preferred cipher suite + \item \textbf{SSH-1 (1995):} Early secure shell implementations + \item \textbf{Microsoft Office:} Document password protection + \item \textbf{Adobe PDF:} File encryption standard + \end{itemize} + \item \textbf{Why RC4 dominated:} + \begin{itemize}[<+->] + \item 5-10x faster than DES in software implementations + \item Minimal memory requirements (perfect for embedded systems) + \item No export restrictions (unlike strong block ciphers) + \item Simple to implement correctly + \end{itemize} + \end{itemize} +\end{frame} + +\section{RSA in WEP} + +\begin{frame}{Early RC4 weaknesses (1995-2000)} + \begin{itemize}[<+->] + \item \textbf{1995:} First statistical biases discovered by Wagner and Goldberg + \begin{itemize}[<+->] + \item Found that the second byte of RC4 keystream was biased + \item Probability of being zero was $2/256$ instead of $1/256$ + \item Seemed like a minor curiosity at the time... + \end{itemize} + \item \textbf{1997:} Golic discovered more biases in the keystream + \begin{itemize}[<+->] + \item Certain byte positions showed statistical irregularities + \item Still considered mostly theoretical concerns + \end{itemize} + \item \textbf{2000:} Jenkins found patterns in RC4's internal state + \begin{itemize}[<+->] + \item Identified correlations between consecutive keystream bytes + \item Cryptographic community began to worry about RC4's security + \end{itemize} + \item \textbf{The stage was set} for a more devastating attack... + \end{itemize} +\end{frame} + +\begin{frame}{Weak keys in KSA} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{The Discovery:} Certain key patterns create predictable initial states\footnote{\url{https://appliedcryptography.page/papers/rc4-ksa.pdf}} + \item \textbf{Weak Key Pattern:} Keys of the form $(K_1, K_2, \ldots, K_n, 3, 255, \ldots)$ + \begin{itemize}[<+->] + \item When byte 3 of the key is 3, and byte 4 is 255 + \item The KSA creates a predictable correlation in the state array + \end{itemize} + \item \textbf{The Mathematics:} + \begin{itemize}[<+->] + \item After KSA completes, $S[1] = 3$ with high probability + \item In the first step of PRGA: $i = 1, j = S[1] = 3$ + \item First keystream byte: $S[S[1] + S[3]] = S[3 + S[3]]$ + \item This reveals information about the key! + \end{itemize} + \item \textbf{Frequency:} About 1 in 256 keys exhibit this weakness + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{One-time secrecy of a SKE}{Reminder} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \definitionbox{One-time Secrecy for SKE}{ + An SKE scheme $\Sigma$ has one-time secrecy if the following libraries are interchangeable: + \vspace{0.5mm} + \begin{center} + \sslinked{ + \sslibrary{\Sigma}{ots-real}{ + \sslibrarysubroutine{ots.enc}{M}{ + $K \twoheadleftarrow \Sigma.\mathcal{K}$ \\ + $C \coloneq \Sigma.\textsf{Enc}(K, M)$ \\ + return $C$ + }{1} + }{0.8} + }{\interchangeable{}}{ + \sslibrary{\Sigma}{ots-rand}{ + \sslibrarysubroutine{ots.enc}{M}{ + $C \twoheadleftarrow \Sigma.\mathcal{C}$ \\ + return $C$ + }{1} + }{0.8} + } + \end{center} + } + \end{column} + \begin{column}{0.5\textwidth} + An encryption scheme has one-time secrecy if its ciphertexts are uniformly distributed, when keys are sampled uniformly, kept secret, and used for only one encryption, and no matter how the plaintexts are chosen. + \\ + \textbf{Does this apply to RC4, especially after the attacks?} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Attacks mean distinguishability}{RC4 getting less and less ``indistinguishable from random''} + \begin{columns}[c] + \begin{column}{0.35\textwidth} + \sssubroutine{RC4Encrypt}{M}{ + $k \twoheadleftarrow \bits^{\lambda}$ \\ + $K \coloneq \texttt{RC4}(k, |M|)$ \\ + $C \coloneq K \oplus M$ \\ + return $C$ + }{1.5} + \end{column} + \begin{column}{0.3\textwidth} + \begin{center} + {\huge{$\cancel{\approxeq}$}} \\[1em] + \end{center} + \end{column} + \begin{column}{0.35\textwidth} + \sssubroutine{Random}{M}{ + $C \twoheadleftarrow \bits^{|M|}$ \\ + return $C$ + }{1.5} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{In fact...} + \bigimagewithcaption{rc4_bias.png}{Source: Kenny Paterson} +\end{frame} + +\begin{frame}{Attacks: from theory to practice} + \begin{itemize}[<+->] + \item \textbf{Step 1:} Collect many ciphertexts encrypted with related keys + \begin{itemize}[<+->] + \item Keys that differ only in the first few bytes + \item Wait for keys with the vulnerable pattern to appear + \end{itemize} + \item \textbf{Step 2:} Identify weak keys from keystream patterns + \begin{itemize}[<+->] + \item Look for the telltale signatures in the first keystream byte + \item Discard non-vulnerable encryptions + \end{itemize} + \item \textbf{Step 3:} Recover key bytes incrementally + \begin{itemize}[<+->] + \item Use the correlation to determine likely values for key bytes + \item Build up the key one byte at a time + \end{itemize} + \item \textbf{Success rate:} With enough samples, key recovery becomes highly reliable + \end{itemize} +\end{frame} + +\begin{frame}{How WEP encryption works} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{Components:} + \begin{itemize}[<+->] + \item 24-bit IV (Initialization Vector) + \item 104-bit PSK (pre-shared key) + \begin{itemize} + \item Derived from Wi-Fi password + \item Was limited to 40 bits at first due to US export controls! + \end{itemize} + \end{itemize} + \item \textbf{Process:} + \begin{itemize}[<+->] + \item Choose random IV for each packet + \item Concatenate: IV $\|$ Secret Key + \item Feed to RC4 to generate keystream + \item XOR plaintext with keystream + \end{itemize} + \end{itemize} + \begin{center} + \begin{tikzpicture}[scale=0.7] + % Transmitted packet + \draw[thick, dashed] (-0.5,-5) rectangle (7,-6); + \draw[thick, fill=blue!20] (0,-5.2) rectangle (2,-5.8); + \node at (1,-5.5) {IV}; + \draw[thick, fill=gray!20] (2.5,-5.2) rectangle (6.5,-5.8); + \node at (4.5,-5.5) {Ciphertext}; + \node[below] at (3.25,-6) {\small Transmitted Packet}; + \end{tikzpicture} + \end{center} + \end{column} + \begin{column}{0.5\textwidth} + \begin{center} + \begin{tikzpicture}[scale=0.7] + % IV Box + \draw[thick, fill=blue!20] (0,4) rectangle (2,5); + \node at (1,4.5) {IV}; + \node[below] at (1.7,3.8) {\tiny 24 bits}; + + % Secret Key Box + \draw[thick, fill=red!20] (2.5,4) rectangle (5.5,5); + \node at (4,4.5) {Secret Key}; + \node[below] at (5,3.8) {\tiny 104 bits}; + + % Concatenation + \draw[->, thick] (1,4) -- (1,3); + \draw[->, thick] (4,4) -- (4,3); + \draw[thick] (0.5,2.25) rectangle (4.5,3); + \node at (2.5,2.6) {IV $\|$ Key}; + + % RC4 Box + \draw[->, thick] (2.5,2.25) -- (2.5,1.5); + \draw[thick, fill=green!20] (1,0.5) rectangle (4,1.5); + \node at (2.5,1) {RC4}; + + % Keystream + \draw[->, thick] (2.5,0.5) -- (2.5,-0.5); + \node at (2.5,-0.8) {Keystream}; + + % Plaintext + \draw[thick, fill=yellow!20] (6,0.5) rectangle (8.5,1.5); + \node at (7.25,1) {Plaintext}; + + % XOR + \draw[->, thick] (2.5,-1) -- (5,-1); + \draw[->, thick] (7.25,0.5) -- (7.25,-0.5) -- (5.5,-0.5) -- (5.5,-1); + \draw[thick] (5,-1.5) circle (0.5); + \node at (5,-1.5) {$\oplus$}; + + % Ciphertext + \draw[->, thick] (5,-2) -- (5,-3); + \draw[thick, fill=gray!20] (3.5,-3) rectangle (6.5,-4); + \node at (5,-3.5) {Ciphertext}; + \end{tikzpicture} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{WEP: the perfect storm} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize}[<+->] + \item \textbf{WEP (Wired Equivalent Privacy):} Wi-Fi security protocol from 1997 + \begin{itemize}[<+->] + \item Used RC4 for encryption + \item 104-bit secret key shared among all devices + \end{itemize} + \item \textbf{Vulnerable design choice:} Initialization Vectors (IVs) + \begin{itemize}[<+->] + \item To avoid key reuse, WEP prepends a 24-bit IV to each packet + \item RC4 key becomes: $(IV_1, IV_2, IV_3, K_1, K_2, \ldots, K_n)$ + \item IV is sent \emph{in plaintext} with each packet! + \end{itemize} + \item \textbf{Break:} This creates exactly the conditions the FMS (Fluhrer, Mantin, Shamir) attack exploited + \begin{itemize}[<+->] + \item Many related keys (same secret key, different IVs) + \item Attacker knows the first 3 bytes of each key (the IV) + \item Perfect setup for the FMS attack! + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{WEP's IV structure} + \begin{center} + \begin{tikzpicture}[scale=0.6] + \draw[thick] (0,2) rectangle (2,3); + \node at (1,2.5) {\scriptsize IV Byte 1}; + \draw[thick] (2,2) rectangle (4,3); + \node at (3,2.5) {\scriptsize IV Byte 2}; + \draw[thick] (4,2) rectangle (6,3); + \node at (5,2.5) {\scriptsize IV Byte 3}; + \draw[thick, fill=red!20] (6,2) rectangle (8,3); + \node at (7,2.5) {\scriptsize $K_1$}; + \draw[thick, fill=red!20] (8,2) rectangle (10,3); + \node at (9,2.5) {\scriptsize $K_2$}; + \draw[thick, fill=red!20] (10,2) rectangle (12,3); + \node at (11,2.5) {\scriptsize $\ldots$}; + \node[above] at (3,3.2) {\textbf{Known to Attacker}}; + \node[above] at (9,3.2) {\textbf{Secret Key (Target)}};n + \draw[->, thick, red] (1,1.5) -- (1,2); + \node[below, red, text width=5cm, align=center] at (1,1.2) {\textbf{IVs like $(3, 255, x)$}}; + \draw[->, thick, red] (7,1.5) -- (7,0.5); + \node[below, red] at (7,0.3) {\textbf{Reveal $K_1$}}; + \end{tikzpicture} + \end{center} + \begin{itemize}[<+->] + \item \textbf{The FMS Attack:} Exploits weak IV patterns of form $(A+3, 255, x)$ + \item \textbf{Pattern:} To attack key byte $K_A$, wait for IVs $(A+3, 255, x)$ + \item \textbf{Frequency:} About 1 in 65,536 packets match the vulnerable pattern + \item \textbf{Collection:} Need multiple matching IVs per key byte for statistical attack + \item \textbf{Result:} With enough packets, incrementally recover the entire key + \end{itemize} +\end{frame} + +\begin{frame}{Practical tools} + \begin{itemize}[<+->] + \item \textbf{AirSnort (2001):} First practical WEP cracking tool + \begin{itemize}[<+->] + \item Implemented the FMS attack + \item Could crack WEP keys with 1-5 million packets + \item Made WEP cracking accessible to non-experts + \end{itemize} + \item \textbf{WEPCrack (2001):} Another early implementation + \begin{itemize}[<+->] + \item Demonstrated the attack's effectiveness + \item Confirmed that WEP was fundamentally broken + \end{itemize} + \item \textbf{Aircrack-ng (2006):} Improved and optimized tools + \begin{itemize}[<+->] + \item Reduced required packets to hundreds of thousands + \item Added packet injection to speed up attacks + \item Still widely used today for security testing + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Attack: step by step} + \begin{itemize}[<+->] + \item \textbf{Step 1:} Attacker sets Wi-Fi card to monitor mode + \begin{itemize}[<+->] + \item Passively collects all WEP-encrypted packets + \item No need to associate with the target network + \end{itemize} + \item \textbf{Step 2:} Filter for packets with vulnerable IVs + \begin{itemize}[<+->] + \item Look for ``weak IVs'' + \item Collect the corresponding keystream bytes + \end{itemize} + \item \textbf{Step 3:} Apply statistical analysis + \begin{itemize}[<+->] + \item Use FMS attack to determine most likely key byte values + \item Incrementally build up the secret key + \end{itemize} + \item \textbf{Step 4:} Verify the recovered key + \begin{itemize}[<+->] + \item Test against captured packets + \item Success: Complete compromise of the Wi-Fi network! + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Attacks only get better} + \begin{itemize}[<+->] + \item \textbf{Klein's Attack (2005):} Extended the vulnerable IV patterns + \begin{itemize}[<+->] + \item Found additional weak key structures + \item Reduced the number of packets needed for key recovery + \end{itemize} + \item \textbf{PTW Attack (2007):} Pyshkin, Tews, and Weinmann + \begin{itemize}[<+->] + \item Revolutionary approach using Bayes' theorem + \item Could crack WEP with as few as 40,000 packets + \item Made attacks feasible on even low-traffic networks + \end{itemize} + \item \textbf{Key Recovery Speedup:} From hours to minutes + \begin{itemize}[<+->] + \item Modern attacks can crack WEP in under 10 minutes + \item Some demonstrations crack it in under 60 seconds + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Lessons learned from WEP} + \begin{itemize}[<+->] + \item \textbf{Lesson 1:} Never use a stream cipher with related keys + \begin{itemize}[<+->] + \item WEP's IV structure created exactly this scenario + \item Modern protocols use proper key derivation functions + \end{itemize} + \item \textbf{Lesson 2:} Academic attacks become practical faster than expected + \begin{itemize}[<+->] + \item FMS attack went from paper to tool in months + \item ``Theoretical'' often means ``practical soon'' + \end{itemize} + \item \textbf{Lesson 3:} Security protocols need formal analysis + \begin{itemize}[<+->] + \item WEP was designed by committee without cryptographic rigor + \item Modern protocols undergo extensive peer review + \end{itemize} + \item \textbf{Lesson 4:} Backward compatibility can be a security nightmare + \begin{itemize}[<+->] + \item WEP remained deployed long after being broken + \item Organizations were slow to migrate due to cost/complexity + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{WEP timeline} + \begin{itemize}[<+->] + \item \textbf{2001:} FMS attack published - WEP theoretically broken + \item \textbf{2001:} AirSnort released - WEP practically broken + \item \textbf{2003:} WPA (Wi-Fi Protected Access) standardized as replacement + \item \textbf{2004:} WPA2 released with AES encryption + \item \textbf{2006:} Wi-Fi Alliance deprecates WEP + \item \textbf{2012:} WEP support removed from Windows 8 + \item \textbf{2018:} Many vendors stop supporting WEP entirely + \item \textbf{Today:} WEP is considered a historical curiosity + \end{itemize} +\end{frame} + +\section{RC4 in TLS} + +\begin{frame}{RC4 in TLS: from preferred to prohibited} + \begin{itemize}[<+->] + \item \textbf{RC4's role in TLS/SSL:} Once the default stream cipher + \begin{itemize}[<+->] + \item Preferred over block ciphers due to speed + \item No need for padding (unlike CBC mode) + \item Avoided the BEAST attack against CBC ciphers + \end{itemize} + \item \textbf{2011:} BEAST attack made RC4 more attractive + \begin{itemize}[<+->] + \item Attack on CBC mode in TLS 1.0 + \item Many servers switched to RC4-only cipher suites + \item RC4 usage actually increased! + \end{itemize} + \item \textbf{The irony:} Avoiding one attack led directly into another + \begin{itemize}[<+->] + \item RC4's biases were known but considered impractical + \item This assumption would prove catastrophically wrong + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{AlFardan et al. (2013): RC4 biases in TLS} + \begin{columns}[c] + \begin{column}{0.6\textwidth} + \begin{itemize}[<+->] + \item \textbf{The discovery:} RC4's biases are exploitable in TLS:\footnote{\url{https://appliedcryptography.page/papers/rc4-tls.pdf}} + \begin{itemize}[<+->] + \item First 256 bytes of keystream heavily biased + \item Certain byte positions more predictable than others + \item Biases persist even with proper key generation + \end{itemize} + \item \textbf{Key finding:} Single-byte biases + \begin{itemize}[<+->] + \item Position 1: $\Pr[Z_1 = 0] \approx 2^{-7}$ (double expected) + \item Position 2: $\Pr[Z_2 = 0] \approx 2^{-7}$ (double expected) + \item Positions 3-255: Various smaller biases + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \begin{itemize}[<+->] + \item \textbf{Multi-byte biases:} Even stronger patterns + \begin{itemize}[<+->] + \item $(Z_1, Z_{257}) = (0, 0)$ with probability $2^{-11}$ + \item Should be $2^{-16}$ if truly random + \item 32 times more likely than expected! + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The broadcast attack scenario} + \begin{itemize}[<+->] + \item \textbf{Attack model:} Same plaintext encrypted many times + \begin{itemize}[<+->] + \item HTTP cookies sent with every request + \item Session tokens in fixed positions + \item Password fields in web forms + \end{itemize} + \item \textbf{The mathematics:} Bias accumulation + \begin{itemize}[<+->] + \item Collect ciphertexts: $C_1, C_2, \ldots, C_n$ + \item For position $i$: count occurrences of each byte value + \item Most frequent ciphertext byte reveals plaintext byte + \item Required samples: $\mathcal{O}(N \cdot B^{-2})$ where $B$ is bias + \end{itemize} + \item \textbf{Practical requirements:} + \begin{itemize}[<+->] + \item $2^{24}$ to $2^{30}$ encryptions needed + \item Feasible for persistent attackers + \item JavaScript injection can generate traffic + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Garman et al. (2015): attacks only get better} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{The challenge:} AlFardan et al.'s attack was still ``impractical'' + \begin{itemize}[<+->] + \item Required billions of encryptions + \item Took days or weeks to execute + \item Many dismissed it as theoretical + \end{itemize} + \item \textbf{Insight:} Target password verifiers, not cookies\footnote{\url{https://appliedcryptography.page/papers/rc4-attacks.pdf}} + \begin{itemize}[<+->] + \item Basic Authentication sends passwords in every request + \item IMAP/SMTP use similar repeated authentication + \item Password structure provides additional constraints + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \begin{itemize}[<+->] + \item \textbf{The improvements:} Orders of magnitude faster + \begin{itemize}[<+->] + \item Exploit password character distributions + \item Use Mantin's ABSAB bias (positions 1-4) + \item Combine with dictionary attacks + \item Other attack papers use similar techniques, including to break WPA-TKIP, a successor to WEP!\footnote{\url{https://appliedcryptography.page/papers/rc4-biases.pdf}} + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Mantin's ABSAB bias (2005)} + \begin{itemize}[<+->] + \item \textbf{The discovery:} Certain digraph patterns repeat with anomalous frequency\footnote{\url{https://appliedcryptography.page/papers/rc4-absab.pdf}} + \begin{itemize}[<+->] + \item Pattern: Two characters repeat after a gap (e.g., ABAB, ABCAB) + \item Occurs when value 1 is used to update index $j$ in RC4 + \item Creates correlations between distant output positions + \end{itemize} + \item \textbf{The mathematics:} For pattern AB...AB with gap $G$ + \begin{itemize}[<+->] + \item Expected probability in random: $1/N^2$ + \item Actual probability in RC4: $(1 + e^{(-4-8G)/N}/N) \cdot 1/N^2$ + \item Relative bias: $\approx 1/N$ for zero gap, decreases with gap size + \end{itemize} + \item \textbf{Why it matters:} + \begin{itemize}[<+->] + \item Enables distinguishing attacks with only $2^{26}$ samples + \item Can predict individual bytes with 82\% accuracy after $2^{50}$ samples + \item Particularly effective against password-based authentication + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{ABSAB bias in action: practical example} + \begin{itemize}[<+->] + \item \textbf{Target:} Password ``hello123'' in HTTP Basic Authentication + \item \textbf{Step 1:} Password encoded as base64: ``aGVsbG8xMjM='' + \item \textbf{Step 2:} Look for ABSAB patterns in collected ciphertexts: + \begin{center} + \begin{tikzpicture}[scale=0.8] + \foreach \i/\char in {0/h,1/e,2/l,3/l,4/o,5/1,6/2,7/3} { + \draw[thick] (\i*1.2,2) rectangle (\i*1.2+1,3); + \node at (\i*1.2+0.5,2.5) {\texttt{\char}}; + } + \draw[red, ultra thick] (2*1.2-0.1,1.9) rectangle (3*1.2+1.1,3.1); + \node[red, below] at (5,1.75) {Repeated ``ll'' pattern}; + \draw[->, thick, blue] (2.5,1) -- (2.5,1.8); + \node[blue, below] at (2.5,1) {ABSAB: $(l,l,*,l,l)$ occurs 1024× more!}; + \end{tikzpicture} + \end{center} + \item \textbf{Step 3:} After $2^{26}$ samples, frequency analysis reveals: + \begin{itemize}[<+->] + \item Positions 2-3: ``ll'' pattern confirmed via ABSAB + \item Position 0: ``h'' (68/256 occurrences) + \item Position 1: ``e'' (65/256 occurrences) + \item Password structure revealed: ``h\_ll\_\_\_\_'' + \end{itemize} + \item \textbf{Result:} Search space reduced from $62^8$ to $62^4$ possibilities! + \end{itemize} +\end{frame} + +\begin{frame}{Password recovery: the numbers} + \begin{itemize}[<+->] + \item \textbf{Basic Authentication attack performance:} + \begin{itemize}[<+->] + \item 6-character passwords: $2^{26}$ encryptions + \item Time: ~50-100 hours. + \end{itemize} + \item \textbf{IMAP attack results:} + \begin{itemize}[<+->] + \item Real passwords recovered in laboratory setting + \item Character-by-character recovery possible + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{POODLE (2014): the final nail} + \begin{itemize}[<+->] + \item \textbf{POODLE:} Padding Oracle On Downgraded Legacy Encryption + \begin{itemize}[<+->] + \item Not specifically an RC4 attack + \item But exploited SSL 3.0's MAC-then-encrypt with CBC + \item Led to mass exodus from SSL 3.0 + \end{itemize} + \item \textbf{The downgrade dance:} + \begin{itemize}[<+->] + \item Attackers force TLS connections to fail + \item Browsers retry with older SSL 3.0 + \item SSL 3.0 has no downgrade protection! + \end{itemize} + \item \textbf{Why this matters for RC4:} + \begin{itemize}[<+->] + \item SSL 3.0 heavily used RC4 + \item POODLE + RC4 biases = from compromise to compromise + \item Final push to deprecate both SSL 3.0 and RC4 + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Coordinated response between vendors} + \begin{itemize}[<+->] + \item \textbf{2013:} IETF begins discussing RC4 deprecation + \begin{itemize}[<+->] + \item Working groups start planning migration + \end{itemize} + \item \textbf{2014/2015:} Major browsers act + \begin{itemize}[<+->] + \item Chrome/Firefox announce RC4 phase-out plans + \item Microsoft issues security advisories + \item Apple begins removing RC4 from Safari + \end{itemize} + \item \textbf{2015:} RFC 7465 prohibits RC4 in TLS + \begin{itemize}[<+->] + \item ``TLS clients MUST NOT include RC4 cipher suites'' + \item ``TLS servers MUST NOT select RC4 cipher suites'' + \item Formal end of RC4 in internet protocols + \end{itemize} + \item \textbf{2016/2018:} RC4 removed from all major browsers + \end{itemize} +\end{frame} + +\begin{frame}{Technical lessons from RC4's demise} + \begin{itemize}[<+->] + \item \textbf{Lesson 1:} Statistical biases matter at scale + \begin{itemize}[<+->] + \item ``Small'' biases become exploitable with enough data + \item Modern internet generates massive data volumes + \item Never dismiss statistical irregularities + \end{itemize} + \item \textbf{Lesson 2:} Attacks combine in unexpected ways + \begin{itemize}[<+->] + \item ABSAB bias + password structure = practical attack + \item Protocol downgrade + cipher weakness = disaster + \end{itemize} + \item \textbf{Lesson 3:} Migration is painful but necessary + \begin{itemize}[<+->] + \item RC4 removal broke many legacy systems + \item But waiting would have been catastrophic + \item Plan for crypto-agility from the start + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{RC4: a complete timeline} + \begin{itemize}[<+->] + \item \textbf{1987:} Ron Rivest designs RC4 + \item \textbf{1994:} Algorithm leaked to cypherpunks + \item \textbf{1995-2000:} Early bias discoveries + \item \textbf{2001:} FMS attack breaks WEP + \item \textbf{2011:} BEAST attack increases RC4 usage + \item \textbf{2013:} AlFardan et al. show TLS attacks are almost practical + \item \textbf{2014:} POODLE compromises SSL 3.0 + \item \textbf{2015:} Garman et al. improves password recovery + \item \textbf{2015:} IETF prohibits RC4 (RFC 7465) + \item \textbf{2016:} RC4 removed from browsers + \item \textbf{Today:} RC4 is cryptographically dead + \end{itemize} +\end{frame} + +\begin{frame}{The broader impact} + \begin{itemize}[<+->] + \item \textbf{On cryptographic design:} + \begin{itemize}[<+->] + \item Stream ciphers now use different designs (ChaCha20) + \item Focus on provable security properties + \item Extensive bias analysis before deployment + \end{itemize} + \item \textbf{On protocol design:} + \begin{itemize}[<+->] + \item TLS 1.3 removed all weak ciphers + \item Mandatory authenticated encryption (AEAD) + \item No more downgrade attacks + \end{itemize} + \item \textbf{On deployment practices:} + \begin{itemize}[<+->] + \item Regular security audits of cipher suites + \item Sunset dates for algorithms + \item Crypto-agility built into protocols + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Modern alternatives to RC4} + \begin{itemize}[<+->] + \item \textbf{ChaCha20-Poly1305:} The modern stream cipher + \begin{itemize}[<+->] + \item Designed by Daniel J. Bernstein + \item No known biases after extensive analysis + \item Includes authentication (AEAD) + \end{itemize} + \item \textbf{AES-GCM:} The block cipher alternative + \begin{itemize}[<+->] + \item Hardware acceleration on modern CPUs + \item Well-studied security properties + \item Standard choice for TLS 1.3 + \end{itemize} + \item \textbf{Key differences from RC4:} + \begin{itemize}[<+->] + \item Authenticated encryption prevents tampering + \item No statistical biases in keystream + \item Designed with modern cryptanalysis in mind + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{RC4: final thoughts} + \begin{itemize}[<+->] + \item \textbf{A cipher of its time:} + \begin{itemize}[<+->] + \item Perfect for 1990s hardware constraints + \item Served the early internet well + \item But couldn't survive modern cryptanalysis + \end{itemize} + \item \textbf{The lifecycle of cryptography:} + \begin{itemize}[<+->] + \item All ciphers eventually fall + \item Plan for migration from day one + \item Monitor academic literature for early warnings + \end{itemize} + \item \textbf{The human element:} + \begin{itemize}[<+->] + \item Ron Rivest's elegant design lasted 28 years + \item Cryptographers who broke it built on decades of research + \item The cycle continues with new algorithms and new attacks + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-3.tex b/slides/2-3.tex new file mode 100644 index 0000000..b4e1bf0 --- /dev/null +++ b/slides/2-3.tex @@ -0,0 +1,1837 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.3: Secure Messaging} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Slides not complete and may contain errors} + \begin{itemize} + \item This slide deck is not finished, may contain errors, and is missing important material. Do not rely on it yet. + \end{itemize} +\end{frame} + +\section{The Dark Ages} + +\begin{frame}{The Dark Ages} + \begin{itemize} + \item \textbf{Pretty Good Privacy} (PGP) - Created by Phil Zimmermann in 1991 + \item First widely available strong encryption for everyday people + \item Uses public key cryptography for email encryption and digital signatures + \item Revolutionary: Previously, strong crypto was government/military only + \item Core idea: Each user has a key pair (public key + private key) + \end{itemize} +\end{frame} + +\begin{frame}{How PGP works} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Encryption} + \begin{enumerate} + \item Alice writes email to Bob + \item Gets Bob's public key + \item PGP encrypts message with Bob's public key + \item Only Bob's private key can decrypt + \end{enumerate} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Digital Signatures} + \begin{enumerate} + \item Alice signs with her private key + \item Anyone with Alice's public key can verify + \item Proves message came from Alice + \item Detects tampering + \end{enumerate} + \end{column} + \end{columns} + \begin{alertblock}{Hybrid Encryption} + Actually uses symmetric crypto for message, asymmetric for key exchange + \end{alertblock} +\end{frame} + +\begin{frame}{PGP in email clients} + \begin{itemize} + \item \textbf{Early days}: Command-line tools (1991-1995) + \begin{itemize} + \item Manual encryption/decryption + \item Copy and paste ciphertext into email + \end{itemize} + \item \textbf{Integration era}: Plugins and extensions (1995-2010s) + \begin{itemize} + \item Enigmail for Thunderbird + \item GPGTools for Apple Mail + \item Outlook plugins + \end{itemize} + \item \textbf{User experience}: Still complex! + \begin{itemize} + \item Key management burden on users + \item Accidental plaintext replies common + \item Attachments often forgotten + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Look at this mess} + \bigimagewithcaption{pgp_keyserver.png}{A PGP ``key server''} +\end{frame} + +\begin{frame}{Look at this mess} + \bigimagewithcaption{pgp_pubkey.png}{Allegedly my public key. Is it even? I don't know!} +\end{frame} + +\begin{frame}{The Key Distribution Problem} + \begin{columns} + \begin{column}{0.6\textwidth} + \textbf{How do you get someone's public key?} + \begin{itemize} + \item \textbf{Key servers}: MIT, SKS keyservers + \begin{itemize} + \item Upload your public key + \item Search by email/name + \item Anyone can upload anything! + \end{itemize} + \item \textbf{Key fingerprints}: 40-hex-digit identifiers + \begin{itemize} + \item Verify out-of-band (phone, in person) + \item Business cards with fingerprints + \end{itemize} + \item \textbf{Web of Trust}: Keys signed by other users + \begin{itemize} + \item ``I trust Alice, Alice trusts Bob'' + \item Key signing parties! + \begin{itemize} + \item Such was our decadence, our confusion + \end{itemize} + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \begin{exampleblock}{Example Fingerprint} + \ttfamily\scriptsize + D745 2D8B 9E3F 4F3D\\ + 7A82 F9B5 1C4A 6E9D\\ + 8B3F 2E4C 9A7D 5F8E + \end{exampleblock} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{PGP: fundamental challenges} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{itemize} + \item \textbf{Usability nightmare} + \begin{itemize} + \item ``Why Johnny Can't Encrypt'' (1999) - landmark usability study\footnote{\url{https://appliedcryptography.page/papers/johnny-cant.pdf}} + \item Key management too complex for average users + \item Easy to make catastrophic mistakes + \end{itemize} + \item \textbf{No forward secrecy} + \begin{itemize} + \item Compromise private key = decrypt all past messages + \item Keys often used for years or decades + \end{itemize} + \item \textbf{Metadata exposed} + \begin{itemize} + \item Subject lines, recipients visible + \item Timing and frequency observable + \end{itemize} + \item \textbf{Web of Trust failed in practice} + \begin{itemize} + \item Most users never participated + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Why Johnny Can't Encrypt (1999)} + \begin{columns}[T] + \begin{column}{0.5\textwidth} + \textbf{The Study} + \begin{itemize} + \item Whitten \& Tygar tested PGP 5.0 + \item 12 educated email users + \item 90 minutes to encrypt/sign email + \item Had manual + GUI interface + \end{itemize} + \vspace{0.5em} + \textbf{Results: Catastrophic Failure} + \begin{itemize} + \item Only 1/3 succeeded + \item 1/4 sent secrets in plaintext! + \item Didn't understand public keys + \item Used own key to encrypt to others + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Core Conclusions} + \begin{itemize} + \item \textbf{Security $\neq$ normal software} + \begin{itemize} + \item Secondary goal for users + \item Mistakes are irreversible + \item Abstract concepts + \end{itemize} + \item \textbf{Good GUI isn't enough} + \begin{itemize} + \item Need security-specific design + \item Must communicate mental model + \end{itemize} + \item \textbf{``Usable security'' requires:} + \begin{itemize} + \item Users aware of security tasks + \item Can figure out how to do them + \item Don't make dangerous errors + \item Will continue using it + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Why Johnny Still, Still Can't Encrypt (2015)} + \begin{columns}[T] + \begin{column}{0.5\textwidth} + \textbf{The Study - 16 Years Later} + \begin{itemize} + \item Ruoti et al. tested Mailvelope + \item Modern PGP browser extension + \item Integrates with webmail (Gmail) + \item 20 participants (10 pairs) + \item Exchange encrypted email + \end{itemize} + \vspace{0.5em} + \textbf{Results: Still Catastrophic} + \begin{itemize} + \item \textbf{Only 1/10 pairs succeeded!} + \item That pair took full 45 minutes + \item Success only because one knew PKI + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Common Failures} + \begin{itemize} + \item Encrypted with own public key (7/10) + \item Generated keys with friend's info + \item Recipients confused by PGP block + \item One sent private key + password! + \end{itemize} + \vspace{0.5em} + \textbf{Pain Points} + \begin{itemize} + \item No integrated tutorials + \item PKI concepts still mystifying + \item ``After 5 minutes, I would have just given up and called'' + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\section{Off-the-Record Messaging: A Quick Summary} + +\begin{frame}{Enter OTR: Off-the-Record Messaging} + \begin{itemize} + \item \textbf{Created in 2004} by Nikita Borisov, Ian Goldberg, and Eric Brewer + \item Designed specifically for instant messaging, not email + \item Key insight: Chat is synchronous, both parties online! + \item \textbf{Revolutionary features}: + \begin{itemize} + \item Perfect forward secrecy + \item Deniable authentication + \item Automatic key exchange + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{OTR's take on key exchange} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{PGP's Problem} + \begin{itemize} + \item Need recipient's key \textit{before} messaging + \item Complex key distribution infrastructure + \item Users must understand PKI + \item One key for all messages + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{OTR's Solution} + \begin{itemize} + \item Diffie-Hellman key agreement + \item Keys negotiated per conversation + \item Automatic and transparent + \item New keys frequently (ratcheting) + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{OTR: new security properties} + \begin{itemize} + \item \textbf{Forward Secrecy} + \begin{itemize} + \item Each message uses ephemeral keys + \item Compromise today doesn't reveal yesterday's messages + \item Keys deleted after use + \end{itemize} + \item \textbf{Deniable Authentication} + \begin{itemize} + \item Messages authenticated to recipient + \item But no cryptographic proof for third parties + \item Like a real conversation - no permanent record + \end{itemize} + \item \textbf{Socialist Millionaire Protocol} + \begin{itemize} + \item Verify identity without trusted third party + \item Share a secret question/answer + \item Zero-knowledge proof of shared knowledge + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{OTR integration success} + \begin{columns} + \begin{column}{0.6\textwidth} + \textbf{Wide Platform Adoption} + \begin{itemize} + \item \textbf{Pidgin}: Multi-protocol IM client + \item \textbf{Adium}: Mac OS X messaging + \item \textbf{Kopete}: KDE instant messenger + \item \textbf{Jitsi}: Voice/video/chat + \end{itemize} + \vspace{0.5em} + \textbf{Protocol Support} + \begin{itemize} + \item XMPP/Jabber + \item IRC (via proxy) + \item AIM, ICQ, Yahoo Messenger + \item Google Talk + \end{itemize} + \end{column} + \begin{column}{0.4\textwidth} + \textbf{Why It Worked} + \begin{itemize} + \item Plugin architecture + \item No server changes needed + \item Transparent to users + \item ``Just works'' experience + \item Graceful degradation + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{OTR user experience} + \begin{itemize} + \item \textbf{Minimal user intervention} + \begin{itemize} + \item Click ``Start private conversation'' + \item OTR negotiates automatically + \item Visual indicators show encryption status + \end{itemize} + \item \textbf{Optional authentication} + \begin{itemize} + \item Can verify fingerprints if desired + \item Or use shared secret authentication + \item But works without it! + \end{itemize} + \item \textbf{Clear security indicators} + \begin{itemize} + \item ``Private'' vs ``Not Private'' + \item ``Verified'' vs ``Unverified'' + \item Simple padlock icons + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Pidgin: an IM client with OTR support} + \bigimagewithcaption{pidgin_chat.jpg}{Pidgin supported MSN Messenger, Yahoo Messenger, IRC, etc.} +\end{frame} + +\begin{frame}{Pidgin: an IM client with OTR support} + \bigimagewithcaption{pidgin_otr.jpg}{Pidgin was a popular way to use OTR.} +\end{frame} + +\begin{frame}{OTR's legacy} + \begin{itemize} + \item \textbf{Proved feasibility of usable crypto} + \begin{itemize} + \item Automatic key management works + \item Users don't need to understand crypto + \item Security can be transparent + \end{itemize} + \item \textbf{Established core principles} + \begin{itemize} + \item Forward secrecy is essential + \item Ephemeral keys > long-term keys + \item Authentication without non-repudiation + \end{itemize} + \item \textbf{Influenced modern messaging} + \begin{itemize} + \item Signal Protocol builds on OTR ideas + \item WhatsApp, Signal, Wire all use similar concepts + \end{itemize} + \end{itemize} +\end{frame} + +\section{Diving Into Secure Messaging Cryptography through OTR} + +\begin{frame}{About this section} + \begin{itemize} + \item We're going to use OTR in order to start to understand how secure messaging protocols are designed. + \item A core concept we're going to expand on in some detail: \textbf{authenticated key exchange}, especially how it applies to secure messaging protocols. + \end{itemize} +\end{frame} + +\begin{frame}{OTR: new security properties}{Reminder} + \begin{itemize} + \item \textbf{Forward Secrecy} + \begin{itemize} + \item Each message uses ephemeral keys + \item Compromise today doesn't reveal yesterday's messages + \item Keys deleted after use + \end{itemize} + \item \textbf{Deniable Authentication} + \begin{itemize} + \item Messages authenticated to recipient + \item But no cryptographic proof for third parties + \item Like a real conversation - no permanent record + \end{itemize} + \item \textbf{Socialist Millionaire Protocol} + \begin{itemize} + \item Verify identity without trusted third party + \item Share a secret question/answer + \item Zero-knowledge proof of shared knowledge + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Regarding forward secrecy} + \begin{itemize} + \item \textbf{What is forward secrecy?} + \begin{itemize} + \item Past communications remain secure even if long-term keys are compromised + \item If attacker steals your keys today, they can't decrypt yesterday's messages + \item Critical property for long-lived messaging systems + \end{itemize} + \item \textbf{How OTR achieves forward secrecy:} + \begin{enumerate} + \item Uses \textit{ephemeral} Diffie-Hellman key pairs + \item Keys relevant only for a small number of messages in the current conversation + \item Deleted immediately after use + \item New keys generated frequently (``ratcheting'') + \end{enumerate} + \end{itemize} +\end{frame} + +\begin{frame}{Regarding forward secrecy} + \begin{itemize} + \item Forward secrecy means that the protocol must: + \begin{enumerate} + \item Introduce a notion of \textit{ephemeral} public key pairs. + \item Use long-term key pairs (``identity keys'') \textit{only} in the AKE, and \textit{only} for authentication and identity binding, not in the ratcheting steps. + \end{enumerate} + \end{itemize} +\end{frame} + +\begin{frame}{Forward secrecy: key types} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Long-term Identity Keys} + \begin{itemize} + \item Persist across sessions + \item Identify users to each other + \item Used only for authentication + \item Never directly encrypt messages + \item Compromise affects identity, not past messages + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Ephemeral Keys} + \begin{itemize} + \item Generated per conversation + \item Used for actual encryption + \item Derived via Diffie-Hellman + \item Deleted after use + \item Cannot be recovered later + \end{itemize} + \end{column} + \end{columns} + \begin{alertblock}{Key Principle} + Identity keys authenticate the key exchange, but ephemeral keys encrypt the messages + \end{alertblock} +\end{frame} + +\begin{frame}{Forward secrecy in practice} + \begin{itemize} + \item \textbf{The OTR approach:} + \begin{enumerate} + \item Alice and Bob perform authenticated DH exchange + \item Long-term keys sign the ephemeral public values + \item Shared secret derived from ephemeral keys only + \item Message keys derived from shared secret + \item All ephemeral material deleted after use + \end{enumerate} + \item \textbf{Contrast with PGP:} + \begin{itemize} + \item PGP uses same key pair for years + \item One key compromise = all messages exposed + \item No automatic key rotation + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{SIGMA: SIGn-and-Mac Authenticated Key Exchange} + \begin{columns} + \begin{column}{0.4\textwidth} + \begin{itemize} + \item \textbf{AKE} + \begin{itemize} + \item Both parties verify each other's identity + \item Establish shared secret securely + \end{itemize} + \item \textbf{Signatures for Authentication} + \begin{itemize} + \item Each party signs the DH ephemeral public keys + \item Prevents man-in-the-middle attacks + \end{itemize} + \item $K_m \twoheadleftarrow \func{hash}{g^{xy}}$ + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{center} + \begin{tikzpicture}[>=Stealth] + \node (A) at (0,0) {$A$}; + \node (B) at (8,0) {$B$}; + \draw[->] (0.5,0) -- (7.5,0) node[midway,above] {$g^x$}; + \draw[<-] (0.5,-1) -- (7.5,-1) node[midway,above] {$g^y, g^B, \func{sign}{B, (g^x, g^y)}, \func{hmac}{K_m, g^B}$}; + \draw[->] (0.5,-2) -- (7.5,-2) node[midway,above] {$g^A, \func{sign}{A, (g^y, g^x)}, \func{hmac}{K_m, g^A}$}; + \end{tikzpicture} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Why not this?} + \begin{center} + \begin{tikzpicture}[>=Stealth] + \node (A) at (0,0) {$A$}; + \node (B) at (8,0) {$B$}; + \draw[->] (0.5,0) -- (7.5,0) node[midway,above] {$g^x$}; + \draw[<-] (0.5,-1) -- (7.5,-1) node[midway,above] {$g^y, g^B, \func{sign}{B, (g^x, g^y)}$}; + \draw[->] (0.5,-2) -- (7.5,-2) node[midway,above] {$g^A, \func{sign}{A, (g^y, g^x)}$}; + \end{tikzpicture} + \end{center} +\end{frame} + +\begin{frame}{Because...}{Note that Bob records the exchange of the \textit{same} key with Eve that Alice exchanged with Bob!} + \begin{center} + \begin{tikzpicture}[>=Stealth] + \node (A) at (0,0) {$A$}; + \node (B) at (8,0) {$B$}; + \draw[->] (0.5,0) -- (7.5,0) node[midway,above] {$g^x$}; + \draw[<-] (0.5,-1) -- (7.5,-1) node[midway,above] {$g^y, g^B, \func{sign}{B, (g^x, g^y)}$}; + \draw[->, red] (0.5,-2) -- (7.5,-2) node[midway,above] (crossed) {\textcolor{red}{$g^A, \func{sign}{A, (g^y, g^x)}$}}; + \draw[red, thick] (crossed.south west) -- (crossed.north east); + \draw[->] (0.5,-2.7) -- (7.5,-2.7) node[midway,above] {$g^E, \func{sign}{E, (g^y, g^x)}$}; + \end{tikzpicture} + \end{center} +\end{frame} + +\begin{frame}{But why HMAC though?}{Why not just add the identity key to the signature?} + \begin{center} + \begin{tikzpicture}[>=Stealth] + \node (A) at (0,0) {$A$}; + \node (B) at (8,0) {$B$}; + \draw[->] (0.5,0) -- (7.5,0) node[midway,above] {$g^A, g^x$}; + \draw[<-] (0.5,-1) -- (7.5,-1) node[midway,above] {$g^B, g^y, \func{sign}{B, (g^x, g^y, g^A)}$}; + \draw[->] (0.5,-2) -- (7.5,-2) node[midway,above] {$\func{sign}{A, (g^y, g^x, g^B)}$}; + \end{tikzpicture} + \end{center} +\end{frame} + +\begin{frame}{But why HMAC though?}{Why not just add the identity key to the signature?} + \begin{columns}[c] + \begin{column}{0.4\textwidth} + \begin{itemize} + \item Works, but... + \begin{itemize} + \item Need to know both identities before I can produce a signature, + \item Harder to implement ``identity protection'' + \begin{itemize} + \item Identity protection? + \end{itemize} + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{center} + \begin{tikzpicture}[>=Stealth] + \node (A) at (0,0) {$A$}; + \node (B) at (8,0) {$B$}; + \draw[->] (0.5,0) -- (7.5,0) node[midway,above] {$g^A, g^x$}; + \draw[<-] (0.5,-1) -- (7.5,-1) node[midway,above] {$g^B, g^y, \func{sign}{B, (g^x, g^y, g^A)}$}; + \draw[->] (0.5,-2) -- (7.5,-2) node[midway,above] {$\func{sign}{A, (g^y, g^x, g^B)}$}; + \end{tikzpicture} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Identity protection (variant)}{Identities are encrypted and are therefore cannot be learned by a passive attacker} + \begin{center} + \begin{tikzpicture}[>=Stealth] + \node (A) at (0,0) {$A$}; + \node (B) at (8,0) {$B$}; + \draw[->] (0.5,0) -- (7.5,0) node[midway,above] {$g^x$}; + \draw[<-] (0.5,-1) -- (7.5,-1) node[midway,above] {$g^y, \func{enc}{K_e, (g^B, \func{sign}{B, (g^x,g^y)}, \func{hmac}{K_m, g^B})}$}; + \draw[->] (0.5,-2) -- (7.5,-2) node[midway,above] {$\func{enc}{K_e, (g^A, \func{sign}{A, (g^y,g^x)}, \func{hmac}{K_m, g^A})}$}; + \end{tikzpicture} + \end{center} +\end{frame} + +\begin{frame}{Passive vs Active Attackers} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Passive Attacker} + \begin{itemize} + \item \textbf{Eavesdropping only} + \item Observes network traffic + \item Records all messages + \item Cannot modify or inject messages + \item Examples: + \begin{itemize} + \item ISP logging traffic + \item Government surveillance + \item WiFi sniffing + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Active Attacker} + \begin{itemize} + \item \textbf{Can modify/inject messages} + \item Intercepts and alters traffic + \item Can impersonate parties + \item Controls network routing + \item Examples: + \begin{itemize} + \item Man-in-the-middle attacks + \item Malicious WiFi hotspots + \item Compromised routers + \end{itemize} + \end{itemize} + \end{column} + \end{columns} + \begin{alertblock}{Protocol Design Impact} + Identity protection works against passive attackers, but active attackers can force identity revelation through protocol manipulation + \end{alertblock} +\end{frame} + +\begin{frame}{SIGMA: SIGn-and-Mac Authenticated Key Exchange} + \begin{columns} + \begin{column}{0.4\textwidth} + \begin{itemize} + \item \textbf{MACs for Identity Binding} + \begin{itemize} + \item MAC protects identity information + \item Links identity to the key exchange + \item $K_m \twoheadleftarrow \func{hash}{g^{xy}}$ + \end{itemize} + \item \textbf{Forward Secrecy} + \begin{itemize} + \item Uses ephemeral DH keys + \item Past sessions safe if long-term keys compromised + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.6\textwidth} + \begin{center} + \begin{tikzpicture}[>=Stealth] + \node (A) at (0,0) {$A$}; + \node (B) at (8,0) {$B$}; + \draw[->] (0.5,0) -- (7.5,0) node[midway,above] {$g^x$}; + \draw[<-] (0.5,-1) -- (7.5,-1) node[midway,above] {$g^y, B, \func{sign}{B, (g^x,g^y)}, \func{hmac}{K_m, g^B}$}; + \draw[->] (0.5,-2) -- (7.5,-2) node[midway,above] {$A, \func{sign}{A, (g^y,g^x)}, \func{hmac}{K_m, g^A}$}; + \end{tikzpicture} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{OTR version 2: Authenticated Key Exchange} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{flushleft} + \begin{tikzpicture}[>=Stealth, scale=0.67, transform shape] + \node (Alice) at (0,0) {\text{Alice}}; + \node (Bob) at (10,0) {\text{Bob}}; + \draw[->] (0.5,-1) -- (9.5,-1) node[midway,above] {$\begin{array}{rcl} + r \twoheadleftarrow \bits^{\lambda} \\ + x \twoheadleftarrow \bits^{\lambda} \\ + \func{enc}{r, g^x}, \func{hash}{g^x} + \end{array}$}; + \draw[<-] (0.5,-2.5) -- (9.5,-2.5) node[midway,above] {$\begin{array}{rcl} + y \twoheadleftarrow \bits^{\lambda} \\ + g^y + \end{array}$}; + \draw[->] (0.5,-5.5) -- (9.5,-5.5) node[midway,above] {$\begin{array}{rcl} + s & = & g^{xy} \\ + (c, c', m_{1}, m_{1}', m_{2}, m_{2}') & \twoheadleftarrow & \func{hash}{s} \\ + M_A & = & \func{hmac}{m_{1}, (g^x, g^y, g^A)} \\ + X_A & = & (g^A, \func{sign}{A, M_A}) \\ + \multicolumn{3}{c}{r, \func{enc}{c, X_A}, \func{hmac}{m_{2}, \func{enc}{c, X_A}}} + \end{array}$}; + \end{tikzpicture} + \end{flushleft} + \end{column} + \begin{column}{0.5\textwidth} + \begin{flushright} + \begin{tikzpicture}[>=Stealth, scale=0.67, transform shape] + \draw[<-] (0.5,-1) -- (9.5,-1) node[midway,above] {$\begin{array}{rcl} + g^x & = & \func{dec}{r, \func{enc}{r, g^x}} \\ + g^x & \overset{?}{=} & \func{hash}{g^x} \\ + s & = & g^{xy} \\ + (c, c', m_{1}, m_{1}', m_{2}, m_{2}') & \twoheadleftarrow & \func{hash}{s} \\ + \func{hmac}{m_{2}, \func{enc}{c, X_A}} & \overset{?}{=} & \func{hmac}{m_{2}, \func{enc}{c, X_A}} \\ + (g^A, \func{sign}{A, M_A}) & = & \func{dec}{c, X_A} \\ + M_A & = & \func{hmac}{m_{1}, (g^x, g^y, g^A)} \\ + \func{signverif}{g^A, M_A} & \overset{?}{=} & \texttt{true} \\ + M_B & = & \func{hmac}{m_{1}', (g^y, g^x, g^B)} \\ + X_B & = & (g^B, \func{sign}{B, M_B}) \\ + \multicolumn{3}{c}{\func{enc}{c', X_B}, \func{hmac}{m_{2}', \func{enc}{c', X_B}}} + \end{array}$}; + \draw[->] (0.5,-4) -- (9.5,-4) node[midway,above] {$\begin{array}{rcl} + \func{hmac}{m_{2}', \func{enc}{c', X_B}} & \overset{?}{=} & \func{hmac}{m_{2}', \func{enc}{c', X_B}} \\ + (g^B, \func{sign}{B, M_B}) & = & \func{dec}{c', X_B} \\ + M_B & = & \func{hmac}{m_{1}', (g^y, g^x, g^B)} \\ + \func{signverif}{g^B, M_B} & \overset{?}{=} & \texttt{true} \\ + \end{array}$}; + \end{tikzpicture} + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\section{Interlude: Key Derivation in Protocols} + +\begin{frame}{You may have noticed...} + \begin{itemize} + \item We often use hashing to derive symmetric primitive keys from shared secrets... + \begin{itemize} + \item $K_m \twoheadleftarrow \func{hash}{g^{xy}}$ + \item $K_e \twoheadleftarrow \func{hash}{g^{xy}}$ + \item $(c, c', m_{1}, m_{1}', m_{2}, m_{2}') \twoheadleftarrow \func{hash}{s}$ + \item Etc. + \end{itemize} + \item This doesn't really make sense. What's \textit{really} going on here? + \end{itemize} +\end{frame} + +\begin{frame}{We need a way to derive keys from shared secrets} + \begin{itemize} + \item The Diffie-Hellman shared secret $g^{xy}$ is not suitable for direct use: + \begin{itemize} + \item May not be uniformly distributed + \item Could have mathematical structure that weakens security + \item We need multiple different keys for different purposes + \end{itemize} + \item \textbf{Key Derivation Functions (KDFs)} solve this: + \begin{itemize} + \item Extract entropy and produce uniform output + \item Can generate multiple keys from one shared secret + \item Examples: HKDF, scrypt, Argon2 + \end{itemize} + \item \textbf{Proper approach}: $\func{kdf}{g^{xy}, \texttt{context}} \rightarrow (K_{\texttt{enc}}, K_{\texttt{mac}}, K_{\texttt{auth}}, \ldots)$ + \end{itemize} +\end{frame} + +\begin{frame}{Recall the example of elliptic curves} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{itemize} + \item ECDH produces a point (or its x-coordinate) as the shared secret + \item This value has mathematical structure: + \begin{itemize} + \item Limited to valid curve points + \item Not all bit patterns are possible + \item Single value, but we need multiple keys + \end{itemize} + \item KDFs solve this: $\func{kdf}{s} \rightarrow \text{uniform keys}$ + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{elliptic_curve_integers.png}{Elliptic curve over the integers. Source: Serious Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Recall the example of elliptic curves} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{center} + \begin{tikzpicture}[scale=2] + \foreach \x in {0.1,0.2,...,2.2} { + \foreach \y in {0.1,0.2,...,2.2} { + \fill (\x,\y) circle (0.5pt); + } + } + \draw[->] (0,0) -- (2.2,0) node[right] {$x$}; + \draw[->] (0,0) -- (0,2.2) node[above] {$y$}; + \node[below] at (1,-0.1) {Uniform Complete Distribution}; + \end{tikzpicture} + \end{center} + \end{column} + \begin{column}{0.5\textwidth} + \imagewithcaption{elliptic_curve_integers.png}{Elliptic curve over the integers. Source: Serious Cryptography} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{What goes wrong without proper key derivation?} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Example: Curve25519 point as AES key} + \begin{itemize} + \item Curve25519 produces 32-byte x-coordinates + \item But only $\approx 2^{252}$ valid points + \item AES-256 expects uniform 256-bit keys + \end{itemize} + \vspace{0.5em} + \textbf{Concrete attack scenario:} + \begin{itemize} + \item Attacker knows top bits are biased + \item Can distinguish real keys from random + \item Reduces effective key space + \item Makes brute force easier + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Distribution problems:} + \begin{itemize} + \item \textbf{Bit bias}: Top 3 bits of x-coordinate never all 1 + \item \textbf{Modular reduction}: $x < 2^{255} - 19$ + \item \textbf{Invalid points}: Half of x-values have no corresponding y + \end{itemize} + \vspace{0.5em} + \begin{alertblock}{Real vulnerability} + In some protocols, attacker can force specific shared secrets by choosing malicious public keys from small subgroups + \end{alertblock} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{OTR's hand-rolled KDF} + \begin{itemize} + \item \textbf{OTR needed multiple keys from one shared secret} + \begin{itemize} + \item Encryption keys, MAC keys, counter values... + \item Needed consistent, deterministic derivation + \end{itemize} + \item \textbf{Their solution (simplified):} + \begin{itemize} + \item $h_0 = \func{sha256}{s \mathbin{\|} \texttt{0x00}}$ + \item $h_1 = \func{sha256}{s \mathbin{\|} \texttt{0x01}}$ + \item $h_2 = \func{sha256}{s \mathbin{\|} \texttt{0x02}}$ + \item Extract different keys from different hash outputs + \end{itemize} + \item \textbf{Problems with this approach:} + \begin{itemize} + \item No formal security analysis + \item Related-key concerns + \item Every protocol invented its own variant + \item No standard way to include context/domain separation + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Enter HKDF: HMAC-based Key Derivation Function} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Motivated by real needs:}\footnote{\url{https://appliedcryptography.page/papers/hkdf-scheme.pdf}} + \begin{itemize} + \item OTR, TLS, IPsec all needed KDFs + \item Each had ad-hoc solutions + \item Krawczyk (2010) formalized the problem + \end{itemize} + \vspace{0.5em} + \textbf{HKDF Design:} + \begin{itemize} + \item \textbf{Extract}: Concentrate entropy + \begin{itemize} + \item $\texttt{prk} = \func{hmac}{\texttt{salt}, \texttt{ikm}}$ + \end{itemize} + \item \textbf{Expand}: Generate keys + \begin{itemize} + \item $\texttt{okm} = \func{hkdf\text{-}expand}{\texttt{prk}, \texttt{info}, \texttt{len}}$ + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Why HKDF is great:} + \begin{itemize} + \item \textbf{Provably secure} + \begin{itemize} + \item Based on HMAC security + \item Extract-then-expand paradigm + \end{itemize} + \item \textbf{Domain separation} + \begin{itemize} + \item ``info'' parameter for context + \item Different contexts $\rightarrow$ different keys + \end{itemize} + \item \textbf{Flexible output} + \begin{itemize} + \item Generate any length needed + \item Multiple keys from one PRK + \end{itemize} + \item \textbf{Now standard}: RFC 5869 + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{HKDF in practice: OTR key derivation}{OTR does not do this, this is an example} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{From one secret to many keys:} + \begin{itemize} + \item Start with: $s = g^{xy}$ + \item Derive some unique session ID as the salt + \item \texttt{HKDF(ikm, info, salt, len)} + \end{itemize} + \vspace{0.5em} + \begin{exampleblock}{OTR Key Derivation} + \ttfamily\scriptsize + c = HKDF(s, "OTR-ENC-Alice", sessionID, 32)\\ + c' = HKDF(s, "OTR-ENC-Bob", sessionID, 32)\\ + m1 = HKDF(s, "OTR-MAC1-Alice", sessionID, 2)\\ + m1' = HKDF(s, "OTR-MAC1-Bob", sessionID, 32)\\ + m2 = HKDF(s, "OTR-MAC2-Alice", sessionID, 32)\\ + m2' = HKDF(s, "OTR-MAC2-Bob", sessionID, 32) + \end{exampleblock} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Domain separation benefits:} + \begin{itemize} + \item \textbf{Clear purpose}: Each key has explicit context + \item \textbf{No key reuse}: Different contexts = different keys + \item \textbf{Direction-specific}: Alice/Bob get different keys + \end{itemize} + \vspace{0.5em} + \textbf{Compare to ad-hoc approach:} + \begin{itemize} + \item No semantic meaning + \item Easy to mess up counters + \item No formal analysis + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\section{Back to OTR: Sending and Receiving Messages} + +\begin{frame}{OTR: message exchange and ratcheting} + \begin{itemize} + \item \textbf{Each message includes:} + \begin{itemize} + \item The encrypted message itself + \item A new ephemeral DH public key share + \item MAC authenticating the entire message + \end{itemize} + \item \textbf{On sending/receiving a message:} + \begin{enumerate} + \item Generate new ephemeral key pair: $x_{\text{new}} \twoheadleftarrow \bits^{\lambda}$ + \item Include $g^{x_{\text{new}}}$ with the message + \item Compute new shared secret: $s_{\text{new}} = g^{x_{\text{new}} \cdot y_{\text{current}}}$ + \item Derive new keys from $s_{\text{new}}$ + \item Delete old ephemeral private key + \end{enumerate} + \item \textbf{MAC key revelation (for deniability):} + \begin{itemize} + \item Once both parties have acknowledged receipt + \item Publish the old MAC keys in cleartext + \item Anyone could now forge past messages! + \item No cryptographic proof of who sent what + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Forward secrecy example: stolen laptop} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{The Scenario:} + \begin{itemize} + \item You're having an OTR conversation + \item 30 messages already exchanged + \item Your laptop gets stolen! + \item Attacker has: + \begin{itemize} + \item Your current ephemeral key + \item Your long-term identity key + \item The OTR client state + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{What the attacker CAN do:} + \begin{itemize} + \item Continue the conversation as you + \item Read messages buffered in memory + \item Decrypt future messages (until detected) + \end{itemize} + \vspace{0.5em} + \textbf{What the attacker CANNOT do:} + \begin{itemize} + \item Decrypt your past 30 messages + \item Recover deleted ephemeral keys + \item Prove you sent past messages + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Limitations to forward secrecy in practice} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Key erasure challenges:} + \begin{itemize} + \item \textbf{Memory persistence} + \begin{itemize} + \item Keys may remain in RAM + \item Swap files on disk + \item Hibernation files + \item Core dumps + \end{itemize} + \item \textbf{Language/OS limitations} + \begin{itemize} + \item No guaranteed secure erasure + \item Garbage collection delays + \item Memory optimization copies + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Synchronization vs Security:} + \begin{itemize} + \item \textbf{The dilemma:} + \begin{itemize} + \item Messages arrive out of order + \item Network delays/retries + \item Must decrypt when received + \end{itemize} + \item \textbf{Signal/WhatsApp solution:} + \begin{itemize} + \item Keep window of old keys + \item ``Message key cache'' + \item Trade-off: usability vs security + \end{itemize} + \item \textbf{Real impact:} + \begin{itemize} + \item Forward secrecy weakened + \item Attack window extended + \item But better UX + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Deniability as a security property} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{What is deniability?} + \begin{itemize} + \item Messages authenticated to recipient + \item But no cryptographic proof for third parties + \item \textbf{After conversation:} anyone could have created the transcript + \end{itemize} + \vspace{0.5em} + \textbf{OTR's approach:} + \begin{itemize} + \item \textbf{MACs instead of signatures} + \begin{itemize} + \item Both parties have MAC key + \item Either could forge messages + \item Old MAC keys revealed + \item Now anyone can now forge past messages + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Contrast with digital signatures:} + \begin{itemize} + \item \textbf{PGP-signed email:} + \begin{itemize} + \item Permanent proof of authorship + \item Third party can verify later + \item Non-repudiation by design + \end{itemize} + \item \textbf{OTR philosophy:} + \begin{itemize} + \item Like face-to-face conversation + \item No permanent cryptographic record + \item Protects against coercion + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The deniability debate: Manning/Lamo case} + \textbf{The 2010 incident:} + \begin{itemize} + \item Chelsea Manning allegedly used OTR with Adrian Lamo + \item Allegedly discussed classified document leaks + \item Lamo saved chat logs, gave to FBI + \item \textbf{Used as evidence in court} + \end{itemize} + \vspace{0.5em} + \textbf{Why deniability failed:} + \begin{itemize} + \item Courts don't require cryptographic proof + \item Context and corroboration matter more + \item One party (Lamo) testified to authenticity + \item Technical deniability $\neq$ legal deniability + \end{itemize} +\end{frame} + +\begin{frame}{The deniability debate: Is deniability worth anything?} + \textbf{Is deniability worth anything?} + \begin{itemize} + \item \textbf{Arguments for:} + \begin{itemize} + \item Prevents automatic mass verification + \item Raises doubt about leaked transcripts + \item Protects against future proof requirements + \end{itemize} + \item \textbf{Arguments against:} + \begin{itemize} + \item Courts accept weaker evidence + \item Screenshots can be just as damning + \item Adds protocol complexity + \item Users don't understand it + \end{itemize} + \end{itemize} + \vspace{0.5em} + \begin{alertblock}{Open question} + Does cryptographic deniability provide meaningful real-world protection? + \end{alertblock} +\end{frame} + +\begin{frame}{Attacks on OTR version 2} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Version Rollback Attack}\footnote{\url{https://appliedcryptography.page/papers/otr-analysis.pdf}} + \begin{itemize} + \item Version negotiation happens before authentication + \item Attacker can force use of older, weaker version + \item \textbf{Attack scenario:} + \begin{itemize} + \item Attacker modifies messages to claim only OTRv1 + \end{itemize} + \item \textbf{The fix:} + \begin{itemize} + \item Include version number in AKE + \item Authenticate the negotiated version + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Authentication Failure} + \begin{itemize} + \item Mallory can convince Alice she completed AKE with Bob + \item Bob has no knowledge of this exchange + \item Only affects AKE completion belief + \item \textbf{Important limitations:} + \begin{itemize} + \item No actual MITM possible + \item Cannot decrypt messages + \item Cannot impersonate either party + \end{itemize} + \item \textbf{Real impact:} + \begin{itemize} + \item Alice thinks she's secure with Bob + \item Sends encrypted messages Bob can't read + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{OTRv2 message integrity attack} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Attack Setup:} + \begin{itemize} + \item Exploits MAC key revelation + message ordering + \item Requires network control (active attacker) + \end{itemize} + \vspace{0.5em} + \textbf{Key Insight:} + \begin{itemize} + \item Alice reveals MAC keys after ``finishing'' with them + \item Assumes messages arrive in order, but attacker can delay/reorder messages! + \item Combined with malleable encryption = attack + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Attack Prerequisites:} + \begin{itemize} + \item \textbf{MAC key revelation} for deniability + \item \textbf{Malleable encryption} (stream cipher) + \item \textbf{Network control} by attacker + \item \textbf{Message ordering assumptions} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Message integrity attack: why it works} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Step-by-step:} + \begin{enumerate} + \item Alice sends $m_0$ with keys $(x_0, y_0)$ + \item Bob responds with $m_1$ using $(x_1, y_0)$ + \item Alice sees Bob moved to $x_1$, assumes $(x_0, y_0)$ done + \item Alice publishes MAC keys for $(x_0, y_0)$ + \item Mallory blocks Alice's next message + \item Mallory creates forged $m'_0$ using: + \begin{itemize} + \item Published MAC keys + \item Malleable encryption + \end{itemize} + \item Bob accepts as delayed message + \end{enumerate} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Why Bob accepts it:} + \begin{itemize} + \item Message appears to precede $m_1$ + \item Valid MAC (Mallory has the key!) + \item Network delays are common + \item No way to detect forgery + \end{itemize} + \vspace{0.5em} + \textbf{Attack Impact:} + \begin{itemize} + \item Insert forged messages + \item Modify past messages + \item Break conversation integrity + \item Deniability feature enables attack! + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Fixing the message integrity attack} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Potential solutions:} + \begin{itemize} + \item \textbf{Delayed MAC revelation} + \begin{itemize} + \item Wait longer before publishing + \item Ensure truly done with keys + \end{itemize} + \item \textbf{Better state machine} + \begin{itemize} + \item Track message expectations + \item Reject out-of-order messages + \end{itemize} + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Additional improvements:} + \begin{itemize} + \item \textbf{Use authenticated encryption} + \begin{itemize} + \item Not just MAC + malleable cipher + \item Modern AEAD constructions + \end{itemize} + \item \textbf{Include counters in MAC} + \begin{itemize} + \item Prevent message reordering + \item Detect replay attempts + \end{itemize} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\section{Signal} + +\begin{frame}{From synchronous to asynchronous messaging} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{OTR: Synchronous Protocol} + \begin{itemize} + \item Both parties must be online + \item Real-time key exchange required + \item Can't send to offline users + \item \textbf{User experience:} + \begin{itemize} + \item ``Bob is offline'' + \item Wait for Bob to come online + \item Then initiate secure chat + \end{itemize} + \item Works for MSN Messenger and the early 2000s + \item Not suitable for mobile era + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Signal: Asynchronous Protocol} + \begin{itemize} + \item Send messages anytime + \item Recipient can be offline + \item \textbf{SMS-like experience:} + \begin{itemize} + \item Send message to Bob's phone + \item Bob's phone is off + \item Bob receives when phone turns on + \end{itemize} + \item \textbf{Challenge:} How to do AKE without Bob? + \item \textbf{Solution:} Pre-keys on server + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{OTR version 2: Authenticated Key Exchange} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \begin{flushleft} + \begin{tikzpicture}[>=Stealth, scale=0.67, transform shape] + \node (Alice) at (0,0) {\text{Alice}}; + \node (Bob) at (10,0) {\text{Bob}}; + \draw[->] (0.5,-1) -- (9.5,-1) node[midway,above] {$\begin{array}{rcl} + r \twoheadleftarrow \bits^{\lambda} \\ + x \twoheadleftarrow \bits^{\lambda} \\ + \func{enc}{r, g^x}, \func{hash}{g^x} + \end{array}$}; + \draw[<-] (0.5,-2.5) -- (9.5,-2.5) node[midway,above] {$\begin{array}{rcl} + y \twoheadleftarrow \bits^{\lambda} \\ + g^y + \end{array}$}; + \draw[->] (0.5,-5.5) -- (9.5,-5.5) node[midway,above] {$\begin{array}{rcl} + s & = & g^{xy} \\ + (c, c', m_{1}, m_{1}', m_{2}, m_{2}') & \twoheadleftarrow & \func{hash}{s} \\ + M_A & = & \func{hmac}{m_{1}, (g^x, g^y, g^A)} \\ + X_A & = & (g^A, \func{sign}{A, M_A}) \\ + \multicolumn{3}{c}{r, \func{enc}{c, X_A}, \func{hmac}{m_{2}, \func{enc}{c, X_A}}} + \end{array}$}; + \end{tikzpicture} + \end{flushleft} + \end{column} + \begin{column}{0.5\textwidth} + \begin{flushright} + \begin{tikzpicture}[>=Stealth, scale=0.67, transform shape] + \draw[<-] (0.5,-1) -- (9.5,-1) node[midway,above] {$\begin{array}{rcl} + g^x & = & \func{dec}{r, \func{enc}{r, g^x}} \\ + g^x & \overset{?}{=} & \func{hash}{g^x} \\ + s & = & g^{xy} \\ + (c, c', m_{1}, m_{1}', m_{2}, m_{2}') & \twoheadleftarrow & \func{hash}{s} \\ + \func{hmac}{m_{2}, \func{enc}{c, X_A}} & \overset{?}{=} & \func{hmac}{m_{2}, \func{enc}{c, X_A}} \\ + (g^A, \func{sign}{A, M_A}) & = & \func{dec}{c, X_A} \\ + M_A & = & \func{hmac}{m_{1}, (g^x, g^y, g^A)} \\ + \func{signverif}{g^A, M_A} & \overset{?}{=} & \texttt{true} \\ + M_B & = & \func{hmac}{m_{1}', (g^y, g^x, g^B)} \\ + X_B & = & (g^B, \func{sign}{B, M_B}) \\ + \multicolumn{3}{c}{\func{enc}{c', X_B}, \func{hmac}{m_{2}', \func{enc}{c', X_B}}} + \end{array}$}; + \draw[->] (0.5,-4) -- (9.5,-4) node[midway,above] {$\begin{array}{rcl} + \func{hmac}{m_{2}', \func{enc}{c', X_B}} & \overset{?}{=} & \func{hmac}{m_{2}', \func{enc}{c', X_B}} \\ + (g^B, \func{sign}{B, M_B}) & = & \func{dec}{c', X_B} \\ + M_B & = & \func{hmac}{m_{1}', (g^y, g^x, g^B)} \\ + \func{signverif}{g^B, M_B} & \overset{?}{=} & \texttt{true} \\ + \end{array}$}; + \end{tikzpicture} + \end{flushright} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{X3DH: Signal's Asynchronous Key Exchange} + \begin{columns}[c] + \begin{column}{1\textwidth} + \vspace{-0.75cm} + \begin{center} + \begin{tikzpicture}[>=Stealth, scale=1, transform shape] + \node (Alice) at (0,0) {\textbf{Alice}}; + \node (Server) at (4,0) {\textbf{Server}}; + \node (Bob) at (8,0) {\textbf{Bob}}; + \draw[<-, thick] (4.5,-0.5) -- (7.5,-0.5) node[midway,above] {\small Upload}; + \node[right, align=left] at (8,-1.5) {$g^B, g^{B}_{spk},$\\[0.25em]$\func{sign}{B, g^{B}_{spk}},$\\[0.25em]$g^{B}_{opk_0} \ldots g^{B}_{opk_{100}}$}; + \draw[->, thick] (0.5,-1) -- (3.5,-1) node[midway,above] {\small Fetch Bob}; + \draw[<-, thick] (0.5,-1.5) -- (3.5,-1.5) node[midway,above] {\small Bundle}; + \node[left, align=right] at (0,-1.5) {$g^B, g^{B}_{spk},$\\[0.25em]$\func{sign}{B, g^{B}_{spk}},$\\[0.25em]$g^{B}_{opk_i}$}; + \node[draw, rounded corners] at (4.25,-4) {$\renewcommand{\arraystretch}{1.5}\begin{array}{rcl} + \Delta_1 & = & \func{dh}{A, g^{B}_{spk}} \\ + \Delta_2 & = & \func{dh}{{A}_{eph_0}, g^B} \\ + \Delta_3 & = & \func{dh}{{A}_{eph_0}, g^{B}_{spk}} \\ + \Delta_4 & = & \func{dh}{{A}_{eph_0}, g^{B}_{opk_i}} \\ + S & = & c_0 \| \Delta_1 \| \Delta_2 \| \Delta_3 \| \Delta_4 + \end{array}$ + }; + \end{tikzpicture} + \end{center} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{X3DH: Signal's Asynchronous Key Exchange} + \begin{itemize} + \item $spk$: ``Signed pre-key'': a signed ephemeral key + \begin{itemize} + \item Replaced every $n$ days + \end{itemize} + \item $opk$: ``One-time'' ephemeral pre-key + \begin{itemize} + \item Bob uploads 100 of them, used only once + \end{itemize} + \item $eph$: Ephemeral keys, generated during the session + \item $c_0 \ldots c_n$: Various constants found in the protocol + \item Alice can obtain $S$ even if Bob is offline! + \item Now, using $S$, Alice can derive a bunch of keys to get the session going + \end{itemize} +\end{frame} + +\begin{frame}{Signal Double Ratchet} + \vspace{-1.25cm} + \begin{center}\resizebox{0.7\textwidth}{!}{ + \begin{msc}{} + \setmscvalues{small} + \drawframe{none} + \setlength{\instdist}{7cm} + \declinst{alice}{}{Alice} + \declinst{bob}{}{Bob} + \action*{$\begin{array}{rcl} + (rk_0, ck_0) & \twoheadleftarrow & \func{hkdf}{S, c_1, c_2} \\ + A_{eph_1} & \twoheadleftarrow & \bits^\lambda \\ + (rk_1, ck_1) & \twoheadleftarrow & \func{hkdf}{\func{dh}{A_{eph_1}, g^{B}_{spk}}, rk_0, c_2} \\ + e_0 & \twoheadleftarrow & \func{hkdf}{\func{hmac}{ck_1, c_3}, c_1, c_4} \\ + m_0 & = & \func{aead-enc}{e_0, \texttt{msg}_0, (g^{A} \| g^{A}_{spk} \| g^{B} \| g^{B}_{spk} \| g^{A}_{eph_1})} + \end{array}$}{alice} + \nextlevel[9] + \mess{$g^{A}, g^{A}_{spk}, g^{A}_{eph_0}, g^{A}_{eph_1}, m_0$}{alice}{bob} + \nextlevel[1] + \action*{$\begin{array}{rcl} + S & = & c_0 \| \func{dh}{B_{spk}, g^{A}} \| \func{dh}{B, g^{A}_{eph_0}} \| \func{dh}{B_{spk}, g^{A}_{eph_0}} \| \func{dh}{{B}_{opk_i}, g^{A}_{eph_0}} \\ + (rk_0, ck_0) & \twoheadleftarrow & \func{hkdf}{S, c_1, c_2} \\ + (rk_1, ck_1) & \twoheadleftarrow & \func{hkdf}{\func{dh}{B_{spk}, g^{A}_{eph_1}}, rk_0, c_2} \\ + e_0 & \twoheadleftarrow & \func{hkdf}{\func{hmac}{ck_1, c_3}, c_1, c_4} \\ + \texttt{msg}_0 & = & \func{aead-dec}{e_0, m_0, (g^{A} \| g^{A}_{spk} \| g^{B} \| g^{B}_{spk} \| g^{A}_{eph_1})} \\ + B_{eph_0} & \twoheadleftarrow & \bits^\lambda \\ + (rk_2, ck_2) & \twoheadleftarrow & \func{hkdf}{\func{dh}{B_{eph_0}, g^{A}_{eph_1}}, rk_1, c_2} \\ + e_1 & \twoheadleftarrow & \func{hkdf}{\func{hmac}{ck_2, c_3}, c_1, c_4} \\ + m_1 & = & \func{aead-enc}{e_1, \texttt{msg}_1, (g^{B} \| g^{B}_{spk} \| g^{A} \| g^{A}_{spk} \| g^{B}_{eph_0})} + \end{array}$}{bob} + \nextlevel[14] + \mess{$g^{B}_{eph_0}, m_1$}{bob}{alice} + \nextlevel[1] + \action*{$\begin{array}{rcl} + (rk_2, ck_2) & \twoheadleftarrow & \func{hkdf}{\func{dh}{A_{eph_1}, g^{B}_{eph_0}}, rk_1, c_2} \\ + e_1 & \twoheadleftarrow & \func{hkdf}{\func{hmac}{ck_2, c_3}, c_1, c_4} \\ + \texttt{msg}_1 & = & \func{aead-dec}{e_1, m_1, (g^{B} \| g^{B}_{spk} \| g^{A} \| g^{A}_{spk} \| g^{B}_{eph_0})} + \end{array}$}{alice} + \nextlevel[5] + \end{msc} + }\end{center} +\end{frame} + +\begin{frame}{Why the Double Ratchet is nice} + \begin{itemize} + \item \textbf{Every message gets fresh keys} + \begin{itemize} + \item Chain key advances: $ck_{i+1} = \func{hmac}{ck_i, c_3}$ + \item Message key derived: $e_i = \func{hkdf}{\func{hmac}{ck_i, c_3}, c_1, c_4}$ + \item Old chain keys immediately deleted + \item Compromise of $e_i$ reveals nothing about $e_{i-1}$ or $e_{i+1}$ + \end{itemize} + \item \textbf{Two types of ratcheting} + \begin{itemize} + \item \textbf{Symmetric ratchet}: HMAC chain for immediate messages + \item \textbf{DH ratchet}: New ephemeral keys when direction changes + \item Root key combines both: $(rk_{new}, ck_{new}) = \func{hkdf}{\func{dh}{\text{new ephemerals}}, rk_{old}, c_2}$ + \end{itemize} + \item \textbf{Post-compromise security!} + \begin{itemize} + \item If attacker steals your state at time $t$... + \item After one DH ratchet step, they're locked out again + \item Fresh randomness from new ephemeral keys + \item OTR couldn't do this - required interactive AKE + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{Forward Secrecy vs Post-Compromise Security} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Forward Secrecy} + \begin{itemize} + \item \textbf{Past messages stay secret} + \item If keys compromised today, yesterday's messages remain encrypted + \item ``Looking backward'' protection + \item \textbf{How it works:} + \begin{itemize} + \item Delete old keys after use + \item Can't decrypt without keys + \item Time travel won't help attacker + \end{itemize} + \item \textbf{Example:} Laptop stolen after conversation - past messages safe + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Post-Compromise Security} + \begin{itemize} + \item \textbf{Future messages become secret again} + \item If keys compromised today, tomorrow's messages will be secure + \item ``Healing'' or ``self-healing'' property + \item \textbf{How it works:} + \begin{itemize} + \item Inject fresh randomness + \item New ephemeral keys + \item Attacker locked out again + \end{itemize} + \item \textbf{Example:} Laptop stolen but recovered - future messages re-secure + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Can your message truly be secure after a hack?} + \begin{columns}[c] + \begin{column}{1\textwidth} + \begin{center} + \Large \textbf{The Promise and Reality of Post-Compromise Security}\footnote{\url{https://appliedcryptography.page/papers/pcs-impossibility.pdf}} + \end{center} + \vspace{1em} + \begin{itemize} + \item Based on: ``Impossibility Results for Post-Compromise Security'' by Cremers, Medinger, and Naska (2024) + \item \textbf{Spoiler:} The answer might surprise you... + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{The Dream: Self-Healing Security} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{The Promise of PCS:} + \begin{itemize} + \item Your phone gets hacked today + \item Attacker reads all your secrets + \item But tomorrow... + \item \textbf{Magic happens!} + \item Future messages become secure again + \item Attacker is ``locked out'' + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{How it ``works'':} + \begin{itemize} + \item Continuously inject fresh randomness + \item Update keys with every message + \item If attacker misses an update... + \item They can't decrypt future messages! + \item Like changing locks after a break-in + \end{itemize} + \end{column} + \end{columns} + \begin{alertblock}{Question for the class} + Does this sound too good to be true? + \end{alertblock} +\end{frame} + +\begin{frame}{PCS reality check} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{Academic papers say:} + \begin{itemize} + \item ``Signal Protocol achieves PCS!'' + \item ``Double Ratchet provides healing!'' + \item ``Proven secure!'' + \item Lots of formal proofs! Wow! + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{This paper says:} + \begin{itemize} + \item Wait, not so fast... + \item Those proofs assume perfect conditions + \item Real apps $\neq$ Academic protocols + \item \textbf{Users don't actually get PCS!} + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Phones live in the real world} + \textbf{Things that happen to real phones:} + \begin{itemize} + \item \textbf{Hardware failures:} Bit flips, memory corruption + \item \textbf{Software issues:} App crashes, OS updates + \item \textbf{User actions:} Restore from backup, reinstall apps + \item \textbf{Physical events:} Drop phone in toilet + \end{itemize} + \vspace{0.5em} + \textbf{What happens to your chats when these occur?} + \begin{itemize} + \item Academic answer: ``You're locked out forever!'' + \item Real-world requirement: ``I need to keep chatting!'' + \item If WhatsApp doesn't meet that requirement, it will lose users + \end{itemize} +\end{frame} + +\begin{frame}{Sessions all the way down} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{What users see:} + \begin{itemize} + \item One conversation with Bob + \item Linear list of messages + \item Simple and clean + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{What's really happening:} + \begin{itemize} + \item Multiple concurrent ``sessions'' + \item Signal allows up to \textbf{40 sessions!} + \begin{itemize} + \item WhatsApp even more, I believe + \end{itemize} + \item Each can be compromised separately + \item Attacker can start new ones + \end{itemize} + \end{column} + \end{columns} + \vspace{0.5em} + \begin{block}{The Impossibility Result} + If your app must handle state loss (all real apps do), then full conversation-level PCS is \textbf{mathematically impossible} + \end{block} +\end{frame} + +\begin{frame}{Why 40 sessions?} + \textbf{Signal's Magic Number: 40} + \begin{itemize} + \item Not arbitrary - represents a design choice + \item Each session = tolerance for one ``desync event'' + \item More sessions = Better usability, Worse security + \end{itemize} + \vspace{0.5em} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{N = 1 (Ultra secure)} + \begin{itemize} + \item Minimal attack surface + \item Constant ``can't decrypt'' errors + \item Messages lost during network delays + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{N = 40 (Signal's choice)} + \begin{itemize} + \item Handles many failure scenarios + \item Good user experience + \item 40 ways for attacker to get in! + \end{itemize} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{Using Tamarin to crush dreams} + \textbf{How they proved the impossibility:} + \begin{enumerate} + \item Model abstract communication system in Tamarin prover + \item Add real-world requirements: + \begin{itemize} + \item Must handle dynamic state loss (crashes, backups) + \item Must handle static state loss (lost devices) + \item Must allow recovery to continue chatting + \end{itemize} + \item Try to prove PCS property holds... + \item \textbf{Tamarin finds counterexamples!} + \end{enumerate} +\end{frame} + +\begin{frame}{So what can we do?} + \textbf{If we can't have perfect PCS, can we do better?} + \begin{itemize} + \item \textbf{Reduce session count:} Maybe N = 2 instead of 40? + \item \textbf{Sequential sessions:} Old sessions can only receive, not send + \item \textbf{Time limits:} Delete old sessions after time T + \item \textbf{UI warnings:} Highlight messages from old sessions + \end{itemize} + \vspace{0.5em} + \textbf{But remember:} + \begin{itemize} + \item These are band-aids, not cures + \item Fundamental trade-off remains + \item Perfect security = Unusable app + \end{itemize} +\end{frame} + +\begin{frame}{Discussion time} + \begin{columns}[c] + \begin{column}{0.7\textwidth} + \begin{enumerate} + \item \textbf{Is post-compromise security just security theater?} + \begin{itemize} + \item If users don't actually get it, why do we pretend? + \item Marketing vs. reality? + \end{itemize} + \item \textbf{What would you choose?} + \begin{itemize} + \item Ultra-secure but breaks constantly? + \item Works smoothly but weaker guarantees? + \end{itemize} + \item \textbf{Can we do better?} + \begin{itemize} + \item Hardware security modules? + \item Out-of-band verification? + \item Just give up on state loss resilience? + \end{itemize} + \item \textbf{Who's being honest with users?} + \begin{itemize} + \item Should apps disclose these limitations? + \item Do users even care? + \end{itemize} + \end{enumerate} + \end{column} + \begin{column}{0.3\textwidth} + \imagewithcaption{noelle_spamton.png}{Academia versus the real world} + \end{column} + \end{columns} +\end{frame} + +\begin{frame}{What about Telegram?} + \begin{columns} + \begin{column}{0.5\textwidth} + \textbf{Telegram's Approach} + \begin{itemize} + \item Two modes: Cloud chats vs Secret chats + \item Cloud chats: Encrypted to server, not E2E + \item Secret chats: Custom MTProto 2.0 protocol + \item Only available in 1-on-1 conversations + \item Must be explicitly enabled + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{Key Differences from Signal} + \begin{itemize} + \item Most users never use secret chats + \item Custom crypto instead of proven protocols + \item Server can read most messages + \item Focus on features over security + \item Different threat model assumptions + \end{itemize} + \end{column} + \end{columns} + \begin{alertblock}{Security Reality} + Despite marketing, most Telegram usage is \textbf{not} end-to-end encrypted + \end{alertblock} +\end{frame} + +\begin{frame}{Telegram's MTProto} + \textbf{What Telegram Did} + \begin{itemize} + \item Designed custom encryption protocol + \item Ignored existing academic work + \item No formal security analysis initially + \item Multiple versions after vulnerabilities found + \end{itemize} + \textbf{The Cryptographic Community Response} + \begin{itemize} + \item ``Don't roll your own crypto!'' + \item Multiple published attacks + \item Academic papers showing weaknesses + \item Telegram's defensive responses + \end{itemize} +\end{frame} + +\begin{frame}{Why Telegram made these choices} + \begin{itemize} + \item \textbf{Server-side features require plaintext access:} + \begin{itemize} + \item Cloud sync across unlimited devices + \item Powerful search across all messages + \item Large file sharing and streaming + \item Bots and integrations + \item Message editing and deletion + \end{itemize} + \item \textbf{Different threat model:} + \begin{itemize} + \item ``We don't trust governments, but we trust ourselves'' + \item Emphasis on government censorship resistance + \item Less focus on protecting from service provider + \end{itemize} + \item \textbf{User experience priorities:} + \begin{itemize} + \item Instant sync, no waiting for key exchange + \item Works the same across all platforms + \item No ``this message couldn't be decrypted'' errors + \end{itemize} + \end{itemize} +\end{frame} + +\begin{frame}{The Telegram Paradox} + \begin{columns}[c] + \begin{column}{0.5\textwidth} + \textbf{What activists think they're getting:} + \begin{itemize} + \item End-to-end encrypted messaging + \item Protection from government surveillance + \item Secure communication platform + \item ``Telegram is encrypted, right?'' + \end{itemize} + \end{column} + \begin{column}{0.5\textwidth} + \textbf{What they're actually getting:} + \begin{itemize} + \item Messages readable by Telegram servers + \item Subject to legal requests and seizure + \item Only secret chats are E2E encrypted + \item Most users never enable secret chats + \end{itemize} + \end{column} + \end{columns} + \vspace{0.5em} + \begin{alertblock}{Real-world Impact} + Pavel Durov can read your Telegram chats at his discretion + \end{alertblock} +\end{frame} + +\section{Group Secure Messaging} +% Group messaging with WhatsApp as example +% Group messaging challenges +% MLS + +\section{Post-Quantum Secure Messaging} +% PQ3 +% PQX3DH +% https://github.com/signalapp/SparsePostQuantumRatchet/ + +\begin{frame}{Slides not complete and may contain errors} + \begin{itemize} + \item This slide deck is not finished, may contain errors, and is missing important material. Do not rely on it yet. + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-4.tex b/slides/2-4.tex new file mode 100644 index 0000000..34513da --- /dev/null +++ b/slides/2-4.tex @@ -0,0 +1,28 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.4: Applied Cryptography in Cloud Security} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Slides not complete and may contain errors} + \begin{itemize} + \item This slide deck is not finished, may contain errors, and is missing important material. Do not rely on it yet. + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-5.tex b/slides/2-5.tex new file mode 100644 index 0000000..ff3ec75 --- /dev/null +++ b/slides/2-5.tex @@ -0,0 +1,28 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.5: High-Assurance Cryptography} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Slides not complete and may contain errors} + \begin{itemize} + \item This slide deck is not finished, may contain errors, and is missing important material. Do not rely on it yet. + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-6.tex b/slides/2-6.tex new file mode 100644 index 0000000..7010610 --- /dev/null +++ b/slides/2-6.tex @@ -0,0 +1,28 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.6: Cryptocurrency Cryptography} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Slides not complete and may contain errors} + \begin{itemize} + \item This slide deck is not finished, may contain errors, and is missing important material. Do not rely on it yet. + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-7.tex b/slides/2-7.tex new file mode 100644 index 0000000..6e82427 --- /dev/null +++ b/slides/2-7.tex @@ -0,0 +1,28 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.7: Post-Quantum Cryptography} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Slides not complete and may contain errors} + \begin{itemize} + \item This slide deck is not finished, may contain errors, and is missing important material. Do not rely on it yet. + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-8.tex b/slides/2-8.tex new file mode 100644 index 0000000..9f371a1 --- /dev/null +++ b/slides/2-8.tex @@ -0,0 +1,28 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.8: Zero-Knowledge Proofs} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Slides not complete and may contain errors} + \begin{itemize} + \item This slide deck is not finished, may contain errors, and is missing important material. Do not rely on it yet. + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/2-9.tex b/slides/2-9.tex new file mode 100644 index 0000000..8c1a839 --- /dev/null +++ b/slides/2-9.tex @@ -0,0 +1,28 @@ +\documentclass[aspectratio=169, lualatex, handout]{beamer} +\makeatletter\def\input@path{{theme/}}\makeatother\usetheme{cipher} + +\title{Applied Cryptography} +\author{Nadim Kobeissi} +\institute{American University of Beirut} +\instituteimage{images/aub_white.png} +\date{\today} +\coversubtitle{CMPS 297AD/396AI\\Fall 2025} +\coverpartname{Part 2: Real-World Cryptography} +\covertopicname{2.9: Secure Multiparty Computation} +\coverwebsite{https://appliedcryptography.page} + +\begin{document} +\begin{frame}[plain] + \titlepage +\end{frame} + +\begin{frame}{Slides not complete and may contain errors} + \begin{itemize} + \item This slide deck is not finished, may contain errors, and is missing important material. Do not rely on it yet. + \end{itemize} +\end{frame} + +\begin{frame}[plain] + \titlepage +\end{frame} +\end{document} diff --git a/slides/Makefile b/slides/Makefile new file mode 100644 index 0000000..8131346 --- /dev/null +++ b/slides/Makefile @@ -0,0 +1,73 @@ +all: + @make 1-1 + @make 1-2 + @make 1-3 + @make 1-4 + @make 1-5 + @make 1-6 + @make 1-7 + @make 1-8 + @make 2-1 + @make 2-2 + @make 2-3 + @make 2-4 + @make 2-5 + @make 2-6 + @make 2-7 + @make 2-8 + @make 2-9 + @make 2-10 + +1-1: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "1-1.tex" + +1-2: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "1-2.tex" + +1-3: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "1-3.tex" + +1-4: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "1-4.tex" + +1-5: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "1-5.tex" + +1-6: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "1-6.tex" + +1-7: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "1-7.tex" + +1-8: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "1-8.tex" + +2-1: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-1.tex" + +2-2: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-2.tex" + +2-3: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-3.tex" + +2-4: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-4.tex" + +2-5: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-5.tex" + +2-6: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-6.tex" + +2-7: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-7.tex" + +2-8: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-8.tex" + +2-9: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-9.tex" + +2-10: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website/slides "2-10.tex" diff --git a/slides/README.md b/slides/README.md new file mode 100644 index 0000000..0b946d4 --- /dev/null +++ b/slides/README.md @@ -0,0 +1,37 @@ +# Slides + +Welcome to the slides! Here they are. Isn't that amazing? + +## Readiness status + +I'm still working on the slides. If the checkbox isn't checked, it means you shouldn't use them yet. + +#### Part 1 + +**Complete!** + +#### Part 2 + +- [x] Part 2: Topic 1 +- [ ] Part 2: Topic 2 +- [ ] Part 2: Topic 3 +- [ ] Part 2: Topic 4 +- [ ] Part 2: Topic 5 +- [ ] Part 2: Topic 6 +- [ ] Part 2: Topic 7 +- [ ] Part 2: Topic 8 +- [ ] Part 2: Topic 9 +- [ ] Part 2: Topic 10 + +## Compiling the slides + +You'll need to first have [Tectonic](https://tectonic-typesetting.github.io/en-US/) installed. The good news is that this means that you don't need to install LaTeX! + +## Notes + +### Regarding handout mode +By default, these slides are presented in "handout mode", meaning they don't have transitions. If you want to compile them a slide deck with transitions (useful during teaching), remove the `handout` directive from the first line of the slide deck, and then run the corresponding `make` command. + +### Converting from SVG +This is for my use only, please ignore: +`magick -density 4000 input.svg -resize 4000x output.png` diff --git a/slides/images/aead_scenario_1.pdf b/slides/images/aead_scenario_1.pdf new file mode 100644 index 0000000..7995b37 --- /dev/null +++ b/slides/images/aead_scenario_1.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23247d51d041e23595e07d074fa149237c9177924b48828b527d88ed40fe2b79 +size 141802 diff --git a/slides/images/aead_scenario_2.pdf b/slides/images/aead_scenario_2.pdf new file mode 100644 index 0000000..435b952 --- /dev/null +++ b/slides/images/aead_scenario_2.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b262a9b189cfb0823dbfdf779793f4b9ea9a17045c5c9d9b5b6fdb912ffb774b +size 139540 diff --git a/slides/images/aead_scenario_4.pdf b/slides/images/aead_scenario_4.pdf new file mode 100644 index 0000000..0bfb0a1 --- /dev/null +++ b/slides/images/aead_scenario_4.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:475e9b724d1d116bf42500a6d4202d66d66ba644204ef64bc8eb2bf78e37f46c +size 187995 diff --git a/slides/images/aes_subbytes.png b/slides/images/aes_subbytes.png new file mode 100644 index 0000000..df76493 --- /dev/null +++ b/slides/images/aes_subbytes.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5634e92f50763dc9bd3f2340a522f8bf8dcc2b4256a541b5c724d1c6dc159e8d +size 122609 diff --git a/slides/images/attacker_interface.pdf b/slides/images/attacker_interface.pdf new file mode 100644 index 0000000..1f027e0 --- /dev/null +++ b/slides/images/attacker_interface.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa446d3565407c170d66869ea4688dbc6e097736a604ce7f3744774fb1ca1908 +size 97970 diff --git a/slides/images/attacker_interface_prog.pdf b/slides/images/attacker_interface_prog.pdf new file mode 100644 index 0000000..9e259ac --- /dev/null +++ b/slides/images/attacker_interface_prog.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bdb3e6663a087c1b48fc605d45bda13843a86e45db387bde098a276d807c79d0 +size 192779 diff --git a/slides/images/aub_white.png b/slides/images/aub_white.png new file mode 100644 index 0000000..0d75bbd --- /dev/null +++ b/slides/images/aub_white.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d135e51b23db455ad7fee5713adc239ae7c6b11f5e42c84fc2b62b85281f3d2a +size 378436 diff --git a/slides/images/battleship.jpg b/slides/images/battleship.jpg new file mode 100644 index 0000000..e8576c3 --- /dev/null +++ b/slides/images/battleship.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb10e6750d4e20edee9e401ab26c8b5fe0d31c0e311ff01bf2f48197494309d5 +size 117950 diff --git a/slides/images/block_cipher_modes.png b/slides/images/block_cipher_modes.png new file mode 100644 index 0000000..c572855 --- /dev/null +++ b/slides/images/block_cipher_modes.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9aa3ebe12006a231d08b4c0315ea57fbb1fc4a2d60ac4a5f9d34031e741f1063 +size 122713 diff --git a/slides/images/caesar.png b/slides/images/caesar.png new file mode 100644 index 0000000..04d6e0e --- /dev/null +++ b/slides/images/caesar.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5efabb8ee73dcd00911a28669059b6559ed726761579a2503e8b68d1918a55e5 +size 77155 diff --git a/slides/images/cbc_with_dec.pdf b/slides/images/cbc_with_dec.pdf new file mode 100644 index 0000000..c3b27c1 --- /dev/null +++ b/slides/images/cbc_with_dec.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:738082b115cedac35b41b514e0540698253d36c10d53256705f7d40e660ee550 +size 123126 diff --git a/slides/images/cedar.jpg b/slides/images/cedar.jpg new file mode 100644 index 0000000..4667afc --- /dev/null +++ b/slides/images/cedar.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae7443e6b6b9c42638968154156bcae4303d0b13ebf2aafb4ef99f82fd594913 +size 849349 diff --git a/slides/images/clock_13.jpg b/slides/images/clock_13.jpg new file mode 100644 index 0000000..6e0f180 --- /dev/null +++ b/slides/images/clock_13.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de2dfe2e746c177297d80ed61cb28ce948d84edd7d68243616365c99cca271eb +size 126590 diff --git a/slides/images/complexity.png b/slides/images/complexity.png new file mode 100644 index 0000000..63a2b94 --- /dev/null +++ b/slides/images/complexity.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4d3f70825abf14482946afb108092229c2b9ed2b360b337a7ca0a5459aadac7 +size 120053 diff --git a/slides/images/ctr_dec.pdf b/slides/images/ctr_dec.pdf new file mode 100644 index 0000000..ac180d3 --- /dev/null +++ b/slides/images/ctr_dec.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d2bf2d06e8d67a86302ab7cc21642158e2e0362f19d1a9a7b2124d490c4257f +size 83539 diff --git a/slides/images/ctr_dec_delta.pdf b/slides/images/ctr_dec_delta.pdf new file mode 100644 index 0000000..cca380d --- /dev/null +++ b/slides/images/ctr_dec_delta.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:087169b70d0f8feffa841782ab62cadfa0ef690c9069d01ef70a8ee2f07ab9da +size 91592 diff --git a/slides/images/ctr_with_dec.pdf b/slides/images/ctr_with_dec.pdf new file mode 100644 index 0000000..9cbdee7 --- /dev/null +++ b/slides/images/ctr_with_dec.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:98fab760caac946bde8b0458a1cfd11788db942f00f8c55ccecdaea58a896496 +size 118707 diff --git a/slides/images/deep_crack_a.jpg b/slides/images/deep_crack_a.jpg new file mode 100644 index 0000000..89a1e6c --- /dev/null +++ b/slides/images/deep_crack_a.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4fa8c9a4dc3b1ff3b48eb99571e062f601d9cbef3364f2ed06e09162ccf122de +size 579480 diff --git a/slides/images/deep_crack_b.jpg b/slides/images/deep_crack_b.jpg new file mode 100644 index 0000000..aa27e01 --- /dev/null +++ b/slides/images/deep_crack_b.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7c6524277367fdfd49fe883c91ada56ebdc8e54a697161c4ab9f20daa140bc7 +size 55478 diff --git a/slides/images/dh.png b/slides/images/dh.png new file mode 100644 index 0000000..122a0dc --- /dev/null +++ b/slides/images/dh.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:659b0c59f285ab5636b386a0e1e917049882e7f3d312bee7b475972335d949fb +size 1006966 diff --git a/slides/images/djb.jpg b/slides/images/djb.jpg new file mode 100644 index 0000000..0ad3d47 --- /dev/null +++ b/slides/images/djb.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0ed11816aff43499cff488ce1af5ecec7db46604048324dc16f14d8227bdb4d +size 689671 diff --git a/slides/images/elliptic_curve_add.png b/slides/images/elliptic_curve_add.png new file mode 100644 index 0000000..0f1227b --- /dev/null +++ b/slides/images/elliptic_curve_add.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1683ef9f7c2928525fbaf42e2727859049fbec36acc4dd1693675adb0b40c1ae +size 92435 diff --git a/slides/images/elliptic_curve_double.png b/slides/images/elliptic_curve_double.png new file mode 100644 index 0000000..2f0bd9e --- /dev/null +++ b/slides/images/elliptic_curve_double.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5cc05debc8674c58308177c42b2e170039c7f3d5b9a9c0772a5480fe7f7a0814 +size 123964 diff --git a/slides/images/elliptic_curve_integers.png b/slides/images/elliptic_curve_integers.png new file mode 100644 index 0000000..ba96e69 --- /dev/null +++ b/slides/images/elliptic_curve_integers.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:401e5c9829da6b89a40bf18b059486d9f02558ada9a0674a6c0d3f6be8ac526a +size 191064 diff --git a/slides/images/elliptic_curve_real.png b/slides/images/elliptic_curve_real.png new file mode 100644 index 0000000..0181c11 --- /dev/null +++ b/slides/images/elliptic_curve_real.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ade6f868124fa9b62de3906a75979b7145605045cbb5013369575e31c900ee67 +size 81032 diff --git a/slides/images/export_1.jpg b/slides/images/export_1.jpg new file mode 100644 index 0000000..b239388 --- /dev/null +++ b/slides/images/export_1.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0bb1b1f21f1aeb55019a22893dcf3462dfb023f0b48e367dc07ff76bf555e20 +size 10028 diff --git a/slides/images/export_2.jpg b/slides/images/export_2.jpg new file mode 100644 index 0000000..1e55b6f --- /dev/null +++ b/slides/images/export_2.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc0d58122151b4891b7215077c7ef176f71078c84148c9a9ab6cdda7141fe0f4 +size 54083 diff --git a/slides/images/export_3.jpg b/slides/images/export_3.jpg new file mode 100644 index 0000000..98a7091 --- /dev/null +++ b/slides/images/export_3.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee26be1feaf8b53f7ab7559e6cda3cd29f8d8ca1c5fa5cb2c250556714543490 +size 215235 diff --git a/slides/images/feistel_cipher.pdf b/slides/images/feistel_cipher.pdf new file mode 100644 index 0000000..5e3e9ff --- /dev/null +++ b/slides/images/feistel_cipher.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13322ad7f4528e095566ca3f0b1819b19ae64aa5ace91604e0952ea6a8f6ad34 +size 85740 diff --git a/slides/images/feistel_cipher_inv.pdf b/slides/images/feistel_cipher_inv.pdf new file mode 100644 index 0000000..af485f8 --- /dev/null +++ b/slides/images/feistel_cipher_inv.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:274fe32241f546e2866c30dbed31b01690a3885da09125d9da81e7f5524b76a8 +size 92701 diff --git a/slides/images/fischer.png b/slides/images/fischer.png new file mode 100644 index 0000000..c7b162c --- /dev/null +++ b/slides/images/fischer.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0e7554cdf312ed963f2950a8de521a6ae06767cd61b2d72257ea8db3332d308 +size 192817 diff --git a/slides/images/fischer_sectioned.png b/slides/images/fischer_sectioned.png new file mode 100644 index 0000000..16099cd --- /dev/null +++ b/slides/images/fischer_sectioned.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c8147c7726d575a3bdf5cfd13102c0b70e5b559d1fcc4967cda5d2275c3041c +size 393306 diff --git a/slides/images/fischer_theory.png b/slides/images/fischer_theory.png new file mode 100644 index 0000000..81bd6e3 --- /dev/null +++ b/slides/images/fischer_theory.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:774c1fee292a2f6da657ef8c2af9217b7f061cfab85eebd2dc0a77fd9e66a9b5 +size 376946 diff --git a/slides/images/fischer_tls_13_bubbles.png b/slides/images/fischer_tls_13_bubbles.png new file mode 100644 index 0000000..58b9778 --- /dev/null +++ b/slides/images/fischer_tls_13_bubbles.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1dfd4a230365507b61d4d2eae0c907afa97eb9414f97406d40c35094914a3115 +size 759266 diff --git a/slides/images/gcm.pdf b/slides/images/gcm.pdf new file mode 100644 index 0000000..a6dff4e --- /dev/null +++ b/slides/images/gcm.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd6d13480ae8b07ca76f8f90685ae5bf40dcf8ca8e3d16254e77dcaed195fb84 +size 106231 diff --git a/slides/images/gpu_farm.jpg b/slides/images/gpu_farm.jpg new file mode 100644 index 0000000..040c0eb --- /dev/null +++ b/slides/images/gpu_farm.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ad5dc2585cafbefc18635e1be25a02ae06fc5e36f5b6805c020502a5f25f5b1 +size 312388 diff --git a/slides/images/keyed_enc.pdf b/slides/images/keyed_enc.pdf new file mode 100644 index 0000000..d0e9d81 --- /dev/null +++ b/slides/images/keyed_enc.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5bf0bd4daba789d1ad10e6c6b4162cf321245ec109da4663edf8ef69a9b5c0e3 +size 118533 diff --git a/slides/images/letsencrypt_certs.png b/slides/images/letsencrypt_certs.png new file mode 100644 index 0000000..8d4049d --- /dev/null +++ b/slides/images/letsencrypt_certs.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6bc3fad45013428d9e794f4b5ddab3cca1659017498844eec5d470fb2009b647 +size 129225 diff --git a/slides/images/letsencrypt_https.png b/slides/images/letsencrypt_https.png new file mode 100644 index 0000000..a615dc4 --- /dev/null +++ b/slides/images/letsencrypt_https.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:edc6c5695efac0768206425330395eff4c20a9e53895c446960aca4f6527fefc +size 171287 diff --git a/slides/images/letsencrypt_issuance.png b/slides/images/letsencrypt_issuance.png new file mode 100644 index 0000000..4cff0fc --- /dev/null +++ b/slides/images/letsencrypt_issuance.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ddd9b9041fca14d835c7272a4e9aef3ec34ecb1efdd4c703f22ecbb8c361a10 +size 120686 diff --git a/slides/images/logjam_1.png b/slides/images/logjam_1.png new file mode 100644 index 0000000..bde3070 --- /dev/null +++ b/slides/images/logjam_1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c3337c8c8fa206c81b54d7c0f494e77a3e9e81611bdf0af5500a6a4290d6288 +size 171965 diff --git a/slides/images/logjam_2.png b/slides/images/logjam_2.png new file mode 100644 index 0000000..2999bfc --- /dev/null +++ b/slides/images/logjam_2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c86adef30fd409bd73ab005d25120bb55470bc87ce538242e404ec4fd1098660 +size 311735 diff --git a/slides/images/logjam_3.png b/slides/images/logjam_3.png new file mode 100644 index 0000000..ed6f5d4 --- /dev/null +++ b/slides/images/logjam_3.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:312d183f01f95876f83a96c02570d4ab3f8076339c5a2aa1c475024cb2ce9444 +size 1313098 diff --git a/slides/images/merkle_damgard.pdf b/slides/images/merkle_damgard.pdf new file mode 100644 index 0000000..73bcfdf --- /dev/null +++ b/slides/images/merkle_damgard.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cf991fa17bdceb0a5e45b20aa538cdbcc453f842c0d488a9c367267fe8453e6d +size 112116 diff --git a/slides/images/naive_enc.pdf b/slides/images/naive_enc.pdf new file mode 100644 index 0000000..5d29cb2 --- /dev/null +++ b/slides/images/naive_enc.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f91b46052ea07d7dc064857da7e94b712784f8a390c3c2ec1f7227186384ebbe +size 117312 diff --git a/slides/images/nist_peanut.png b/slides/images/nist_peanut.png new file mode 100644 index 0000000..1562691 --- /dev/null +++ b/slides/images/nist_peanut.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce95d9fa460c5d4bb7f2f2341b622418a69a2993da55d8d189005b39400817bf +size 278994 diff --git a/slides/images/noelle_spamton.png b/slides/images/noelle_spamton.png new file mode 100644 index 0000000..1faad62 --- /dev/null +++ b/slides/images/noelle_spamton.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff6e76bb275b7d4adf53a663c94b7218aa832332db60fd04bb6783b5651fbdc8 +size 1747235 diff --git a/slides/images/oracle_painting_zoom.jpg b/slides/images/oracle_painting_zoom.jpg new file mode 100644 index 0000000..0d8f2e9 --- /dev/null +++ b/slides/images/oracle_painting_zoom.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88c3e126a482351cd15b965aa8533b74d8b4837e9e107b997c67cc935347c352 +size 482293 diff --git a/slides/images/persistence_of_memory.jpg b/slides/images/persistence_of_memory.jpg new file mode 100644 index 0000000..db7f4f0 --- /dev/null +++ b/slides/images/persistence_of_memory.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa0787736eeae116244a5c84eaf275163f2b70e039330b3f58981c3e299a3959 +size 488762 diff --git a/slides/images/pgp_keyserver.png b/slides/images/pgp_keyserver.png new file mode 100644 index 0000000..b60316e --- /dev/null +++ b/slides/images/pgp_keyserver.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f598dc674ef590ead76c331b1cbebf1b24d24af24415e66bda074d268f43383c +size 516077 diff --git a/slides/images/pgp_pubkey.png b/slides/images/pgp_pubkey.png new file mode 100644 index 0000000..1294843 --- /dev/null +++ b/slides/images/pgp_pubkey.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:131705f174e7802872330069ef2d22d406ecd846bf6e1a9d4b519b074c669418 +size 1139154 diff --git a/slides/images/pidgin_chat.jpg b/slides/images/pidgin_chat.jpg new file mode 100644 index 0000000..34ee681 --- /dev/null +++ b/slides/images/pidgin_chat.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7481be2ac9051f22151b8bd608cc07d37501fddc28a7ee70bf3b7534a34489d7 +size 31588 diff --git a/slides/images/pidgin_otr.jpg b/slides/images/pidgin_otr.jpg new file mode 100644 index 0000000..274610c --- /dev/null +++ b/slides/images/pidgin_otr.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9fec288fd11fda3ccaee9f65977b22d0e0c6275e83c4333bf94ef4a1c98eb5fe +size 160126 diff --git a/slides/images/prf_enc_2.pdf b/slides/images/prf_enc_2.pdf new file mode 100644 index 0000000..c8a1baa --- /dev/null +++ b/slides/images/prf_enc_2.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce43aabad4fae45cbfbcb232a32f2738f39dca07ac7c41eb90d1b5fddd22e960 +size 122319 diff --git a/slides/images/prf_enc_malleable.pdf b/slides/images/prf_enc_malleable.pdf new file mode 100644 index 0000000..fdaa95b --- /dev/null +++ b/slides/images/prf_enc_malleable.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ca50821c0dc42cbb2f8ad041ec5f4215e3d1465e4b6b7861865a339eeec1a0e9 +size 126353 diff --git a/slides/images/prg_distributions.pdf b/slides/images/prg_distributions.pdf new file mode 100644 index 0000000..2193196 --- /dev/null +++ b/slides/images/prg_distributions.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b2a45f587eaf65b7354948c1b89022de7c81964bfc26f1589a2c4c20808d933 +size 108168 diff --git a/slides/images/qiao.png b/slides/images/qiao.png new file mode 100644 index 0000000..a2d0cac --- /dev/null +++ b/slides/images/qiao.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90ee3d4632c50df773a67b2692a957235bab475f12558c4339934ddf1bb0bba7 +size 179187 diff --git a/slides/images/rc4_bias.png b/slides/images/rc4_bias.png new file mode 100644 index 0000000..f8cacfa --- /dev/null +++ b/slides/images/rc4_bias.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7d87eb46845e3c70686d33ebe6191dc6edd0a0ecb06c8128301699b5c8b77837 +size 792894 diff --git a/slides/images/rc4_prga_py.png b/slides/images/rc4_prga_py.png new file mode 100644 index 0000000..eb1aa80 --- /dev/null +++ b/slides/images/rc4_prga_py.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6d1e0a6cae3fb521b168c568ea8ccb68314259ae36cd04c00ea24b5b1d5c632 +size 60881 diff --git a/slides/images/safecurves.png b/slides/images/safecurves.png new file mode 100644 index 0000000..c155daa --- /dev/null +++ b/slides/images/safecurves.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec3580517ee98189dda816eb0c9ca78d79e1e92551c2730921e9e099dde182cf +size 285854 diff --git a/slides/images/sha2.png b/slides/images/sha2.png new file mode 100644 index 0000000..f78d98a --- /dev/null +++ b/slides/images/sha2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4e08f131de33395e2a6a5dcad08ffa010486e455c57959bc5d4ff8eb1000440 +size 70561 diff --git a/slides/images/sigma_test.png b/slides/images/sigma_test.png new file mode 100644 index 0000000..89a4785 --- /dev/null +++ b/slides/images/sigma_test.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e6eb96b3c5db7e163f8c4ae5f7de8f6513e1a475502a15653fdde6fe4bd66e05 +size 132926 diff --git a/slides/images/signal.jpg b/slides/images/signal.jpg new file mode 100644 index 0000000..2f58b7e --- /dev/null +++ b/slides/images/signal.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6327e9d15b3fc3d5e1a9e43b7454e536f814bbee28a3512395f94b1c3790b91 +size 113927 diff --git a/slides/images/signal_verification.png b/slides/images/signal_verification.png new file mode 100644 index 0000000..d37c330 --- /dev/null +++ b/slides/images/signal_verification.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f40121781259cd93a5f666bdb73d71495808dc2aa092e28a129b083fb26cf1f +size 62301 diff --git a/slides/images/sponge.png b/slides/images/sponge.png new file mode 100644 index 0000000..6921677 --- /dev/null +++ b/slides/images/sponge.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:741243e1b0658c9ad847770ee747f5557b635c2d275f4e1470be71cd8b21e7bc +size 41845 diff --git a/slides/images/tls_13_handshake.png b/slides/images/tls_13_handshake.png new file mode 100644 index 0000000..7d8ba61 --- /dev/null +++ b/slides/images/tls_13_handshake.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9f35d2528b97935b675cb0cad8ab9db205f2a7518c15292f8a043995bce6f18 +size 203618 diff --git a/slides/images/tls_13_sketch.png b/slides/images/tls_13_sketch.png new file mode 100644 index 0000000..625e755 --- /dev/null +++ b/slides/images/tls_13_sketch.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d29bf7a4924c7136e549b6c79f0352abe1c4dc7ed34f38e702c46f51b0c69174 +size 34678 diff --git a/slides/images/tls_attacks_timeline_2015.png b/slides/images/tls_attacks_timeline_2015.png new file mode 100644 index 0000000..c18f7b7 --- /dev/null +++ b/slides/images/tls_attacks_timeline_2015.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1042d1c883dbcc283e1df39c01452b272ff466eb586a8a3029ce72eddcb77721 +size 109603 diff --git a/slides/images/tls_borat.jpg b/slides/images/tls_borat.jpg new file mode 100644 index 0000000..e74b62f --- /dev/null +++ b/slides/images/tls_borat.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c6688d2e13ae6192c46f84ba7a0a5584c82e3ec8376fc8d1443347d3f59f58be +size 141583 diff --git a/slides/images/tls_collision.png b/slides/images/tls_collision.png new file mode 100644 index 0000000..758b94e --- /dev/null +++ b/slides/images/tls_collision.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56fbb3c2f1777eeceb239cdd0618e9fc0f05e80c35fff45d112532ee3d9f821c +size 359376 diff --git a/slides/images/tls_freak.png b/slides/images/tls_freak.png new file mode 100644 index 0000000..b79f8d4 --- /dev/null +++ b/slides/images/tls_freak.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c2414311ccee51de2888b5ec64889553183fff3ea1002326dbc92b0cb143b4b7 +size 175855 diff --git a/slides/images/tls_handshake.png b/slides/images/tls_handshake.png new file mode 100644 index 0000000..cea7b88 --- /dev/null +++ b/slides/images/tls_handshake.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3dea420e07eb2263c204b3cb23ecc0d5d09c7c11d408cc0bb610a93828d151c1 +size 269315 diff --git a/slides/images/tls_illustrated.png b/slides/images/tls_illustrated.png new file mode 100644 index 0000000..aceb96f --- /dev/null +++ b/slides/images/tls_illustrated.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88bc669dda2fd4ccb6fc07c69d698331892c1ba7edaa446d682924f68baaa576 +size 200236 diff --git a/slides/images/tls_smack.png b/slides/images/tls_smack.png new file mode 100644 index 0000000..22b36ad --- /dev/null +++ b/slides/images/tls_smack.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7e1216541c81ce19acb924bd36b84e3a3f7a44ea5197161b583b8c174ff55be +size 127319 diff --git a/slides/images/tux_encrypted_ctr.png b/slides/images/tux_encrypted_ctr.png new file mode 100644 index 0000000..714d6aa --- /dev/null +++ b/slides/images/tux_encrypted_ctr.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6043ff47124d578526bcc5f4d87752ff10f38d776aeeee5d21163780d0d42e7c +size 2655510 diff --git a/slides/images/tux_encrypted_ecb.png b/slides/images/tux_encrypted_ecb.png new file mode 100644 index 0000000..0b1e1d6 --- /dev/null +++ b/slides/images/tux_encrypted_ecb.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1405a6034e0f7c1645c0ab1ddfa2365564ee34b46ea57534f02c8e691a6b7797 +size 635965 diff --git a/slides/images/tux_plaintext.png b/slides/images/tux_plaintext.png new file mode 100644 index 0000000..c658b77 --- /dev/null +++ b/slides/images/tux_plaintext.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:263174c721da5e98df34544c7799d179fbae045c9c9d4bcf4d56202d44abb52a +size 165187 diff --git a/slides/images/vigenere.png b/slides/images/vigenere.png new file mode 100644 index 0000000..609f266 --- /dev/null +++ b/slides/images/vigenere.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bacd5371c4d92f080af66d290a6eb006f5fc2c5c35379fd5f8c819a6bae16fe2 +size 79124 diff --git a/slides/images/xor_dec.png b/slides/images/xor_dec.png new file mode 100644 index 0000000..eace6b2 --- /dev/null +++ b/slides/images/xor_dec.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8fdb5aadce8329c2d6eecd6fdbbb381b4e7567c2f3ef6feadef5ad9bf0e4c23c +size 38074 diff --git a/slides/images/xor_enc.png b/slides/images/xor_enc.png new file mode 100644 index 0000000..9618ed6 --- /dev/null +++ b/slides/images/xor_enc.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2591f282474b66c235df3c12a4b7e1e0279cb6aab4857fcfecfc316e5d8ea872 +size 37565 diff --git a/slides/images/yoda_meme.jpg b/slides/images/yoda_meme.jpg new file mode 100644 index 0000000..a17e90d --- /dev/null +++ b/slides/images/yoda_meme.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ddbb53ff0a6683793eebc44dc420c3c9304a6f23a47d9ace63e9efe8f4b383fe +size 69918 diff --git a/slides/theme/beamercolorthemecipher.sty b/slides/theme/beamercolorthemecipher.sty new file mode 100644 index 0000000..66ffa59 --- /dev/null +++ b/slides/theme/beamercolorthemecipher.sty @@ -0,0 +1,58 @@ +\ProvidesPackage{theme/beamercolorthemecipher}[2025/05/04 v1.0 Cipher Beamer Theme] + +% Define the color palette +\definecolor{cipherprimary}{HTML}{2C5E1A} +\definecolor{cipherprimarydark}{HTML}{1E3E12} +\definecolor{ciphersecondary}{HTML}{4A9C31} +\definecolor{cipheraccent}{HTML}{8CB369} +\definecolor{cipherdark}{HTML}{1A2C0D} +\definecolor{cipherlight}{HTML}{F6F9F1} +\definecolor{ciphergray}{HTML}{E8F0DF} +\definecolor{ciphergraydark}{HTML}{CAD9B7} +\definecolor{cipherwhite}{HTML}{FFFFFF} +\definecolor{cipherdarkbg}{HTML}{040903} +\definecolor{hlbg}{HTML}{F5F5A4} +\colorlet{hlfg}{black} + +% Basic colors +\setbeamercolor{background canvas}{bg=cipherlight} +\setbeamercolor{normal text}{fg=cipherdark, bg=cipherlight} +\setbeamercolor{alerted text}{fg=cipherprimary} +\setbeamercolor{example text}{fg=ciphersecondary} + +% Title page +\setbeamercolor{title}{fg=cipherdark} +\setbeamercolor{subtitle}{fg=cipheraccent} +\setbeamercolor{author}{fg=cipherdark} +\setbeamercolor{date}{fg=cipherdark} +\setbeamercolor{cover website}{fg=cipherwhite} +\setbeamercolor{cover text}{fg=cipherwhite} +\setbeamercolor{title}{fg=cipherwhite} +\setbeamercolor{subtitle}{fg=cipheraccent} +\setbeamercolor{author}{fg=cipherwhite} +\setbeamercolor{institute}{fg=cipherwhite} +\setbeamercolor{part name}{fg=cipherwhite} +\setbeamercolor{topic name}{fg=cipherwhite} +\setbeamercolor{cover footer}{fg=cipherwhite, bg=cipherprimarydark} + +% Structure elements +\setbeamercolor{structure}{fg=cipherprimary} +\setbeamercolor{frametitle}{fg=cipherdark, bg=} +\setbeamercolor{framesubtitle}{fg=cipheraccent, bg=} + +% Blocks +\setbeamercolor{block title}{fg=cipherwhite, bg=cipherprimary} +\setbeamercolor{block body}{fg=cipherdark, bg=ciphergray} +\setbeamercolor{block title alerted}{fg=cipherwhite, bg=cipherprimarydark} +\setbeamercolor{block body alerted}{fg=cipherdark, bg=ciphergraydark} +\setbeamercolor{block title example}{fg=cipherwhite, bg=ciphersecondary} +\setbeamercolor{block body example}{fg=cipherdark, bg=ciphergray} + +% Items +\setbeamercolor{item}{fg=cipherprimary} +\setbeamercolor{itemize item}{fg=cipherprimary} +\setbeamercolor{itemize subitem}{fg=ciphersecondary} +\setbeamercolor{itemize subsubitem}{fg=cipheraccent} + +% Footline +\setbeamercolor{footline}{fg=cipherdark} diff --git a/slides/theme/beamerfontthemecipher.sty b/slides/theme/beamerfontthemecipher.sty new file mode 100644 index 0000000..3722e8a --- /dev/null +++ b/slides/theme/beamerfontthemecipher.sty @@ -0,0 +1,29 @@ +\ProvidesPackage{theme/beamerfontthemecipher}[2025/05/04 v1.0 Cipher Beamer Theme] + +\RequirePackage{../../misc/fonts/fonts} +\renewcommand{\familydefault}{\sfdefault} + +% Slightly increase line spacing throughout the presentation +\linespread{1.05}\selectfont + +% Frame title fonts +\setbeamerfont{frametitle}{family=\sffamily, size=\LARGE, series=\bfseries} +\setbeamerfont{framesubtitle}{family=\sffamily, size=\Large, series=\mdseries} + +% Caption fonts +\setbeamerfont{caption}{family=\sffamily, size=\tiny} + +% Footline fonts +\setbeamerfont{footline}{family=\ttfamily, size=\tiny} + +% Footnote fonts +\setbeamerfont{footnote}{size=\tiny} +\setbeamerfont{footnote mark}{size=\tiny} + +% Cover slide specific fonts +\setbeamerfont{title}{family=\sffamily, size=\LARGE} +\setbeamerfont{subtitle}{family=\ttfamily, size=\large} +\setbeamerfont{part name}{family=\ttfamily, size=\scriptsize} +\setbeamerfont{topic name}{family=\sffamily, size=\large} +\setbeamerfont{cover website}{family=\ttfamily, size=\small} +\setbeamerfont{author}{family=\sffamily, size=\small} diff --git a/slides/theme/beamerinnerthemecipher.sty b/slides/theme/beamerinnerthemecipher.sty new file mode 100644 index 0000000..6447a36 --- /dev/null +++ b/slides/theme/beamerinnerthemecipher.sty @@ -0,0 +1,191 @@ +\ProvidesPackage{theme/beamerinnerthemecipher}[2025/05/04 v1.0 Cipher Beamer Theme] + +% Cover slide (title page with logo and image) +\defbeamertemplate*{title page}{cipher}{ + % Background + \begin{tikzpicture}[remember picture, overlay] + \fill[cipherdarkbg] (current page.north west) rectangle (current page.south east); + \draw[cipheraccent, line width=3pt] + (current page.north west) rectangle (current page.south east); + \end{tikzpicture} + + % University logo + \begin{tikzpicture}[remember picture, overlay] + \node[anchor=north west, inner sep=0pt] at ([shift={(0.95cm,-0.6cm)}]current page.north west) { + \includegraphics[height=1.6cm]{\insertinstituteimage} + }; + \end{tikzpicture} + + % Grid layout for cover slide + \vspace{1cm} + \begin{columns}[c,onlytextwidth] + % Left column - image + \begin{column}{0.45\textwidth} + \begin{beamercolorbox}[center]{cover text} + \begin{tikzpicture} + \node[inner sep=0pt] { + \includegraphics[width=\textwidth, height=1\textwidth, keepaspectratio]{images/cedar.jpg} + }; + \draw[white, line width=1mm] + (current bounding box.south west) rectangle (current bounding box.north east); + \end{tikzpicture} + \end{beamercolorbox} + \end{column} + + % Right column - text + \begin{column}{0.6\textwidth} + \begin{beamercolorbox}[wd=\textwidth, leftskip=1.3cm]{title} + \usebeamerfont{title}\usebeamercolor[fg]{title}\inserttitle\par + \vskip0cm + \usebeamercolor[fg]{subtitle}\usebeamerfont{subtitle}\insertcoversubtitle\par + \vskip0.3cm + \usebeamercolor[fg]{part name}\usebeamerfont{part name}\insertcoverpartname\par + \vskip0cm + \usebeamercolor[fg]{topic name}\usebeamerfont{topic name}\insertcovertopicname\par + \vskip0.3cm + \usebeamercolor[fg]{author}\usebeamerfont{author}\insertauthor\par + \vskip0cm + \usebeamercolor[fg]{cover website}\usebeamerfont{cover website}\url{\insertcoverwebsite}\par + \end{beamercolorbox} + \end{column} + \end{columns} +} + +\setbeamertemplate{itemize items}[circle] +\setbeamertemplate{enumerate items}[default] +\setbeamertemplate{section in toc}[circle] +\beamertemplatenavigationsymbolsempty + +\AtBeginSection[]{ + \begin{frame}[plain] + \begin{tikzpicture}[remember picture, overlay] + \fill[cipherdarkbg] (current page.north west) rectangle (current page.south east); + \draw[cipheraccent, line width=2pt] (current page.north west) rectangle (current page.south east); + \end{tikzpicture} + + \vspace{2cm} + \begin{center} + \begin{minipage}{0.9\textwidth} + \raggedright + {\usebeamercolor[fg]{subtitle}\usebeamerfont{subtitle}\Large Section \thesection} + + \vspace{0.5cm} + {\usebeamercolor[fg]{title}\usebeamerfont{title}\fontsize{20}{24}\selectfont\insertsectionhead\par} + \end{minipage} + + \vspace{1cm} + \begin{tikzpicture} + \draw[cipheraccent, line width=3pt] (0,0) -- (8,0); + \end{tikzpicture} + \end{center} + \end{frame} +} + +\AtBeginSubsection[]{ + \begin{frame}[plain] + \begin{tikzpicture}[remember picture, overlay] + \fill[cipherdarkbg!90] (current page.north west) rectangle (current page.south east); + \draw[cipheraccent, line width=1.5pt] (current page.north west) rectangle (current page.south east); + \end{tikzpicture} + + \vspace{2cm} + \begin{center} + \begin{minipage}{0.9\textwidth} + \raggedright + {\usebeamercolor[fg]{subtitle}\usebeamerfont{subtitle}Section \thesection: \insertsectionhead}\\[2.5em] + {\usebeamercolor[fg]{subtitle}\usebeamerfont{subtitle}\Large Subsection \thesection.\thesubsection}\\[0.2em] + {\usebeamercolor[fg]{title}\usebeamerfont{title}\fontsize{18}{22}\selectfont\insertsubsectionhead\par} + \end{minipage} + + \vspace{1cm} + \begin{tikzpicture} + \draw[cipheraccent, line width=2.5pt] (0,0) -- (6,0); + \end{tikzpicture} + \end{center} + \end{frame} +} + +% Custom commands +\newcommand{\coversubtitle}[1]{\def\insertcoversubtitle{#1}} +\newcommand{\covertopicname}[1]{\def\insertcovertopicname{#1}} +\newcommand{\coverpartname}[1]{\def\insertcoverpartname{#1}} +\newcommand{\coverwebsite}[1]{\def\insertcoverwebsite{#1}} +\newcommand{\instituteimage}[1]{\def\insertinstituteimage{#1}} + +\newcommand{\definitionbox}[2]{% + \begin{tcolorbox}[ + enhanced, + colback=cipherprimary!5!cipherlight, + colframe=cipherprimary, + colbacktitle=cipherprimary!40!white, + title=#1, + fonttitle=\bfseries\sffamily, + boxrule=0.4mm, + arc=2mm, + left=3mm,right=3mm,top=3mm,bottom=3mm, + drop shadow={opacity=0.1}, + sharp corners=southeast, + fontupper=\fontsize{9.5pt}{11pt}\selectfont + ] + #2 + \end{tcolorbox} +} + +\newcommand{\alertbox}[2]{% + \begin{tcolorbox}[ + enhanced, + colback=red!5!cipherlight, + colframe=red!70!black, + colbacktitle=red!30!white, + title=#1, + fonttitle=\bfseries\sffamily, + boxrule=0.4mm, + arc=2mm, + left=3mm,right=3mm,top=3mm,bottom=3mm, + drop shadow={opacity=0.1}, + sharp corners=southeast, + fontupper=\fontsize{9.5pt}{11pt}\selectfont + ] + #2 + \end{tcolorbox} +} + +% Nicely formatted image with caption +\newcommand{\imagewithcaption}[3][0.9\textwidth]{ + \begin{center} + \begin{tikzpicture} + \hspace{-1mm} + \node[fill=white, anchor=center, inner sep=1mm]{ + \includegraphics[width=#1, height=0.6\textheight, keepaspectratio]{images/#2} + }; + \node[fit=(current bounding box), inner sep=0.5mm, draw=white, line width=0.5mm] {}; + \end{tikzpicture} + \vspace{0.5em} + \begin{minipage}{0.7\textwidth} + \centering + \usebeamerfont{caption}#3 + \end{minipage} + \end{center} +} + +% Nicely formatted image with caption (big) +\newcommand{\bigimagewithcaption}[3][1\textwidth]{ + \begin{center} + \vspace{-0.5cm} + \begin{tikzpicture} + \hspace{-1mm} + \node[fill=white, anchor=center, inner sep=1mm]{ + \includegraphics[width=#1, height=0.75\textheight, keepaspectratio]{images/#2} + }; + \node[fit=(current bounding box), inner sep=0.5mm, draw=white, line width=0.5mm] {}; + \end{tikzpicture} + \vspace{0.3em} + \begin{minipage}{0.8\textwidth} + \centering + \usebeamerfont{caption}#3 + \end{minipage} + \end{center} +} + +\newcommand\fstar{\textsf{F}\ensuremath{^\star}\xspace} +\newcommand\haclstar{\textsf{HACL}\ensuremath{^\star}\xspace} diff --git a/slides/theme/beamerouterthemecipher.sty b/slides/theme/beamerouterthemecipher.sty new file mode 100644 index 0000000..850fe78 --- /dev/null +++ b/slides/theme/beamerouterthemecipher.sty @@ -0,0 +1,29 @@ +\ProvidesPackage{theme/beamerouterthemecipher}[2025/05/04 v1.0 Cipher Beamer Theme] + +% Frame title +\defbeamertemplate*{frametitle}{cipher}{ + \begin{beamercolorbox}[wd=\paperwidth,sep=0.5cm]{frametitle} + \usebeamerfont{frametitle}\insertframetitle\par% + \ifx\insertframesubtitle\@empty\else% + {\usebeamerfont{framesubtitle}\usebeamercolor[fg]{framesubtitle}\insertframesubtitle\par}% + \fi% + \end{beamercolorbox} +} + +% Footline (only shown when not cover slide) +\defbeamertemplate*{footline}{cipher}{ + \ifnum\c@framenumber=1\else + \begin{beamercolorbox}[ht=2.5ex,dp=1.125ex,leftskip=0.3cm,rightskip=0.3cm]{footline} + \usebeamerfont{footline}\color{footline.fg!50}\inserttitle\ - \insertinstitute\hfill\insertframenumber\,/\,\inserttotalframenumber + \end{beamercolorbox} + \fi +} + +% Background - can be used to add a subtle border matching the theme +\defbeamertemplate*{background}{cipher}{ + \begin{tikzpicture}[remember picture, overlay] + % Add a subtle border to all slides + \draw[cipheraccent, line width=3pt] + (current page.north west) rectangle (current page.south east); + \end{tikzpicture} +} diff --git a/slides/theme/beamerthemecipher.sty b/slides/theme/beamerthemecipher.sty new file mode 100644 index 0000000..90597df --- /dev/null +++ b/slides/theme/beamerthemecipher.sty @@ -0,0 +1,22 @@ +\ProvidesPackage{theme/beamerthemecipher}[2025/05/04 v1.0 Cipher Beamer Theme] + +% Load required packages +\RequirePackage{ + mathtools,fontspec,unicode-math, + amsmath,amsthm,amssymb,amsfonts,graphicx,setspace,cancel, + etoolbox,hyperref,xstring,fancybox,xspace,titlecaps +} +\RequirePackage{microtype} + +% TikZ libraries +\RequirePackage{tikz} +\RequirePackage{pgfplots} +\pgfplotsset{compat=1.18} + +% Load dependent themes +\usecolortheme{cipher} +\usefonttheme{cipher} +\useinnertheme{cipher} +\useoutertheme{cipher} +\RequirePackage{../../misc/macros/joc} +\RequirePackage{../../misc/macros/msc5} diff --git a/syllabus/Makefile b/syllabus/Makefile new file mode 100644 index 0000000..dcf0d27 --- /dev/null +++ b/syllabus/Makefile @@ -0,0 +1,2 @@ +syllabus: + @export SOURCE_DATE_EPOCH=1700000000 && tectonic -o ../website "syllabus.tex" diff --git a/syllabus/README.md b/syllabus/README.md new file mode 100644 index 0000000..80c77da --- /dev/null +++ b/syllabus/README.md @@ -0,0 +1,5 @@ +# Syllabus + +This folder contains the course syllabus. + +Practically speaking, the [course website](https://appliedcryptography.page) may serve as a more accessible resource giving an overview of the course. diff --git a/syllabus/syllabus.tex b/syllabus/syllabus.tex new file mode 100755 index 0000000..055f263 --- /dev/null +++ b/syllabus/syllabus.tex @@ -0,0 +1,149 @@ +\documentclass[10pt,a4paper,american]{article} +\newcommand{\aublogopath}{../website/res/img/aub_black.png} +\usepackage{../misc/macros/joc} +\usepackage{../misc/fonts/fonts} +\usepackage{../misc/macros/classhandout} + +\begin{document} + +\classhandoutheader + +\urldef{\urlcodeofconduct}\url{https://www.aub.edu.lb/SAO/Documents/student%20code%20of%20conduct.pdf} + +\section*{Course Syllabus} +\textit{Applied Cryptography} explores the core theory of modern cryptography and how to apply these fundamental principles to build and analyze real-world secure systems. We start with foundational concepts—such as Kerckhoff's Principle, computational hardness, and provable security—before moving on to key cryptographic primitives like pseudorandom generators, block ciphers, and hash functions. Building on this solid groundwork, we will survey how these technologies power critical real-world deployments such as TLS, secure messaging protocols (e.g., Signal), and post-quantum cryptography. We will also delve into specialized topics like high-assurance cryptographic implementations, elliptic-curve-based systems, and zero-knowledge proofs to give you a complete understanding of contemporary cryptography's scope and impact. By the end of the semester, you will have gained both a rigorous theoretical perspective and practical hands-on experience, enabling you to evaluate, design, and implement cryptographic solutions. + +\section{Course Objectives \& Outcomes} +This course is designed to bridge the theoretical foundations of cryptography with its practical applications in contemporary secure systems. By engaging with lectures, lab sessions, problem sets, and project work, you will develop a thorough understanding of modern cryptographic concepts and gain the hands-on skills needed to implement, assess, and communicate security solutions. + +Upon successful completion of this course, a student should be able to: + +\begin{itemize} + \item Understand the reasoning behind the mathematical underpinnings of modern cryptography. + \item Analyze and prove the security properties of cryptographic constructions. + \item Understand how cryptographic constructions can be composed to build secure protocols and systems. + \item Discern between how cryptography is approached mathematically versus from an engineering perspective. + \item Critically assess security implementations and evaluate real-world cryptographic protocols. + \item Gain an understanding about the future of cryptography and its role in emerging technologies. +\end{itemize} + +\section{Course Prerequisites} +This course is intended for \textbf{senior undergraduate} students. \textbf{Graduate students} are also welcome to register provided that they are working on a research topic that is relevant to this course. The following prerequisites are \textbf{optional but recommended}: + +\begin{itemize} + \item \textbf{CMPS 215:} Theory of Computation +\end{itemize} + +If you want to understand whether you have the sufficient background for this course, review this revision chapter and try to do all the exercises: \url{https://joyofcryptography.com/pdf/chap0.pdf} + +\section{Materials} +\begin{itemize} + \item Mike Rosulek, {\href{https://joyofcryptography.com}{\textit{The Joy of Cryptography}}}, Oregon State University, 2021.\footnote{\textit{The Joy of Cryptography} is available free of charge at \url{https://joyofcryptography.com}.} + \item Handouts will be made available during the course and on the course website. +\end{itemize} + +\section{Course Schedule} +The course schedule is available on the course website, where it is always kept up-to-date, including details about the lecture topics, materials and easy access to slides: \url{https://appliedcryptography.page} + +\section{Assessment Items \& Grading Criteria} +In this course, your performance will be evaluated through multiple components designed to measure both your theoretical understanding and your practical skills in cryptography. By staying current with the readings, attending and participating in lectures and lab sessions, and completing all assigned work, you will gain a thorough mastery of the material. + +Overall, these graded components are designed to ensure that you not only grasp the theoretical underpinnings of cryptography but also develop the practical expertise needed to implement, analyze, and innovate within the field. + +\subsection{This Is Your Classroom} +An essential facet in this course's design is encouraging students to produce work that is entirely theirs, without resorting to AI technologies. This ensures that students are embracing their full learning potential and makes grading more fair throughout the classroom. As such, the class sessions and lab sessions will favor \textbf{engagement}: + +\begin{itemize} + \item \textbf{Interactive lectures:} Classes will incorporate interactive elements such as in-class exercises, discussions, and collaborative problem-solving to encourage active participation. + \item \textbf{Real-time feedback:} Students will regularly have opportunities to demonstrate their understanding through low-stakes activities, receiving immediate feedback to guide their learning. + \item \textbf{Peer teaching:} Students will occasionally be invited to explain concepts to their peers, reinforcing their own understanding while creating a collaborative learning environment. + \item \textbf{Lab progress discussions:} Students will be encouraged to openly discuss their progress on lab projects as they work, allowing for real-time problem-solving and knowledge sharing. + \item \textbf{Security strategy workshops:} During lab sessions, students will present their approaches to implementing security goals, receiving feedback from peers and instructors to refine their solutions. + \item \textbf{Collaborative troubleshooting:} Labs will incorporate structured time for students to collectively address challenges, fostering a community where security insights and implementation techniques are freely exchanged. +\end{itemize} + +\subsection{Problem Sets} +Problem sets will be assigned periodically throughout the semester to reinforce and deepen your understanding of the lecture material. Each set will include a range of exercises—some focused on theoretical proofs and problem-solving, others requiring short coding tasks or computational experiments. These assignments are designed to bridge the gap between abstract cryptographic concepts and their concrete applications. You are encouraged to start working on each problem set early and to seek guidance during office hours or lab sessions if you encounter difficulties. + +\subsection{Lab Sessions} +Weekly lab sessions will be held to serve as a hands-on complement to the lectures. During each lab, you will experiment with real-world libraries, and even simulate attacks or vulnerabilities to understand why certain security practices are necessary. These sessions will also help you become comfortable with relevant tools and environments, including formal analysis tools. Attendance is mandatory, and lab participation will be graded based on preparedness, engagement, and the successful completion of in-lab activities. Labs offer an excellent opportunity for collaborative problem-solving and immediate feedback on your work. + +Example lab sessions include: + +\begin{itemize} + \item \textbf{Zero-Knowledge Battleship:} Build a secure battleship game that uses zero-knowledge proofs to verify that the server is reporting ship hits honestly without revealing the entire board layout. This lab explores ZKP implementations and demonstrates their power in creating trustworthy interactive applications. + \item \textbf{Cryptographic Protocol Reverse Engineering:} Analyze real-world mobile applications to identify how they implement cryptographic protocols, discover potential vulnerabilities, and understand how protocol design flaws can lead to security breaches. + \item \textbf{Breaking Cloud Storage Encryption:} Investigate current research into vulnerabilities in cloud storage encryption protocols. Implement proof-of-concept attacks in a controlled environment and propose mitigations for the discovered vulnerabilities. + \item \textbf{Implementation of Secure Messaging Protocols:} Implement a simplified version of the Signal Protocol for secure messaging, focusing on the Double Ratchet algorithm and how it provides forward secrecy and post-compromise security. + \item \textbf{Side-Channel Attack Workshop:} Perform practical timing and power analysis attacks against basic cryptographic implementations to understand the importance of constant-time algorithms and other side-channel mitigations. + \item \textbf{Post-Quantum Cryptography Evaluation:} Compare and test different post-quantum cryptographic algorithms, analyzing their performance, security margins, and implementation challenges. + \item \textbf{Formal Verification with Verifpal, Progressing to Tamarin:} Model cryptographic protocols first using Verifpal as a learning tool and then progressing towards mature tools such as Tamarin, automatically verifying their security properties, learning how formal methods can discover subtle vulnerabilities that manual review might miss. +\end{itemize} + +Lab participation will be graded based on preparedness, engagement, demonstrated understanding during checkpoints, and the successful completion of in-lab activities. + +\subsection{Exams} +There will be a midterm exam and a comprehensive final exam. The exams will test your command of topics discussed throughout the semester. You are expected to come to each exam prepared, having thoroughly reviewed lecture notes, and lab material. + +\subsection{Grading Breakdown} +The final course grade will be computed using the following breakdown: + +\begin{center} + \renewcommand{\arraystretch}{2} + \begin{tabular}{|p{2.5in}|c|} + \hline + \textbf{Category} & \textbf{Percentage} \\ + \hline + Attendance \& Participation & $10\%$ \\ + \hline + Problem Sets & $10\%$ \\ + \hline + Lab Sessions \& Projects & $30\%$ \\ + \hline + Midterm Exam & $25\%$ \\ + \hline + Final Exam & $25\%$ \\ + \hline + \end{tabular} +\end{center} + +\section{Course Policies} +Students are expected to strictly observe the following course policies: + +\subsection{Attendance} +\textbf{Do not register for this course if you do not plan to attend all classes, labs, and exams.} You are expected to abide by the university's rules on attendance. You are expected to attend lectures and to be on time for all sessions and activities related to this course. Lectures are a sequence. Missing one lecture will almost certainly mean that you will not be able to keep up with the following lectures without studying the material covered in the missed lecture. Catching up with missed lectures is your responsibility and is done on your own time. You are responsible for all work, even when absent. Attendance may be recorded at every class session. Excessive absence will not be tolerated and will result in being dropped from the course. + +\subsection{Academic Misconduct \& Plagiarism} +Lectures and labs start on time. You may not be allowed to come into the room or lab once class has started. Any class conduct that disturbs the learning atmosphere may be deemed misbehavior and will not be tolerated. + +This course has a strict \textbf{zero tolerance policy for cheating}. Any instance of cheating will result in an immediate, non-negotiable grade of 0 on the pertinent assignment and a report to the university faculty: +\begin{itemize} + \item Your work has to be your own. No copying work (or rewriting it line by line based on someone else's work) will be tolerated. + \item Any sharing of any answers on any assignment is considered cheating. + \item Coaching another student by helping them writing their answers line by line is also cheating. + \item Copying answers or code from the Internet or hiring someone to write your answers for you is cheating. +\end{itemize} + +Explaining how to use systems or tools and helping others with high-level design issues is not cheating. + +\textbf{Regarding AI Tools:} Any use of AI tools to produce answers to class assignments or lab projects is considered cheating. +\begin{itemize} + \item Using AI tools like ChatGPT, GitHub Copilot, or similar to generate code, proofs, or written answers constitutes cheating. + \item Submitting AI-generated work without proper attribution and explanation is considered plagiarism. + \item The course will employ AI-detection tools and manual review techniques to identify AI-generated submissions. + \item Using AI to enhance your learning experience (e.g. asking ChatGPT questions about the material) is not considered cheating. +\end{itemize} + +The Student Code of Conduct\footnote{\urlcodeofconduct} acts as the main reference in determining instances of misconduct. + +\subsection{Communication Policy} +You are requested to check your e-mail and the course website regularly. You are responsible for all the information communicated to you via these tools. \textbf{Bookmark the course website and visit it regularly. All course news will be kept up to date on the website.} + +\section{Note for Special Needs Students} +AUB strives to make learning experiences as accessible as possible. If you anticipate or experience academic barriers due to a disability (including mental health, chronic or temporary medical conditions), please inform the course instructor immediately so that we can privately discuss options. In order to help establish reasonable accommodations and facilitate a smooth accommodations process, you are encouraged to contact the Accessible Education Office: \href{mailto:accessibility@aub.edu.lb}{accessibility@aub.edu.lb}; +961-1-350000, x3246; West Hall, 314. + +\section{Nondiscrimination} +AUB is committed to facilitating a campus free of all forms of discrimination including sex/gender-based harassment prohibited by Title IX. The University's non-discrimination policy applies to, and protects, all students, faculty, and staff. If you think you have experienced discrimination or harassment, including sexual misconduct, we encourage you to tell someone promptly. If you speak to a faculty or staff member about an issue such as harassment, sexual violence, or discrimination, the information will be kept as private as possible, however, faculty and designated staff are required to bring it to the attention of the University's Title IX Coordinator. Faculty can refer you to fully confidential resources, and you can find information and contacts at \url{https://www.aub.edu.lb/titleix}. To report an incident, contact the University's Title IX Coordinator Trudi Hodges at 01-350000 ext. 2514, or +\href{mailto:titleix@aub.edu.lb}{titleix@aub.edu.lb}. An anonymous report may be submitted online via EthicsPoint at \url{https://www.aub.ethicspoint.com}. + +\end{document} diff --git a/website/error.html b/website/error.html new file mode 100644 index 0000000..3742583 --- /dev/null +++ b/website/error.html @@ -0,0 +1,15 @@ + + + + + + + + Try Again + + + + Try Again + + + \ No newline at end of file diff --git a/website/favicon.ico b/website/favicon.ico new file mode 100644 index 0000000..e404cb5 --- /dev/null +++ b/website/favicon.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:381d527337b855a57aa11ff839a110dbe28a1805d2037e86cfcc67eea0fd5bcc +size 16958 diff --git a/website/index.html b/website/index.html new file mode 100755 index 0000000..17119db --- /dev/null +++ b/website/index.html @@ -0,0 +1,728 @@ + + + + + + Applied Cryptography (CMPS 297AD/396AI) — American University of Beirut + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

Applied Cryptography

+

American University of Beirut

+
CMPS 297AD/396AI
+
+
+ +
+
+
+

Welcome

+
+
+

+ Welcome to the website for the Applied Cryptography course at the American University of Beirut! This page serves as a unified and self-sufficient source of truth on everything concerning your course. +

+

+ Bookmark this website for the duration of the course and visit it regularly. All course news will be kept up to date on this website. +

+

+ Last updated: Loading... +

+
+ +
+

Course Description

+

Applied Cryptography explores the core theory of modern cryptography and how to apply these fundamental principles to build and analyze real-world secure systems. We start with foundational concepts—such as Kerckhoff's Principle, computational hardness, and provable security—before moving on to key cryptographic primitives like pseudorandom generators, block ciphers, and hash functions. Building on this solid groundwork, we will survey how these technologies power critical real-world deployments such as TLS, secure messaging protocols (e.g., Signal), and post-quantum cryptography. We will also delve into specialized topics like high-assurance cryptographic implementations, elliptic-curve-based systems, and zero-knowledge proofs to give you a complete understanding of contemporary cryptography's scope and impact. By the end of the semester, you will have gained both a rigorous theoretical perspective and practical hands-on experience, enabling you to evaluate, design, and implement cryptographic solutions.

+
+ +
+

Note: This website is an informal resource, and not a substitute for the AUB learning management system.

+
+ +
+
+

Course Dates & Times

+
+
    +
  • Lecture Times: Tuesdays and Thursdays, 12:30 to 13:45
  • +
  • Lecture Location: Nicely Hall, Room 320
  • +
  • Lab Times: I don't know yet
  • +
  • Lab Location: I don't know yet
  • +
  • Term Dates: August 25th until December 13th, 2025.
  • +
  • Instructor's Email: cmps-297ad-396ai@nadim.email
  • +
  • Office Hours: Email me to make an appointment.
  • +
+
+
+ +
+

Course Prerequisites

+
+

This course is intended for senior undergraduate students. Graduate students are also welcome to register provided that they are working on a research topic that is relevant to this course. The following prerequisites are optional but recommended:

+
    +
  • CMPS 215: Theory of Computation
  • +
+

If you want to understand whether you have the sufficient background for this course, review this revision chapter and try to do all the exercises.

+
+
+
+ +
+

Important Links

+ +
+
+ +
+
+

News

+
+
+ May 28th, 2025 +

Part 1 materials are complete!

+

The course plan, readings, slides, problem sets and lab session proposals for Part 1 of the course are now all complete and available on this website!

+

Things may change during the semester as Part 1 is being taught, but the course is beginning to take real shape, and the materials should at the very least be able to provide prospective students with an idea of what to expect. Also, the course schedule for Part 2 now looks much more mature and substantial, and will likely only change minimally as the course is developed.

+
+
+
+

Older News

+ +
+
+

Older news entries are kept for the academic year for archival purposes.

+
+ May 1st, 2025 +

We have a course number!

+

I'm excited to announce that our course has been officially assigned the course numbers CMPS 297AD (undergraduate) and CMPS 396AI (graduate). Please use these numbers when registering for the class through the university system.

+

Please note that this website is still very much under construction! I'm not even set on the course schedule yet. Everything isn't final. Some things could be outright wrong. Feedback welcome.

+
+
+
+
+ +
+
+

Materials

+
+ +

+ Every lecture will be accompanied by outside readings that expand on what is discussed in class or present the same material in a different way. Neither the readings nor the lectures are a replacement for each other; deeply understanding the material will likely require attendance as well as reading. It is possible to read before or after class, depending on your learning style. +

+

+ Aside from the textbooks and materials, students will also require their own personal computer for various parts of this course. Linux, Mac and Windows computers are all suitable. +

+ +
+

Textbook

+
+
+ + The Joy of Cryptography book cover + +
+

The Joy of Cryptography

+

Oregon State University, 2021

+

Mike Rosulek

+

Required. This textbook is the primary resource for our course and is available free of charge online.

+

Note: For this course, we will be using an updated edition of the textbook that is not yet released to the public. Professor Rosulek has been gracious enough to grant us access in advance — access will be shared privately with students during the course.

+
+
+
+
+ +
+
+

Online Readings

+ +
+
+

+ Online readings provide essential supplementary material that expands on specific cryptographic concepts, vulnerabilities, and practical implementations discussed throughout the course. +

+
+ +
+
+
+ +
+
+

Interactive Learning Tools

+ +
+
+

+ Interactive learning tools provide hands-on learning experiences that help reinforce cryptographic concepts through visualization, simulation, and practical application in ways that complement traditional reading materials. +

+
+
    +
  • ASecuritySite.com: Tons of informal resources regarding many different encryption schemes and protocols.
  • +
  • Visual One-Time Pad: An interactive tool for understanding the one-time pad encryption algorithm.
  • +
  • Rijndael Cipher: animation explaining AES's internal structure.
  • +
  • Verifpal: Cryptographic protocol analysis for students and engineers.
  • +
  • ProofFrog: Tool for verifying cryptographic proofs written in the style of The Joy of Cryptography.
  • +
  • Noise Explorer: an online engine for reasoning about Noise Protocol Framework Handshake Patterns.
  • +
  • The New Illustrated TLS Connection: Every byte of a TLS connection explained and reproduced.
  • +
  • More to be added soon!
  • +
+
+
+
+
+ +
+
+

Syllabus and Course Schedule

+
+ +
+

+ A PDF copy of the Fall 2025 syllabus is available. +

+
+ +
+
+

Part 1: Provable Security

+ +
+
+

+ Part 1 explores the theoretical underpinnings of modern cryptography through the lens of provable security. Starting with introductory concepts and perfect secrecy in the one-time pad, we progressively build a rigorous framework for understanding and analyzing cryptographic primitives. We examine fundamental building blocks like pseudorandom generators, functions, and permutations, then advance to encryption schemes secure against increasingly powerful adversaries—from passive eavesdroppers to active attackers who can manipulate ciphertexts. The section also covers essential cryptographic tools including collision-resistant hash functions, digital signatures, and key exchange protocols. Throughout these topics, we emphasize formal security definitions, reduction proofs, and the connections between theoretical security guarantees and practical implementations. By the end of this section, students will have developed a comprehensive understanding of provable security techniques that form the foundation for analyzing and designing secure cryptographic systems. +

+ +
+ Slides + Topic 1.1 +

Introduction

+

This introduction establishes the foundation for the entire course by covering the scope, objectives, and structure of applied cryptography. We'll discuss key themes that will recur throughout the semester, including the balance between theory and practice, the importance of formal security definitions, and the evolution of cryptographic thinking. Students will gain a clear understanding of what to expect from the course and how the various topics connect to form a coherent framework for secure system design.

+
+
Required Readings
+
    +
  • The Joy of Cryptography, Chapter 0: Review of Concepts & Notation.
  • +
+
+
+ +
+ Slides + Topic 1.2 +

One-Time Pad & The Provable Security Mindset

+

This topic introduces the concept of perfect secrecy through the One-Time Pad (OTP) encryption system and explores its mathematical proof of unconditional security. While theoretically unbreakable, we'll examine the severe practical limitations that make OTP challenging to deploy in real-world systems, including key generation, distribution, and management problems. The topic then transitions to Kerckhoff's fundamental principle—that a cryptosystem should remain secure even if everything about the system, except the key, is public knowledge. We'll discuss how this principle has shaped modern cryptographic design philosophy and why security through obscurity fails as a long-term strategy for protecting sensitive information.

+
+
Required Readings
+
    +
  • The Joy of Cryptography, Chapter 0: Review of Concepts & Notation.
  • +
  • The Joy of Cryptography, Chapter 1: One-Time Pad & The Provable Security Mindset.
  • +
+
+
+ +
+ Slides + Topic 1.3 +

Provable Security & Computational Cryptography

+

This topic begins by delving into the rigorous mathematical frameworks that allow cryptographers to provide formal security guarantees for cryptographic schemes. We'll examine how precise definitions of security properties create a foundation for meaningful analysis, and explore various adversarial models that capture different threat scenarios. The concept of reduction—proving that breaking a scheme is at least as hard as solving some well-studied mathematical problem—will be thoroughly explored. We then transition to modern computational cryptography, moving from unconditional security to a more practical approach where security is defined against computationally bounded adversaries. Students will learn about indistinguishability as a fundamental security concept, the bad-event technique for security proofs, and birthday probabilities in cryptographic attacks. The session provides essential mathematical foundations for understanding modern cryptographic security, including quantitative intuition about large numbers (like 2128) and tiny probabilities (like 2-80) that define practical security boundaries, preparing students for subsequent topics in pseudorandomness.

+
+
Required Readings
+
    +
  • The Joy of Cryptography, Chapter 2: Rudiments of Provable Security.
  • +
  • The Joy of Cryptography, Chapter 4: Modern Computational Cryptography.
  • +
+
+
+ +
+ Slides + Topic 1.4 +

Pseudorandomness

+

This topic explores three fundamental pseudorandom primitives that enable practical cryptography. Pseudorandom generators (PRGs) solve one-time pad's key length limitation by expanding short seeds into longer outputs indistinguishable from random. Pseudorandom functions (PRFs) extend this by creating massive virtual dictionaries mapping inputs to pseudorandom outputs, allowing parties with a shared secret to derive unlimited pseudorandom data. Pseudorandom permutations (PRPs), also called block ciphers, provide both forward and inverse operations indistinguishable from random permutations. We'll examine key constructions including GGM (building PRFs from PRGs), the Feistel network (building invertible PRPs from non-invertible PRFs), and the PRF-PRP switching lemma that enables interchangeability in security proofs. Throughout, we'll emphasize crucial security principles like the PRF "Golden Rule" of preventing input repetition.

+
+
Required Readings
+
    +
  • The Joy of Cryptography, Chapter 5: Pseudorandom Generators.
  • +
  • The Joy of Cryptography, Chapter 6: Pseudorandom Functions.
  • +
  • The Joy of Cryptography, Chapter 7: Pseudorandom Permutations.
  • +
+
Optional Readings
+ +
+
+ +
+ Slides + Topic 1.5 +

Chosen-Plaintext & Chosen-Ciphertext Attacks

+

This topic explores advanced security models for symmetric-key encryption, beginning with chosen-plaintext attack (CPA) security, where ciphertexts must be indistinguishable from random strings. We'll examine why deterministic encryption cannot achieve this security level and explore solutions including randomized PRF-based schemes and block cipher modes like CBC and CTR, while explaining why ECB mode remains fundamentally insecure. The topic then advances to chosen-ciphertext attacks (CCA), where adversaries can decrypt chosen ciphertexts, demonstrating how even CPA-secure schemes like CTR mode remain vulnerable due to their malleability. We'll analyze practical format-oracle attacks that exploit information leakage during decryption to recover entire plaintexts, and examine how preventing adversaries from creating valid modified ciphertexts is essential for achieving comprehensive CCA security in real-world systems.

+
+
Required Readings
+
    +
  • The Joy of Cryptography, Chapter 8: Chosen-Plaintext Attacks.
  • +
  • The Joy of Cryptography, Chapter 9: Chosen-Ciphertext Attacks.
  • +
+
Optional Readings
+ +
+
+ +
+ Slides + Topic 1.6 +

Collision-Resistant Hash Functions

+

This topic explores collision-resistant hash functions, cryptographic primitives that convert arbitrary-length inputs to fixed-length outputs while making it computationally infeasible to find colliding inputs. We'll examine three essential properties—collision resistance, preimage resistance, and second preimage resistance—while exploring practical applications in password storage, data integrity verification, and proof-of-work systems. The topic introduces the counterintuitive birthday paradox, demonstrating why collisions can be found after approximately square-root-many attempts rather than brute force. We'll survey hash function evolution from broken algorithms like MD5 and SHA-1 to modern standards like SHA-2, SHA-3, and BLAKE3, while analyzing vulnerabilities including precomputation attacks using rainbow tables and length extension weaknesses in Merkle–Damgård constructions. The topic covers critical defensive techniques including properly salting hashes and implementing specialized password hashing algorithms like PBKDF2 and memory-hard functions such as Scrypt, which resist hardware acceleration attacks by requiring significant memory resources, providing comprehensive guidance for secure hash function implementation in real-world systems.

+
+
Required Readings
+
    +
  • The Joy of Cryptography, Chapter 10: Collision-Resistant Hash Functions.
  • +
  • The Joy of Cryptography, Chapter 12: Random Oracles and Other Idealized Models.
  • +
+
Optional Readings
+ +
+
+
+ Slides + Topic 1.7 +

Hard Problems & Diffie-Hellman

+

This topic explores computational hardness problems that form the cornerstone of modern public-key cryptography, with particular focus on the discrete logarithm problem that underpins Diffie-Hellman key exchange. We'll examine how complexity theory provides a framework for classifying problems based on their computational difficulty, covering fundamental complexity classes including P, NP, and the famous unsolved P vs. NP problem. The topic then investigates the discrete logarithm problem in detail, analyzing its computational complexity and known algorithms, before exploring how this hard problem enables the revolutionary Diffie-Hellman protocol that allows two parties to establish a shared secret over an insecure channel. We'll examine the mathematical foundations of DH using modular exponentiation in prime fields, the computational hardness assumptions (CDH and DDH) that underpin its security, and protocol variants including anonymous and authenticated DH. The topic concludes by analyzing practical implementation considerations, security pitfalls, and how theoretical hardness assumptions translate into real-world cryptographic security.

+
+
Required Readings
+
    +
  • Jean-Philippe Aumasson, Serious Cryptography, 2nd Edition. Chapter 9: Hard Problems, No Starch Press, 2024.
  • +
  • Jean-Philippe Aumasson, Serious Cryptography, 2nd Edition. Chapter 11: Diffie-Hellman, No Starch Press, 2024.
  • +
+
Optional Readings
+ +
+
+ +
+ Slides + Topic 1.8 +

Elliptic Curves & Digital Signatures

+

This topic explores elliptic curve cryptography (ECC), an approach that provides stronger security with smaller keys than traditional cryptosystems like RSA. We'll examine the mathematical foundations of elliptic curves and their group structure supporting point addition and scalar multiplication operations. The topic covers the elliptic curve discrete logarithm problem (ECDLP) that underpins ECC's security, and how it enables efficient implementations of key exchange (ECDH) and digital signatures (ECDSA and EdDSA/Ed25519). We'll analyze the advantages of ECC, including faster signing operations and significantly shorter keys and signatures compared to RSA, while examining critical implementation considerations that affect security. The topic concludes with guidance on selecting appropriate curves, comparing standardized options like NIST curves and Curve25519, and exploring potential vulnerabilities including invalid curve attacks, randomness failures, and interoperability challenges in modern ECC deployments.

+
+
Required Readings
+
    +
  • Jean-Philippe Aumasson, Serious Cryptography, 2nd Edition. Chapter 12: Elliptic Curves, No Starch Press, 2024.
  • +
+
Optional Readings
+ +
+
+
+
+ +
+
+

Part 2: Real-World Cryptography

+ +
+
+

+ Part 2 shifts from theoretical foundations to practical applications, examining how cryptographic principles are implemented in real-world systems. We begin with secure messaging protocols that provide forward secrecy and post-compromise security through ratcheting mechanisms, then explore authenticated key exchange protocols that secure communications against active adversaries. The section covers advanced concepts like zero-knowledge proofs that enable proving knowledge without revealing secrets, and post-quantum cryptography designed to resist attacks from quantum computers. We examine critical infrastructure protocols like TLS that secure internet communications, cloud security applications of cryptography, and analyze significant cryptographic failures to extract valuable design lessons. The course then investigates formal verification and high-assurance implementations that provide mathematical guarantees of security, specialized cryptography in cryptocurrencies, secure multiparty computation enabling joint computation without revealing inputs, and privacy-preserving technologies that protect sensitive information while enabling useful computation. By connecting theoretical foundations to practical systems, students will develop the knowledge needed to evaluate, implement, and design secure cryptographic solutions for complex real-world environments. +

+ +
+ Slides + Topic 2.1 +

Transport Layer Security

+

This topic examines the Transport Layer Security (TLS) protocol, the backbone of secure communication on the internet that secures billions of connections daily. We'll explore the evolution from SSL to modern TLS 1.3, analyzing the protocol architecture, handshake process, and the cryptographic primitives deployed at each stage. The session covers key exchange mechanisms, authentication methods, and the cipher suites that provide confidentiality and integrity protections. Students will learn about certificate validation, trust models, and the public key infrastructure (PKI) that underpins TLS security. We'll also investigate significant vulnerabilities that have affected TLS implementations throughout its history, including FREAK, Logjam, Heartbleed, and POODLE, analyzing how these vulnerabilities arose and the mitigations developed in response. The topic concludes with practical deployment considerations, performance optimizations like session resumption and 0-RTT, and the security trade-offs encountered when configuring TLS in production environments.

+
+
Required Readings
+
    +
  • Jean-Philippe Aumasson, Serious Cryptography, 2nd Edition. Chapter 13: TLS, No Starch Press, 2024.
  • +
+
Optional Readings
+ +
+
+ +
+ Slides + Topic 2.2 +

The Story of RC4

+

This topic presents a biographical narrative of RC4 (Rivest Cipher 4), tracing its remarkable journey from promising youth to eventual downfall in cryptographic history. We'll examine RC4's birth as a proprietary stream cipher at RSA Security in 1987, its meteoric rise to become the most widely deployed stream cipher in the world, and its golden era powering protocols like WEP, SSL, and TLS due to its simplicity and performance advantages. The topic then chronicles RC4's gradual decline as researchers uncovered a series of increasingly devastating weaknesses, starting with the 2001 Fluhrer-Mantin-Shamir attack on WEP, through the 2013 discovery of extensive biases in RC4-generated keystreams that enabled practical attacks against TLS, culminating in the 2015 "Bar Mitzvah" and RC4 NOMORE attacks that could recover passwords and other sensitive information from encrypted connections. We'll analyze how the security community responded to these revelations, including browser vendors' gradual restriction of RC4 ciphersuites and the IETF's eventual formal prohibition of RC4 in TLS in 2015, while drawing broader lessons about cryptographic lifecycle management, the importance of formal security analysis, and how the story of RC4 exemplifies both the evolution of cryptanalytic techniques and the challenges of maintaining backward compatibility in security protocols.

+
+
Required Readings
+
    +
  • None.
  • +
+
Optional Readings
+ +
+
+ +
+ Slides + Topic 2.3 +

Secure Messaging

+

This topic traces the evolution of secure messaging from early failures to modern protocols, examining how cryptographic innovation has shaped private communication. We begin with PGP's usability challenges and fundamental limitations, understanding why "Johnny Can't Encrypt" despite decades of effort. The topic then explores Off-the-Record (OTR) messaging's revolutionary features—forward secrecy through ephemeral keys, deniable authentication via MACs instead of signatures, and automatic key exchange—demonstrating how synchronous protocols solved many of PGP's problems. We dive deep into authenticated key exchange protocols like SIGMA, examining how they prevent man-in-the-middle attacks while maintaining identity protection. The discussion covers proper key derivation functions (HKDF) for deriving multiple keys from shared secrets, addressing the shortcomings of ad-hoc approaches. We then transition to Signal's asynchronous messaging architecture, analyzing X3DH key exchange and the Double Ratchet's elegant combination of symmetric and Diffie-Hellman ratcheting. The topic critically examines post-compromise security's promises versus reality, revealing through formal analysis why perfect healing is impossible in practical systems that must handle state loss. We also contrast Signal's approach with alternatives like Telegram's controversial design choices. Throughout, we'll analyze the fundamental trade-offs between security guarantees, usability, and real-world deployment constraints that shape how billions of messages are protected daily. We'll also examine modern extensions including secure group messaging protocols like MLS (Messaging Layer Security) that scale encrypted conversations to thousands of participants, and post-quantum secure messaging advances such as Apple's PQ3 and Signal's PQXDH that protect against future quantum attackers.

+
+
Required Readings
+
    +
  • The Joy of Cryptography, Chapter 17: Encrypted Messaging & Ratcheting.
  • +
  • More to be added soon!
  • +
+
Optional Readings
+ +
+
+ +
+ Slides + Topic 2.4 +

Applied Cryptography in Cloud Security

+

This topic explores how cryptographic principles and techniques are applied to secure cloud computing environments, focusing on the unique challenges of protecting data and applications in distributed, multi-tenant infrastructures. We'll examine key management strategies for distributed systems, including hierarchical key management, key rotation policies, and hardware security modules (HSMs) in cloud deployments. The topic covers confidential computing technologies that use hardware-based trusted execution environments and memory encryption to protect data in use. Students will learn about tokenization systems that replace sensitive data with non-sensitive equivalents, and encryption schemes optimized for cloud storage including convergent encryption and client-side encryption models. We'll investigate secret management at scale, analyzing secure vaults, dynamic credential generation, and secure secret distribution in containerized environments. The topic also explores cryptographic access control mechanisms like attribute-based encryption and practical implementations of end-to-end encryption in cloud services, examining how these technologies can maintain confidentiality even when the cloud provider itself isn't fully trusted.

+
+
Required Readings
+
    +
  • Mark Russinovich, Manuel Costa, Cédric Fournet, David Chisnall, Antoine Delignat-Lavaud, Sylvan Clebsch, Kapil Vaswani and Vikas Bhatia, Toward Confidential Cloud Computing, Communications of the ACM, 2021.
  • +
  • More to be added soon!
  • +
+
+
+ +
+ Slides + Topic 2.5 +

High-Assurance Cryptography

+

This topic examines methodologies for developing cryptographic implementations with high assurance of correctness and security, moving beyond traditional testing approaches to formal verification and rigorous proof techniques. We'll explore the spectrum of formal methods applied to cryptography, from lightweight verification using refinement types to comprehensive mathematical proofs of functional correctness and security properties. The topic covers verification frameworks and tools including F*, Coq, Lean, and ProVerif, examining how they can be applied to verify cryptographic implementations against their specifications and security definitions. Students will learn about verified cryptographic libraries like HACL*, EverCrypt, and initiatives from organizations like Cryspen that bring formal verification to practical cryptography. We'll also discuss the challenges in formally verifying cryptographic code, including the gap between mathematical specifications and efficient implementations, side-channel resistance verification, and performance considerations. The topic concludes with case studies of successful verification projects that have produced high-assurance cryptographic implementations deployed in critical systems.

+
+
Required Readings
+
    +
  • Manuel Barbosa, Gilles Barthe, Karthikeyan Bhargavan, Bruno Blanchet, Cas Cremers, Kevin Liao and Bryan Parno, SoK: Computer-Aided Cryptography, IEEE Symposium on Security and Privacy, 2021.
  • +
  • More to be added soon!
  • +
+
Optional Readings
+ +
+
+ +
+ Slides + Topic 2.6 +

Cryptocurrency Cryptography

+

This topic explores the cryptographic foundations of blockchain systems and cryptocurrencies, examining how traditional cryptographic primitives are combined in novel ways to create decentralized trust systems. We'll investigate the core components of blockchain protocols, including hash functions in proof-of-work mechanisms, digital signatures for transaction authentication, and Merkle trees for efficient verification. The topic covers the cryptographic aspects of Bitcoin, Ethereum, and other significant blockchain platforms, analyzing their security models, consensus mechanisms, and vulnerability mitigations. Students will learn about specialized cryptographic constructions in cryptocurrencies, including zero-knowledge proofs for privacy coins, threshold signatures for multi-signature wallets, and timelock puzzles for conditional transactions. We'll also discuss emerging cryptographic challenges in blockchain systems, including quantum resistance considerations, layer-2 scaling solutions with unique security properties, and the cryptographic foundations of newer consensus mechanisms like proof-of-stake that aim to address energy consumption concerns while maintaining security guarantees.

+
+
Required Readings
+
    +
  • Jean-Philippe Aumasson, Serious Cryptography, 2nd Edition. Chapter 15: Cryptocurrency Cryptography, No Starch Press, 2024.
  • +
+
+
+ +
+ Slides + Topic 2.7 +

Post-Quantum Cryptography

+

This topic explores post-quantum cryptography, which addresses the threat quantum computers pose to current cryptographic systems. We'll examine how quantum algorithms like Shor's can break widely-used public-key cryptography based on factoring and discrete logarithms, while Grover's algorithm reduces symmetric-key security by effectively halving key lengths. The topic introduces the Learning With Errors (LWE) problem as a foundation for post-quantum cryptography, explaining how its computational hardness against quantum attacks makes it suitable for building secure cryptographic primitives. We'll analyze practical LWE-based key exchange protocols that form the basis for NIST's standardized post-quantum schemes like ML-KEM. Students will understand both the theoretical foundation of quantum-resistant cryptography and the practical considerations for implementing these systems in real-world applications, preparing them for the transition to a post-quantum cryptographic landscape.

+
+
Required Readings
+
    +
  • The Joy of Cryptography, Chapter 20: Post-Quantum Cryptography.
  • +
+
Optional Readings
+ +
+
+ +
+ Slides + Topic 2.8 +

Zero-Knowledge Proofs

+

This topic explores zero-knowledge proofs, which enable proving possession of secret information without revealing anything about the secret itself. We'll examine how these interactive protocols can authenticate a party's identity while maintaining deniability—allowing someone to prove they know a private key without creating evidence that could later convince others. The topic begins with the Schnorr identification protocol, which demonstrates this paradoxical capability through a clever three-move interaction. We'll then generalize to sigma protocols, a powerful class of interactive proofs with completeness, special soundness, and honest-verifier zero-knowledge properties. The topic covers several practical examples, including proofs of discrete log equality and complex logical conditions using AND/OR compositions. Finally, we'll explore how interactive proofs can be transformed into non-interactive proofs and digital signatures through the Fiat-Shamir transformation, which replaces the verifier with a cryptographic hash function. This transformation creates powerful primitives like Schnorr signatures but necessarily sacrifices the deniability property that makes interactive zero-knowledge proofs unique.

+
+
Required Readings
+
    +
  • The Joy of Cryptography, Chapter 19: Zero-Knowledge Proofs.
  • +
+
Optional Readings
+ +
+
+ +
+ Slides + Topic 2.9 +

Secure Multiparty Computation

+

This topic explores Secure Multiparty Computation (MPC), a powerful cryptographic paradigm that enables multiple parties to jointly compute functions over their private inputs without revealing those inputs to each other. We'll examine the theoretical foundations of MPC, including feasibility results, security models, and the distinctions between semi-honest and malicious adversaries. The topic covers core MPC techniques including Yao's garbled circuits, secret sharing schemes like Shamir's threshold method, and oblivious transfer protocols that enable secure two-party computation. Students will learn about practical MPC frameworks and implementations such as SCALE-MAMBA, MP-SPDZ, and EMP-toolkit, analyzing their performance characteristics and security guarantees. We'll investigate applications of MPC across various domains, including private data analysis, secure auctions, privacy-preserving machine learning, and confidential financial systems. The topic also addresses performance optimizations like preprocessing, circuit minimization, and communication-efficient protocols that make MPC increasingly practical for real-world use. We'll conclude with case studies of deployed MPC systems, examining how these technologies overcome real-world implementation challenges to enable secure collaboration while maintaining strict privacy guarantees.

+
+
Required Readings
+ +
+
+ +
+ Slides + Topic 2.10 +

Creative Cryptography

+

This topic explores timelock encryption, a fascinating cryptographic innovation that enables messages to be encrypted such that they can only be decrypted after a predetermined time has elapsed. We'll examine both the theoretical foundations and practical implementation of timelock encryption using the League of Entropy, an existing threshold network that implements threshold BLS signatures within Boneh and Franklin's identity-based encryption (IBE) framework. The topic demonstrates how this network, which broadcasts BLS signatures for each time interval (round number), effectively functions as a decentralized key custodian that periodically publishes private keys for an IBE system where identities correspond to specific time periods. We'll analyze the elegant design that requires cryptographic operations only from encryptors and decryptors while allowing the threshold network to remain unmodified and unaware of the timelock functionality. Students will gain hands-on experience with an open-source implementation of this scheme and explore a production-ready web interface utilizing the League of Entropy's distributed randomness beacon service. This creative application of cryptography showcases how existing cryptographic primitives can be combined in innovative ways to enable entirely new functionalities, inspiring students to think beyond conventional applications as they develop their own cryptographic solutions.

+
+
Required Readings
+ +
+
+
+
+
+ +
+
+

Assignments & Lab Sessions

+
+ +
+

+ Check the Syllabus for detailed information on class grading criteria, as well as how lab sessions, problem sets and exams will be designed and presented. +

+
+ +
+
+

Problem Sets

+ +
+
+

Problem sets will be assigned periodically throughout the semester to reinforce and deepen your understanding of the lecture material. Each set will include a range of exercises—some focused on theoretical proofs and problem-solving, others requiring short coding tasks or computational experiments. These assignments are designed to bridge the gap between abstract cryptographic concepts and their concrete applications. You are encouraged to start working on each problem set early and to seek guidance during office hours or lab sessions if you encounter difficulties.

+ +
+

Problem Set 1: Provable Security Foundations

+

This problem set focuses on the fundamental concepts of provable security covered in the first three topics of the course. It consists of four main sections: Cryptographic Foundations, which tests your understanding of basic security goals and perfect secrecy; Provable Security, which explores library interchangeability and formal security proofs; Computational Cryptography, which examines computational security concepts, distinguishability, and the bad events technique; and Application of Cryptographic Principles, which challenges you to analyze block cipher modes, evaluate real-world implementations, and design secure protocols. The assignments blend theoretical analysis with practical applications, requiring you to demonstrate both mathematical reasoning and applied cryptographic thinking. A bonus challenge on the discrete logarithm problem offers extra credit for those wanting to explore advanced concepts.

+
+ +
+

Problem Set 2: Symmetric Cryptography

+

This problem set explores symmetric cryptography fundamentals covered in topics 1.4, 1.5 and 1.6, addressing four key areas: pseudorandomness, encryption security models, hash functions, and practical applications. In pseudorandomness, you'll analyze PRG constructions, PRF security requirements including the "Golden Rule," and Feistel cipher properties. The encryption security section examines why deterministic encryption fails CPA security, format oracle attacks against CPA-secure schemes, and authenticated encryption constructions including AES-GCM. The hash function component investigates collision resistance properties, construction methods like Merkle-Damgård versus Sponge, and specialized password hashing algorithms including memory-hard functions. Real-world case studies challenge you to apply these concepts to file storage systems, software update verification, and password management implementations.

+
+ +
+

Problem Set 3: Asymmetric Cryptography

+

This problem set covers concepts from topics 1.7 and 1.8 of the course, spanning three comprehensive areas: cryptographic hardness foundations, Diffie-Hellman security analysis, and elliptic curve implementation challenges. In cryptographic hardness, you'll analyze real-world implications of mathematical breakthroughs like P=NP and evaluate discrete logarithm security architectures including parameter selection and vulnerability assessment. The Diffie-Hellman section explores attack scenarios in hostile network environments, man-in-the-middle defenses, and protocol design challenges including SSH trust models. Elliptic curve security engineering examines curve selection controversies, invalid curve attacks, mobile performance optimization, and implementation vulnerabilities including side-channel attacks and nonce reuse scenarios. Finally, applied case studies challenge you to design complete key exchange protocols for secure messaging, analyze cryptocurrency signature scheme decisions, and architect enterprise-scale secure communication systems. Throughout, the assignments emphasize both mathematical security analysis and practical deployment considerations, requiring you to bridge theoretical cryptographic principles with real-world system design challenges.

+
+
+
+ +
+
+

Lab Sessions

+ +
+
+

Lab sessions will be held weekly to serve as a hands-on complement to the lectures. During each lab, you will experiment with real-world libraries, and even simulate attacks or vulnerabilities to understand why certain security practices are necessary. These sessions will also help you become comfortable with relevant tools and environments, including formal analysis tools. Attendance is mandatory, and lab participation will be graded based on preparedness, engagement, and the successful completion of in-lab activities. Labs offer an excellent opportunity for collaborative problem-solving and immediate feedback on your work.

+ +
+

Lab 1: Designing a Password Manager

+

In this lab, you will design and implement a secure password manager application. You'll learn about secure password storage techniques, key derivation functions, and encryption methods for sensitive data. The lab will guide you through implementing features such as master password protection, secure password generation, and encrypted storage. You'll also analyze potential vulnerabilities in your system and implement countermeasures to protect against common attacks like password cracking and memory scraping.

+
+ +
+

Lab 2: Designing a Secure Messenger

+

This lab focuses on building a secure messaging application implementing end-to-end encryption. You'll work with cryptographic libraries to implement key exchange protocols, message encryption, and authentication mechanisms. The lab covers essential features like perfect forward secrecy, deniability, and secure group messaging. You'll also explore practical challenges such as key verification, metadata protection, and secure key storage on devices. By the end of this lab, you'll understand the cryptographic foundations behind modern secure messaging platforms like Signal.

+
+ +
+

Lab 3: Protocol Modeling and Verification with Verifpal and Tamarin

+

This lab introduces formal verification of security protocols using two complementary tools: Verifpal and Tamarin. You'll begin with Verifpal, a user-friendly tool designed for students, to model and analyze custom authentication and key exchange protocols. After gaining proficiency in identifying protocol vulnerabilities, you'll advance to Tamarin Prover to perform more sophisticated analyses with temporal properties and unbounded verification. Throughout the lab, you'll apply these tools to real-world protocols like TLS 1.3 fragments and Signal's X3DH, gaining practical experience in formal security verification. By the end of this lab, you'll understand how formal methods can mathematically prove security properties and detect subtle flaws that might otherwise remain hidden in manual security reviews.

+
+ +
+

Lab 4: Designing a Battleship Game Using Zero-Knowledge Systems

+

In this creative lab, you'll implement the classic Battleship game with a cryptographic twist using zero-knowledge proofs. You'll learn how two mutually distrustful parties can play a fair game without revealing their ship placements except when a hit occurs. The lab will guide you through designing commitment schemes, validity proofs for ship placement, and secure mechanisms for torpedo shots and hit verification—all without requiring a trusted third party. This practical application of zero-knowledge techniques demonstrates how cryptography can enable secure computation between untrusting parties in a tangible, engaging context.

+
+ +
+

Propose your own lab session!

+

Take the opportunity to propose and develop your own cryptographic project based on your interests and the concepts covered in the course! You might implement a novel protocol, create a secure application, perform a cryptanalysis of an existing system, or conduct formal verification of a protocol. Your proposal should include your project goals, the cryptographic primitives or techniques you'll explore, implementation details, and how you'll evaluate its security properties. This self-directed project allows you to delve deeper into an area of applied cryptography that particularly interests you while demonstrating your understanding of the course material in a creative and practical context.

+
+
+
+
+
+ + + + + + diff --git a/test b/website/labs/.gitkeep similarity index 100% rename from test rename to website/labs/.gitkeep diff --git a/website/papers/.gitkeep b/website/papers/.gitkeep new file mode 100644 index 0000000..473a0f4 diff --git a/website/papers/confidential-cloud.pdf b/website/papers/confidential-cloud.pdf new file mode 100644 index 0000000..3c5a375 --- /dev/null +++ b/website/papers/confidential-cloud.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:41e6c20a6140e091a4dbae1d7d8ac8dea2639eef41d2553557dbc8a01f0717fa +size 1606776 diff --git a/website/papers/ecc-practice.pdf b/website/papers/ecc-practice.pdf new file mode 100644 index 0000000..86ad8f9 --- /dev/null +++ b/website/papers/ecc-practice.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19a84e91ea04698a741be13123d4fec8aedccab5f92c63b3157d5c5a23634053 +size 589842 diff --git a/website/papers/everest-perspectives.pdf b/website/papers/everest-perspectives.pdf new file mode 100644 index 0000000..8aff37d --- /dev/null +++ b/website/papers/everest-perspectives.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7409fa54f526a811a74f444da19cd4d79f4ced31ffdcfe4425b8a71bd601ad08 +size 1373636 diff --git a/website/papers/google-poodle.pdf b/website/papers/google-poodle.pdf new file mode 100644 index 0000000..8e3efea --- /dev/null +++ b/website/papers/google-poodle.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b2ffe2b23e29fc61a2e99711e7ff799ee26f04addd8cccd1516efb84b8489efe +size 218218 diff --git a/website/papers/group-chats.pdf b/website/papers/group-chats.pdf new file mode 100644 index 0000000..f36f406 --- /dev/null +++ b/website/papers/group-chats.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:849a837ed4e1f38ad90facb7d227141d75b7239dd6720b4eabcf79c5539265ca +size 1341282 diff --git a/website/papers/group-healing.pdf b/website/papers/group-healing.pdf new file mode 100644 index 0000000..5207a9f --- /dev/null +++ b/website/papers/group-healing.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e34eeaa2511cbb64f89c55f134b249c3163a120c6bf106b191165441b7622032 +size 335679 diff --git a/website/papers/hkdf-scheme.pdf b/website/papers/hkdf-scheme.pdf new file mode 100644 index 0000000..d5addbc --- /dev/null +++ b/website/papers/hkdf-scheme.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:873040e29f843aea6ede3989383bd938be3d49b6704992ecbf0c3286a4ccea6d +size 495140 diff --git a/website/papers/imperfect-dh.pdf b/website/papers/imperfect-dh.pdf new file mode 100644 index 0000000..648a651 --- /dev/null +++ b/website/papers/imperfect-dh.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:34229b5a84df1c71f6a8f6c2fbd22fb444d37a13ea7fdfe2f50f3fe60983e984 +size 1386629 diff --git a/website/papers/inria-collisions.pdf b/website/papers/inria-collisions.pdf new file mode 100644 index 0000000..97c0f7b --- /dev/null +++ b/website/papers/inria-collisions.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cce8bfd1730c4d4bfc8f432eb1e623bec94cf5477a254aeba86945f601bad3e7 +size 2316604 diff --git a/website/papers/inria-sweet32.pdf b/website/papers/inria-sweet32.pdf new file mode 100644 index 0000000..a23fe10 --- /dev/null +++ b/website/papers/inria-sweet32.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e686111e366664afa1ef6704c710a16d9a91ca28ab9766541466ff90d7766d2 +size 521213 diff --git a/website/papers/invalid-curve.pdf b/website/papers/invalid-curve.pdf new file mode 100644 index 0000000..65499f6 --- /dev/null +++ b/website/papers/invalid-curve.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c73ac829f9a276cc35b37f53e3509ca2f118faa99038bc4a8e147ee8f6b5c5d8 +size 776151 diff --git a/website/papers/jhu-imessage.pdf b/website/papers/jhu-imessage.pdf new file mode 100644 index 0000000..d1e0a88 --- /dev/null +++ b/website/papers/jhu-imessage.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68b567e3448241d99ad099b34e2b802c0c1808447bf5272f7a0dbabb0cf626da +size 778103 diff --git a/website/papers/johnny-cant.pdf b/website/papers/johnny-cant.pdf new file mode 100644 index 0000000..9937013 --- /dev/null +++ b/website/papers/johnny-cant.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90e32429d51b2203454cad3f024cfd2b30bacd8c5564a2082e06911b46a44615 +size 621840 diff --git a/website/papers/johnny-still.pdf b/website/papers/johnny-still.pdf new file mode 100644 index 0000000..50fedb6 --- /dev/null +++ b/website/papers/johnny-still.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99c3ad6b087424a4d8a6c9d9f6d7e3e9a7a4d7866e4f5dbd27814bdb9d88b908 +size 177038 diff --git a/website/papers/key-commitment.pdf b/website/papers/key-commitment.pdf new file mode 100644 index 0000000..6ecda5a --- /dev/null +++ b/website/papers/key-commitment.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a6ac1779c80b972dfd9cc1a2b34c3006f36a258ad12303cdf10cdbd95259eb1 +size 2587360 diff --git a/website/papers/lessons-tls.pdf b/website/papers/lessons-tls.pdf new file mode 100644 index 0000000..973b637 --- /dev/null +++ b/website/papers/lessons-tls.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a26c63cdeb7dee24b75989a31ea38813d1f9ec5ca96b597d97a2cbb154aca393 +size 2503231 diff --git a/website/papers/luby-rackoff.pdf b/website/papers/luby-rackoff.pdf new file mode 100644 index 0000000..3a176f5 --- /dev/null +++ b/website/papers/luby-rackoff.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68324c2d0b90a019947c86da6a0a21ef7cf8a45ae8d9e1e01d1d43651aea88b4 +size 1981922 diff --git a/website/papers/lucky-thirteen.pdf b/website/papers/lucky-thirteen.pdf new file mode 100644 index 0000000..594356f --- /dev/null +++ b/website/papers/lucky-thirteen.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecdca4301474b98d3d5b308650bbd198143775b853d1f910e33ed2c9adbfe376 +size 378107 diff --git a/website/papers/matter-heartbleed.pdf b/website/papers/matter-heartbleed.pdf new file mode 100644 index 0000000..aafc879 --- /dev/null +++ b/website/papers/matter-heartbleed.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa7d521e53623e9a69e8a554e9b84810e0688aeee5f270e083b053424f7b9e3c +size 723472 diff --git a/website/papers/nintendo-hard.pdf b/website/papers/nintendo-hard.pdf new file mode 100644 index 0000000..4357f25 --- /dev/null +++ b/website/papers/nintendo-hard.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b374d70b0a388fa9d79efd2392e0135578814a754046ffe339072e51f7af699 +size 3593443 diff --git a/website/papers/otr-analysis.pdf b/website/papers/otr-analysis.pdf new file mode 100644 index 0000000..2c38abb --- /dev/null +++ b/website/papers/otr-analysis.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:330de2bcb491d9cb2bb54d1fec21090f57cc9e8bbc596240a37e882ac12fbb7a +size 107018 diff --git a/website/papers/otr-auth.pdf b/website/papers/otr-auth.pdf new file mode 100644 index 0000000..101cd74 --- /dev/null +++ b/website/papers/otr-auth.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a350279ab137df882ebc43a0530d88a6d9a5542cdc914f3ef63f1c0ea64c615 +size 159014 diff --git a/website/papers/otr-messaging.pdf b/website/papers/otr-messaging.pdf new file mode 100644 index 0000000..2d46ce7 --- /dev/null +++ b/website/papers/otr-messaging.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2f75ac1746c64566eb5ccaa220917f471b4bfd3365236a21fd690ce56497d01 +size 131738 diff --git a/website/papers/pcs-impossibility.pdf b/website/papers/pcs-impossibility.pdf new file mode 100644 index 0000000..3a5a7bf --- /dev/null +++ b/website/papers/pcs-impossibility.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e894b6e5d67241a6eed03013302031a39d9cdca83edaccb862796926cde88d6 +size 449498 diff --git a/website/papers/pq3-analysis.pdf b/website/papers/pq3-analysis.pdf new file mode 100644 index 0000000..a20e266 --- /dev/null +++ b/website/papers/pq3-analysis.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1123f9d08c20f3808e8f38ce98ab1d763d4671ce0b23fb01fed8ad491f58a019 +size 676888 diff --git a/website/papers/pqxdh-analysis.pdf b/website/papers/pqxdh-analysis.pdf new file mode 100644 index 0000000..5f569ae --- /dev/null +++ b/website/papers/pqxdh-analysis.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2c4d23eb46ea5fd9706f2509c287a26b2428f06eef9eaf751b6b85d95e517ff9 +size 600204 diff --git a/website/papers/pragmatic-mpc.pdf b/website/papers/pragmatic-mpc.pdf new file mode 100644 index 0000000..e0e5291 --- /dev/null +++ b/website/papers/pragmatic-mpc.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19ec3284b4d76f06e8ebd28923517bf530bd390f1f1061a536be7fb1d81ce942 +size 1308537 diff --git a/website/papers/prime-order.pdf b/website/papers/prime-order.pdf new file mode 100644 index 0000000..60d8cb9 --- /dev/null +++ b/website/papers/prime-order.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0a18d522bd4d639cf8fe88698d634916555091d2fa513fb6c5e57fb1e506408 +size 695552 diff --git a/website/papers/rc4-absab.pdf b/website/papers/rc4-absab.pdf new file mode 100644 index 0000000..79acf4a --- /dev/null +++ b/website/papers/rc4-absab.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37abf6b27333857cee5cfd4bcb45185dd82c1360e2a03c7db06c867fb2908c7a +size 188276 diff --git a/website/papers/rc4-attacks.pdf b/website/papers/rc4-attacks.pdf new file mode 100644 index 0000000..6f2ece2 --- /dev/null +++ b/website/papers/rc4-attacks.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ed4f31743d118747d0467a71c89d63bd95d9c841d69abd861212033b675ec76 +size 1148904 diff --git a/website/papers/rc4-biases.pdf b/website/papers/rc4-biases.pdf new file mode 100644 index 0000000..809867f --- /dev/null +++ b/website/papers/rc4-biases.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1810de76a7d6a15434b4fc536a09e6505cbd65bb0a6fb51784b2b83f3a348cdc +size 438322 diff --git a/website/papers/rc4-ksa.pdf b/website/papers/rc4-ksa.pdf new file mode 100644 index 0000000..c0e63b8 --- /dev/null +++ b/website/papers/rc4-ksa.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14ae46b32faf037a95164a8e31cf71672f88effd05ad2a27f4629e78302db9e1 +size 286106 diff --git a/website/papers/rc4-tls.pdf b/website/papers/rc4-tls.pdf new file mode 100644 index 0000000..ba8f22d --- /dev/null +++ b/website/papers/rc4-tls.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7803f885cf33e853ac335cbe0f12db135de735340386a8c4c2fc969665b24046 +size 2188136 diff --git a/website/papers/rom-methodology.pdf b/website/papers/rom-methodology.pdf new file mode 100644 index 0000000..0403a45 --- /dev/null +++ b/website/papers/rom-methodology.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0bd5987bdf4f2670a23d223d2d2a33c2ae3937e5d008f2e8ca3a0ea70aab558 +size 369450 diff --git a/website/papers/scrypt-memory.pdf b/website/papers/scrypt-memory.pdf new file mode 100644 index 0000000..5735104 --- /dev/null +++ b/website/papers/scrypt-memory.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1cecb5bec5704dbe59781b8cc6e2396ff2bdccef57cc7e107e9cc55d6b4cadb8 +size 524273 diff --git a/website/papers/session-handling.pdf b/website/papers/session-handling.pdf new file mode 100644 index 0000000..6348831 --- /dev/null +++ b/website/papers/session-handling.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:629179838dfe5614605520e48787f067b18560ac1528d7b4ac663c70e5a11ae4 +size 849501 diff --git a/website/papers/shattered-sha1.pdf b/website/papers/shattered-sha1.pdf new file mode 100644 index 0000000..b5dadc5 --- /dev/null +++ b/website/papers/shattered-sha1.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3396362dcc528ed29918c07701e3b5082365a1dc19a9aac8d104c9c3d07c6b2 +size 530778 diff --git a/website/papers/sigma-ake.pdf b/website/papers/sigma-ake.pdf new file mode 100644 index 0000000..d0f448a --- /dev/null +++ b/website/papers/sigma-ake.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fce7245380de6ab7af4e3b580458c47a1724b2ae6c336fc50c27bded4e367da +size 472335 diff --git a/website/papers/signal-analysis.pdf b/website/papers/signal-analysis.pdf new file mode 100644 index 0000000..9e8fa5d --- /dev/null +++ b/website/papers/signal-analysis.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:33b0ca11ba1ceeba18ed89586448f74b4fedb5f07054263827354226632f20df +size 872400 diff --git a/website/papers/smack-tls.pdf b/website/papers/smack-tls.pdf new file mode 100644 index 0000000..d6133b6 --- /dev/null +++ b/website/papers/smack-tls.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:904f032ca003b5acf224506970362048727802474eafe70c351209344dfb06e3 +size 747155 diff --git a/website/papers/sok-verif.pdf b/website/papers/sok-verif.pdf new file mode 100644 index 0000000..8c2b9c6 --- /dev/null +++ b/website/papers/sok-verif.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecc41faf17caf1b362d39b8e8e5380385d52ed10c1ba4432f8bd8ec4375b81e4 +size 317796 diff --git a/website/papers/telegram-exchange.pdf b/website/papers/telegram-exchange.pdf new file mode 100644 index 0000000..fcfe8f9 --- /dev/null +++ b/website/papers/telegram-exchange.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:37ea4cfc990e10cb746b19a4dbfe386f1a2c945bce8326645f3c7dd3da3428e9 +size 923883 diff --git a/website/papers/tlock-bls.pdf b/website/papers/tlock-bls.pdf new file mode 100644 index 0000000..7c62c87 --- /dev/null +++ b/website/papers/tlock-bls.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d55b2f0f36c63dc487bcacf94399c07938e9417543c56c852a6dca2e33711221 +size 422095 diff --git a/website/papers/tls-deployment.pdf b/website/papers/tls-deployment.pdf new file mode 100644 index 0000000..1067fd7 --- /dev/null +++ b/website/papers/tls-deployment.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b09dc25111e7db1646bc7ed730142d922f65acaebdd8b7aa45780e56a75efc0a +size 681211 diff --git a/website/papers/tls13-verif.pdf b/website/papers/tls13-verif.pdf new file mode 100644 index 0000000..ea92247 --- /dev/null +++ b/website/papers/tls13-verif.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4ca6dd2cb76f9d2afbc375872638bde6e59e020a80aaa707f46575271cb7e2a +size 1591372 diff --git a/website/papers/triple-handshakes.pdf b/website/papers/triple-handshakes.pdf new file mode 100644 index 0000000..9bc2390 --- /dev/null +++ b/website/papers/triple-handshakes.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a8041c2b4d29cc3934ea038519732f92c63307d9a92ec8b96883d8f4bf3e58c9 +size 1906824 diff --git a/website/papers/triple-ratchet.pdf b/website/papers/triple-ratchet.pdf new file mode 100644 index 0000000..f972319 --- /dev/null +++ b/website/papers/triple-ratchet.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7cfda253e6cdbd3701305241ac9646b22e5d730d8308931e4e3695cfbfbbb917 +size 1264256 diff --git a/website/papers/wallez-thesis.pdf b/website/papers/wallez-thesis.pdf new file mode 100644 index 0000000..2f87b77 --- /dev/null +++ b/website/papers/wallez-thesis.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e024c359e41ec57a9bbbcbebd37913a2cfcae1ccfaef9e48972f7d49d48218d +size 1654545 diff --git a/website/papers/whatsapp-groups.pdf b/website/papers/whatsapp-groups.pdf new file mode 100644 index 0000000..6be824b --- /dev/null +++ b/website/papers/whatsapp-groups.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb41f92bfeae158ef595867605a51689d4c30613c4ab1536ab35e954b57ed619 +size 1387362 diff --git a/website/papers/wild-cryptography.pdf b/website/papers/wild-cryptography.pdf new file mode 100644 index 0000000..68c786f --- /dev/null +++ b/website/papers/wild-cryptography.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6ffad865384d39c32a175c09399e039cedb1ad2b8b9d7befa1021f494b53af6 +size 186810 diff --git a/website/papers/xwing-hybrid.pdf b/website/papers/xwing-hybrid.pdf new file mode 100644 index 0000000..353b615 --- /dev/null +++ b/website/papers/xwing-hybrid.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:773d00abefd9e88552c8d5f4f04ae95597ff4844b56964d99be76be45632280d +size 683258 diff --git a/website/problem-sets/.gitkeep b/website/problem-sets/.gitkeep new file mode 100644 index 0000000..473a0f4 diff --git a/website/res/css/error.css b/website/res/css/error.css new file mode 100644 index 0000000..7966d5e --- /dev/null +++ b/website/res/css/error.css @@ -0,0 +1,16 @@ +body, +html { + margin: 0; + padding: 0; + height: 100%; + background-color: #000000; + display: flex; + justify-content: center; + align-items: center; +} + +img { + max-width: 100%; + max-height: 100%; + image-rendering: pixelated; +} \ No newline at end of file diff --git a/website/res/css/style.css b/website/res/css/style.css new file mode 100644 index 0000000..6d39913 --- /dev/null +++ b/website/res/css/style.css @@ -0,0 +1,892 @@ +:root { + --primary: #2c5e1a; + --primary-dark: #1e3e12; + --secondary: #4a9c31; + --accent: #8cb369; + --dark: #1a2c0d; + --light: #f6f9f1; + --gray: #e8f0df; + --gray-dark: #cad9b7; + --white: white; + --text-muted-light: #6c757d; + --hero-overlay-dark: rgba(0, 0, 0, 0.5); + --hero-overlay-light: rgba(0, 0, 0, 0.4); + --alert-bg-light: rgba(240, 182, 127, 0.15); + --border-radius: 8px; + --spacing-sm: 0.75rem; + --spacing-md: 1.5rem; + --spacing-lg: 3rem; + --shadow: 0 4px 6px rgba(0, 0, 0, 0.05), 0 1px 3px rgba(0, 0, 0, 0.1); + --shadow-lg: + 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + --transition: all 0.5s ease; +} + +@media (prefers-color-scheme: dark) { + :root { + --primary: #78d159; + --primary-dark: #5eaf41; + --secondary: #8ad566; + --accent: #b8e19f; + --dark: #f2f9ee; + --light: #0a1005; + --gray: #1c2a11; + --gray-dark: #2c4119; + --text-muted: #a8c29b; + --code-bg-dark: #263b18; + --nav-bg-dark: rgba(15, 23, 7, 0.95); + --card-bg-dark: #1a2c0f; + --button-text-dark: #0a1005; + --badge-bg-dark: #2a3f19; + --alert-bg-dark: rgba(152, 195, 122, 0.15); + --shadow: 0 4px 6px rgba(0, 0, 0, 0.2), 0 1px 3px rgba(0, 0, 0, 0.3); + --shadow-lg: + 0 10px 15px -3px rgba(0, 0, 0, 0.3), + 0 4px 6px -2px rgba(0, 0, 0, 0.2); + } +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + scroll-behavior: smooth; + scroll-padding-top: 70px; +} + +body { + font-family: "Inria Sans", sans-serif; + font-size: 16px; + line-height: 1.7; + color: var(--dark); + background-color: var(--light); +} + +a { + color: var(--secondary); + text-decoration: none; + transition: var(--transition); + font-weight: 500; +} + +a:hover { + color: var(--primary); +} + +a img { + border: none; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0 0 var(--spacing-sm) 0; + font-weight: 700; + line-height: 1.2; + color: var(--primary); +} + +p { + margin-bottom: var(--spacing-md); +} + +ul, +ol { + margin-bottom: var(--spacing-md); + padding-left: 1.5rem; +} + +li { + margin-bottom: 0.5rem; +} + +strong { + font-weight: 600; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 var(--spacing-md); +} + +.navbar { + position: sticky; + top: 0; + background-color: var(--light); + box-shadow: var(--shadow); + padding: 1rem 0; + opacity: 0.95; + z-index: 1000; + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); +} + +@media (prefers-color-scheme: dark) { + .navbar { + background-color: var(--nav-bg-dark); + } +} + +.navbar-container { + display: flex; + justify-content: space-between; + align-items: center; +} + +.navbar-logo { + font-family: "Inria Sans", monospace; + font-weight: 700; + font-size: 1.2rem; + color: var(--primary); +} + +.navbar-links { + display: flex; + gap: 1.5rem; +} + +.navbar-links a { + color: var(--dark); + font-weight: 500; +} + +.navbar-links a:hover { + color: var(--secondary); +} + +.hero { + position: relative; + background-image: + linear-gradient(var(--hero-overlay-dark), var(--hero-overlay-light)), + url("../img/cedar.webp"); + background-size: cover; + background-position: center; + min-height: 40vh; + display: flex; + align-items: center; + justify-content: center; + color: var(--white); + text-align: center; + padding: var(--spacing-lg) 0; +} + +.hero-content { + max-width: 800px; + margin: 0 auto; +} + +.hero h1 { + font-size: 3.5rem; + margin-bottom: 1rem; + color: var(--white); + text-shadow: 0px 0px 4px rgba(0, 0, 0, 0.5); + font-weight: 800; +} + +.hero-subtitle { + font-size: 1.5rem; + margin-bottom: 2rem; + opacity: 0.9; + font-weight: 400; +} + +.hero-subtitle img { + max-width: 50%; + height: auto; +} + +.hero-course-code { + display: inline-block; + background-color: var(--accent); + color: var(--dark); + padding: 0.5rem 1.5rem; + font-family: "JetBrains Mono", monospace; + font-weight: 600; + border-radius: var(--border-radius); + margin-top: 1.5rem; + letter-spacing: 1px; +} + +.section { + padding: var(--spacing-lg) 0; + border-bottom: 1px solid var(--gray-dark); +} + +.section:last-child { + border-bottom: none; +} + +.section-header { + position: relative; + margin-bottom: var(--spacing-md); + padding-bottom: var(--spacing-sm); +} + +.section-header::after { + content: ""; + position: absolute; + bottom: 0; + left: 0; + width: 60px; + height: 4px; + background-color: var(--secondary); + border-radius: 2px; +} + +.section-title { + font-size: 2rem; + margin-bottom: 0.5rem; +} + +.subsection { + margin-bottom: var(--spacing-md); +} + +.subsection-title { + font-size: 1.5rem; + margin-bottom: var(--spacing-sm); + color: var(--primary-dark); + display: flex; + align-items: center; +} + +.card { + background-color: var(--white); + border-radius: var(--border-radius); + padding: var(--spacing-md); + margin-bottom: var(--spacing-md); + box-shadow: var(--shadow); + transition: var(--transition); +} + +@media (prefers-color-scheme: dark) { + .card { + background-color: var(--card-bg-dark); + } +} + +.card:hover { + transform: translateY(-5px); + box-shadow: var(--shadow-lg); +} + +.card-highlight { + border-left: 4px solid var(--secondary); +} + +.topic { + position: relative; + margin-bottom: var(--spacing-md); + background-color: var(--white); + border-radius: var(--border-radius); + border-left: 4px solid var(--secondary); + padding: var(--spacing-md); + box-shadow: var(--shadow); + transition: var(--transition); + overflow: hidden; +} + +@media (prefers-color-scheme: dark) { + .topic { + background-color: var(--card-bg-dark); + } +} + +.topic:hover { + transform: translateY(-5px); + box-shadow: var(--shadow-lg); +} + +.topic:last-child { + margin-bottom: 0; +} + +.topic-title { + font-weight: 700; + font-size: 1.2rem; + color: var(--primary-dark); + margin-right: 2.5rem; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.topic-overview { + margin: 0.75rem 0 1.25rem 0; + color: var(--dark); + font-size: 0.95rem; + line-height: 1.6; +} + +.topic-number { + display: inline-block; + font-family: "JetBrains Mono", monospace; + font-size: 0.85rem; + color: var(--secondary); + background-color: var(--gray); + padding: 0.25rem 0.75rem; + border-radius: 50px; + margin-bottom: 0.75rem; +} + +.topic-slides-btn { + position: absolute; + top: 0; + right: 0; + background-color: var(--accent); + color: var(--dark); + font-family: "JetBrains Mono", monospace; + font-size: 0.75rem; + font-weight: 600; + padding: 0.25rem 0.75rem; + border-radius: 0 var(--border-radius) 0 var(--border-radius); + letter-spacing: 0.5px; + display: flex; + align-items: center; + transition: var(--transition); +} + +.topic-slides-btn:hover { + background-color: var(--primary); + color: var(--white); +} + +.topic-slides-btn i { + margin-right: 0.25rem; +} + +.topic-slides-not-available { + display: none; +} + +.topic-readings { + margin-top: 1rem; + padding-top: 1rem; + border-top: 1px solid var(--gray); +} + +.topic-readings h5 { + font-size: 0.9rem; + color: var(--primary-dark); + margin-bottom: 0.5rem; +} + +.topic-readings ul { + margin-bottom: 0; +} + +.code { + font-family: "JetBrains Mono", monospace; + padding: 0.2rem 0.4rem; + background-color: var(--gray); + border-radius: 4px; + font-size: 0.9em; + color: var(--primary-dark); +} + +.alert { + background-color: var(--alert-bg-light); + border-left: 4px solid var(--accent); + padding: var(--spacing-md); + margin-bottom: var(--spacing-md); + border-radius: var(--border-radius); +} + +.alert p:last-child { + margin-bottom: 0; +} + +.icon { + margin-right: 0.5rem; + color: var(--primary-dark); + transform: scale(1.25); + display: inline-block; +} + +.footer { + background-color: var(--primary-dark); + color: var(--white); + padding: var(--spacing-md) 0; + font-size: 0.9rem; + border-top: 1px solid var(--gray); +} + +@media (prefers-color-scheme: dark) { + .footer { + background-color: var(--light); + } +} + +.footer a { + color: var(--accent); +} + +.footer a:hover { + color: var(--white); +} + +.footer-license { + display: flex; + align-items: center; + gap: 10px; +} + +.footer-license p { + margin: 0; + max-width: 600px; +} + +.two-columns { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-md); +} + +@media (max-width: 992px) { + .two-columns { + grid-template-columns: 1fr; + } +} + +.mobile-menu-toggle { + display: none; + background: transparent; + border: none; + cursor: pointer; + padding: 0; + width: 30px; + height: 30px; + position: relative; + outline: none; +} + +.mobile-menu-toggle .bar { + display: block; + width: 100%; + height: 3px; + border-radius: 3px; + background-color: var(--primary); + margin: 6px 0; + transition: var(--transition); +} + +.mobile-menu-toggle.active .bar:nth-child(1) { + transform: rotate(-45deg) translate(-7px, 6px); +} + +.mobile-menu-toggle.active .bar:nth-child(2) { + opacity: 0; +} + +.mobile-menu-toggle.active .bar:nth-child(3) { + transform: rotate(45deg) translate(-7px, -6px); +} + +@media (max-width: 768px) { + .mobile-menu-toggle { + display: block; + z-index: 1010; + } + + .navbar-links { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 2rem; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vh; + background-color: rgba(246, 249, 241, 0.98); + z-index: 1000; + transition: var(--transition); + transform: translateY(-100%); + opacity: 0; + padding: 2rem; + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + } + + .navbar-links.active { + transform: translateY(0); + opacity: 1; + } + + .navbar-links a { + font-size: 1.3rem; + } + + @media (prefers-color-scheme: dark) { + .navbar-links { + background-color: var(--nav-bg-dark); + } + + .mobile-menu-toggle .bar { + background-color: var(--primary); + } + } + + .hero h1 { + font-size: 2.5rem; + } + + .hero-subtitle { + font-size: 1.2rem; + } + + .section-title { + font-size: 1.8rem; + } +} + +@media (max-width: 576px) { + .hero h1 { + font-size: 2rem; + } + + .section { + padding: var(--spacing-md) 0; + } +} + +.btn { + display: inline-block; + padding: 0.75rem 1.5rem; + border-radius: var(--border-radius); + font-weight: 600; + text-align: center; + cursor: pointer; + transition: var(--transition); + background-color: var(--accent); + color: var(--dark); + border: none; + text-decoration: none; +} + +.btn:hover { + background-color: var(--primary); + color: var(--white); + transform: translateY(-2px); + box-shadow: var(--shadow); +} + +.btn-outline { + background-color: transparent; + border: 2px solid var(--secondary); + color: var(--secondary); +} + +.btn-outline:hover { + background-color: var(--secondary); + color: var(--white); +} + +.news-entry { + position: relative; + border-left: 4px solid var(--secondary); + background-color: var(--white); + border-radius: var(--border-radius); + padding: var(--spacing-md); + margin-bottom: var(--spacing-md); + box-shadow: var(--shadow); + transition: var(--transition); + overflow: hidden; +} + +@media (prefers-color-scheme: dark) { + .news-entry { + background-color: var(--card-bg-dark); + } +} + +.news-entry:hover { + transform: translateY(-5px); + box-shadow: var(--shadow-lg); +} + +.news-entry.new::before { + content: "NEW"; + position: absolute; + top: 0; + right: 0; + background-color: var(--accent); + color: var(--dark); + font-family: "JetBrains Mono", monospace; + font-size: 0.7rem; + font-weight: 600; + padding: 0.25rem 0.75rem; + border-radius: 0 var(--border-radius) 0 var(--border-radius); + letter-spacing: 1px; +} + +.news-entry.new { + filter: none; +} + +.news-date { + display: inline-block; + font-family: "JetBrains Mono", monospace; + font-size: 0.85rem; + color: var(--secondary); + background-color: var(--gray); + padding: 0.25rem 0.75rem; + border-radius: 50px; + margin-bottom: 0.75rem; +} + +.news-title { + font-size: 1.4rem; + margin-bottom: 0.75rem; + color: var(--primary-dark); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.news-content { + color: var(--dark); +} + +.news-footer { + display: flex; + justify-content: flex-end; + margin-top: 1rem; + padding-top: 1rem; + border-top: 1px solid var(--gray); +} + +.news-empty { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: var(--white); + border-radius: var(--border-radius); + padding: var(--spacing-lg); + margin-bottom: var(--spacing-md); + text-align: center; + min-height: 200px; +} + +@media (prefers-color-scheme: dark) { + .news-empty { + background-color: var(--card-bg-dark); + } + + .text-muted { + color: var(--text-muted); + } +} + +.news-empty-icon { + font-size: 3rem; + color: var(--gray-dark); + margin-bottom: 1rem; +} + +.news-empty-text { + color: var(--text-muted-light); + font-size: 1.1rem; + font-style: italic; +} + +.text-center { + text-align: center; +} + +.text-muted { + color: var(--text-muted-light); +} + +.mb-0 { + margin-bottom: 0; +} + +.mb-1 { + margin-bottom: 0.25rem; +} + +.mb-2 { + margin-bottom: 0.5rem; +} + +.mb-3 { + margin-bottom: 1rem; +} + +.mb-4 { + margin-bottom: 1.5rem; +} + +.mb-5 { + margin-bottom: 3rem; +} + +.book-display { + display: flex; + gap: 20px; + align-items: flex-start; +} + +.book-cover { + width: 200px; + height: auto; + box-shadow: var(--shadow); + border-radius: var(--border-radius); + transition: var(--transition); +} + +.book-cover:hover { + transform: translateY(-5px); + box-shadow: var(--shadow-lg); +} + +@media (max-width: 576px) { + .book-display .book-cover { + display: none; + } +} + +.collapsible-header { + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + transition: var(--transition); + user-select: none; + padding: 0.75rem 1rem; + border-radius: var(--border-radius); + background-color: var(--gray); + border-left: 4px solid var(--secondary); + box-shadow: var(--shadow); + margin-bottom: 0.5rem; + font-weight: 600; +} + +.collapsible-header:hover { + color: var(--secondary); + transform: translateY(-2px); + box-shadow: var(--shadow-lg); +} + +.collapsible-header .subsection-title { + margin-bottom: 0; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.collapsible-icon { + font-size: 1.6rem; + transition: var(--transition); + color: var(--primary-dark); + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + display: inline-block; +} + +.collapsible-header.active { + background: linear-gradient(to bottom, + var(--gray-dark) 0%, + transparent 100%); + box-shadow: none; + border-radius: var(--border-radius) var(--border-radius) 0 0; +} + +.collapsible-header.active .collapsible-icon { + transform: rotate(180deg); + opacity: 0.5; +} + +.collapsible-content { + max-height: 0; + overflow: hidden; + transition: var(--transition); + padding: 0 1rem; +} + +.collapsible-content.active { + max-height: fit-content; +} + +@media (prefers-color-scheme: dark) { + .code { + background-color: var(--code-bg-dark); + color: var(--accent); + } + + .alert { + background-color: var(--alert-bg-dark); + } + + .news-empty-text { + color: var(--text-muted); + } + + h1, + h2, + h3, + h4, + h5, + h6 { + color: var(--primary); + } + + .subsection-title, + .topic-title, + .topic-readings h5, + .news-title, + .icon { + color: var(--primary); + } + + a.topic-slides-btn { + background-color: var(--accent); + color: var(--button-text-dark); + font-weight: 700; + } + + a.topic-slides-btn:hover { + background-color: var(--primary); + color: var(--button-text-dark); + } + + .btn { + color: var(--button-text-dark); + font-weight: 700; + } + + .btn:hover { + color: var(--button-text-dark); + } + + .news-entry.new::before, + .hero-course-code { + background-color: var(--accent); + color: var(--button-text-dark); + font-weight: 700; + } + + .news-date, + .topic-number { + background-color: var(--badge-bg-dark); + color: var(--accent); + } + + .collapsible-header .collapsible-icon { + color: var(--primary); + } +} \ No newline at end of file diff --git a/website/res/fonts/google/google.css b/website/res/fonts/google/google.css new file mode 100644 index 0000000..67898a3 --- /dev/null +++ b/website/res/fonts/google/google.css @@ -0,0 +1,208 @@ +/* latin-ext */ +@font-face { + font-family: "Inria Sans"; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url(./inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_pM4zT305QaYc.woff2) + format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, + U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Inria Sans"; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url(./inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_qs4zT305QQ.woff2) + format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin-ext */ +@font-face { + font-family: "Inria Sans"; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(./inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIJCtqh-w-ZUcw.woff2) + format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, + U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Inria Sans"; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url(./inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIKitqh-w-ZQ.woff2) + format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin-ext */ +@font-face { + font-family: "Inria Sans"; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url(./inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_pM4zT305QaYc.woff2) + format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, + U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Inria Sans"; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url(./inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_qs4zT305QQ.woff2) + format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin-ext */ +@font-face { + font-family: "Inria Sans"; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(./inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQJPqMQ0bX8JQA.woff2) + format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, + U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Inria Sans"; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url(./inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQxPqMQ0bX8.woff2) + format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin-ext */ +@font-face { + font-family: "Inria Sans"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(./inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1Of4KCFtpe4OZA.woff2) + format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, + U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Inria Sans"; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(./inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1On4KCFtpe4.woff2) + format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin-ext */ +@font-face { + font-family: "Inria Sans"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(./inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQJPqMQ0bX8JQA.woff2) + format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, + U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "Inria Sans"; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(./inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQxPqMQ0bX8.woff2) + format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin-ext */ +@font-face { + font-family: "JetBrains Mono"; + font-style: italic; + font-weight: 100 800; + font-display: swap; + src: url(./jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-Cw2nSGjW7BDEAQ.woff2) + format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, + U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "JetBrains Mono"; + font-style: italic; + font-weight: 100 800; + font-display: swap; + src: url(./jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-CwOnSGjW7BA.woff2) + format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} +/* latin-ext */ +@font-face { + font-family: "JetBrains Mono"; + font-style: normal; + font-weight: 100 800; + font-display: swap; + src: url(./jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD1OwGtT0rU3BE.woff2) + format("woff2"); + unicode-range: + U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, + U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, + U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: "JetBrains Mono"; + font-style: normal; + font-weight: 100 800; + font-display: swap; + src: url(./jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD7OwGtT0rU.woff2) + format("woff2"); + unicode-range: + U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, + U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, + U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/website/res/fonts/google/inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1Of4KCFtpe4OZA.woff2 b/website/res/fonts/google/inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1Of4KCFtpe4OZA.woff2 new file mode 100644 index 0000000..f291c19 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1Of4KCFtpe4OZA.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75f1bb2b5291a6636c49c87d9382ef5267e196a8ebe23f6b1aaf32f8968da833 +size 6336 diff --git a/website/res/fonts/google/inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1On4KCFtpe4.woff2 b/website/res/fonts/google/inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1On4KCFtpe4.woff2 new file mode 100644 index 0000000..7c7d698 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRMTiqXYfZMCOiVj9kQ1On4KCFtpe4.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9874e166957abf3e47a3ee860628ef6df4765db42c6fe590112ce02d37820cdf +size 13316 diff --git a/website/res/fonts/google/inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIJCtqh-w-ZUcw.woff2 b/website/res/fonts/google/inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIJCtqh-w-ZUcw.woff2 new file mode 100644 index 0000000..786e461 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIJCtqh-w-ZUcw.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8871c242888bef97d12766be6923efeb37cf4675cb26d0edf33b3cf11d118ca +size 6576 diff --git a/website/res/fonts/google/inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIKitqh-w-ZQ.woff2 b/website/res/fonts/google/inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIKitqh-w-ZQ.woff2 new file mode 100644 index 0000000..3797acc --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptROTiqXYfZMCOiVj9kQ1OzIKitqh-w-ZQ.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e187b6aa247290d1c267b48ac683577d713fadced86e517c85ab5190a764a9f +size 14088 diff --git a/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQJPqMQ0bX8JQA.woff2 b/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQJPqMQ0bX8JQA.woff2 new file mode 100644 index 0000000..65115d2 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQJPqMQ0bX8JQA.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7af6e8c203d4e8555f7d40f74838bdc23626b8d7c4edc7bdc23818185c3e54f5 +size 6200 diff --git a/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQxPqMQ0bX8.woff2 b/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQxPqMQ0bX8.woff2 new file mode 100644 index 0000000..038c869 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3ELaPQxPqMQ0bX8.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69f2c681590cf7fbab9cfb3cf7f810dadc262b56efef3971418c1b4a742602fb +size 12588 diff --git a/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQJPqMQ0bX8JQA.woff2 b/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQJPqMQ0bX8JQA.woff2 new file mode 100644 index 0000000..0adcdb4 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQJPqMQ0bX8JQA.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3edeeaa3d62a3aca4d7619660e4725ae3238f45a044222eba3fb3a35ba8b5da9 +size 6264 diff --git a/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQxPqMQ0bX8.woff2 b/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQxPqMQ0bX8.woff2 new file mode 100644 index 0000000..2431c23 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRPTiqXYfZMCOiVj9kQ3FLdPQxPqMQ0bX8.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb19b68f3bf63b49a8c5e9f38a083450c94423d6ca0cd447f658c30ffcc9fff3 +size 12696 diff --git a/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_pM4zT305QaYc.woff2 b/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_pM4zT305QaYc.woff2 new file mode 100644 index 0000000..9d81a6a --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_pM4zT305QaYc.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6060c049956f2ca9442c4065868965b7daf98e34fdcdb63aabeab5612412f8a2 +size 6408 diff --git a/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_qs4zT305QQ.woff2 b/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_qs4zT305QQ.woff2 new file mode 100644 index 0000000..2deb2a1 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAgQl_qs4zT305QQ.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:993b2edb8405fca5653e97bf0109e1ee33691144f0d13d2310e4fa89900d6787 +size 13340 diff --git a/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_pM4zT305QaYc.woff2 b/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_pM4zT305QaYc.woff2 new file mode 100644 index 0000000..0bc0bd7 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_pM4zT305QaYc.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d5de84bfab78a50575849bc909a08d232a501915ab3526b85f29a1b32dd16d4 +size 6424 diff --git a/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_qs4zT305QQ.woff2 b/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_qs4zT305QQ.woff2 new file mode 100644 index 0000000..ec1ff77 --- /dev/null +++ b/website/res/fonts/google/inriasans/v14/ptRRTiqXYfZMCOiVj9kQ1OzAkQ5_qs4zT305QQ.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:698c41f16650b7a37040e4108a8c812ab588b516609e83d0bd9c915e203b113c +size 13424 diff --git a/website/res/fonts/google/jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD1OwGtT0rU3BE.woff2 b/website/res/fonts/google/jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD1OwGtT0rU3BE.woff2 new file mode 100644 index 0000000..5163332 --- /dev/null +++ b/website/res/fonts/google/jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD1OwGtT0rU3BE.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7db7affbce1fdee69c1ffc2641bbca289b049867f524c9d861fe35ab6670bf29 +size 15204 diff --git a/website/res/fonts/google/jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD7OwGtT0rU.woff2 b/website/res/fonts/google/jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD7OwGtT0rU.woff2 new file mode 100644 index 0000000..4becb0a --- /dev/null +++ b/website/res/fonts/google/jetbrainsmono/v20/tDbV2o-flEEny0FZhsfKu5WU4xD7OwGtT0rU.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e06740a02a443fb7f3eeda8fcaa685a0f6c620e3f01e6666e847295469ce3ad +size 40480 diff --git a/website/res/fonts/google/jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-Cw2nSGjW7BDEAQ.woff2 b/website/res/fonts/google/jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-Cw2nSGjW7BDEAQ.woff2 new file mode 100644 index 0000000..5d63b38 --- /dev/null +++ b/website/res/fonts/google/jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-Cw2nSGjW7BDEAQ.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bdce8a4f00f61bed7141af8ac231a91be56de82f41ca2b981b34ff48359c288a +size 16540 diff --git a/website/res/fonts/google/jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-CwOnSGjW7BA.woff2 b/website/res/fonts/google/jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-CwOnSGjW7BA.woff2 new file mode 100644 index 0000000..9b38331 --- /dev/null +++ b/website/res/fonts/google/jetbrainsmono/v20/tDbX2o-flEEny0FZhsfKu5WU4xD-CwOnSGjW7BA.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6548575d68391672486bf3815a8dd9fe0ae251d1087875581ac8912d5cb52baa +size 42928 diff --git a/website/res/fonts/phosphor/Phosphor-Duotone.woff2 b/website/res/fonts/phosphor/Phosphor-Duotone.woff2 new file mode 100644 index 0000000..93dd07f --- /dev/null +++ b/website/res/fonts/phosphor/Phosphor-Duotone.woff2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93d163cd4b1f07736d34bfef80803646ab0322efa947a98e3973a1450e3d20cc +size 164420 diff --git a/website/res/fonts/phosphor/phosphor.css b/website/res/fonts/phosphor/phosphor.css new file mode 100644 index 0000000..be7cb51 --- /dev/null +++ b/website/res/fonts/phosphor/phosphor.css @@ -0,0 +1,12111 @@ +@font-face { + font-family: "Phosphor-Duotone"; + src: url("./Phosphor-Duotone.woff2") format("woff2"), + font-weight: normal; + font-style: normal; + font-display: block; +} + +.ph-duotone { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: "Phosphor-Duotone" !important; + speak: never; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.ph-duotone.ph-acorn:before { + content: "\eb9a"; + opacity: 0.2; +} +.ph-duotone.ph-acorn:after { + content: "\eb9b"; + margin-left: -1em; +} +.ph-duotone.ph-address-book:before { + content: "\e6f8"; + opacity: 0.2; +} +.ph-duotone.ph-address-book:after { + content: "\e6f9"; + margin-left: -1em; +} +.ph-duotone.ph-address-book-tabs:before { + content: "\ee4e"; + opacity: 0.2; +} +.ph-duotone.ph-address-book-tabs:after { + content: "\ee4f"; + margin-left: -1em; +} +.ph-duotone.ph-air-traffic-control:before { + content: "\ecd8"; + opacity: 0.2; +} +.ph-duotone.ph-air-traffic-control:after { + content: "\ecd9"; + margin-left: -1em; +} +.ph-duotone.ph-airplane:before { + content: "\e002"; + opacity: 0.2; +} +.ph-duotone.ph-airplane:after { + content: "\e003"; + margin-left: -1em; +} +.ph-duotone.ph-airplane-in-flight:before { + content: "\e4fe"; + opacity: 0.2; +} +.ph-duotone.ph-airplane-in-flight:after { + content: "\e4ff"; + margin-left: -1em; +} +.ph-duotone.ph-airplane-landing:before { + content: "\e502"; + opacity: 0.2; +} +.ph-duotone.ph-airplane-landing:after { + content: "\e503"; + margin-left: -1em; +} +.ph-duotone.ph-airplane-takeoff:before { + content: "\e504"; + opacity: 0.2; +} +.ph-duotone.ph-airplane-takeoff:after { + content: "\e505"; + margin-left: -1em; +} +.ph-duotone.ph-airplane-taxiing:before { + content: "\e500"; + opacity: 0.2; +} +.ph-duotone.ph-airplane-taxiing:after { + content: "\e501"; + margin-left: -1em; +} +.ph-duotone.ph-airplane-tilt:before { + content: "\e5d6"; + opacity: 0.2; +} +.ph-duotone.ph-airplane-tilt:after { + content: "\e5d7"; + margin-left: -1em; +} +.ph-duotone.ph-airplay:before { + content: "\e004"; + opacity: 0.2; +} +.ph-duotone.ph-airplay:after { + content: "\e005"; + margin-left: -1em; +} +.ph-duotone.ph-alarm:before { + content: "\e006"; + opacity: 0.2; +} +.ph-duotone.ph-alarm:after { + content: "\e007"; + margin-left: -1em; +} +.ph-duotone.ph-alien:before { + content: "\e8a6"; + opacity: 0.2; +} +.ph-duotone.ph-alien:after { + content: "\e8a7"; + margin-left: -1em; +} +.ph-duotone.ph-align-bottom:before { + content: "\e506"; + opacity: 0.2; +} +.ph-duotone.ph-align-bottom:after { + content: "\e507"; + margin-left: -1em; +} +.ph-duotone.ph-align-bottom-simple:before { + content: "\eb0c"; + opacity: 0.2; +} +.ph-duotone.ph-align-bottom-simple:after { + content: "\eb0d"; + margin-left: -1em; +} +.ph-duotone.ph-align-center-horizontal:before { + content: "\e50a"; + opacity: 0.2; +} +.ph-duotone.ph-align-center-horizontal:after { + content: "\e50b"; + margin-left: -1em; +} +.ph-duotone.ph-align-center-horizontal-simple:before { + content: "\eb0e"; + opacity: 0.2; +} +.ph-duotone.ph-align-center-horizontal-simple:after { + content: "\eb0f"; + margin-left: -1em; +} +.ph-duotone.ph-align-center-vertical:before { + content: "\e50c"; + opacity: 0.2; +} +.ph-duotone.ph-align-center-vertical:after { + content: "\e50d"; + margin-left: -1em; +} +.ph-duotone.ph-align-center-vertical-simple:before { + content: "\eb10"; + opacity: 0.2; +} +.ph-duotone.ph-align-center-vertical-simple:after { + content: "\eb11"; + margin-left: -1em; +} +.ph-duotone.ph-align-left:before { + content: "\e50e"; + opacity: 0.2; +} +.ph-duotone.ph-align-left:after { + content: "\e50f"; + margin-left: -1em; +} +.ph-duotone.ph-align-left-simple:before { + content: "\eaee"; + opacity: 0.2; +} +.ph-duotone.ph-align-left-simple:after { + content: "\eaef"; + margin-left: -1em; +} +.ph-duotone.ph-align-right:before { + content: "\e510"; + opacity: 0.2; +} +.ph-duotone.ph-align-right:after { + content: "\e511"; + margin-left: -1em; +} +.ph-duotone.ph-align-right-simple:before { + content: "\eb12"; + opacity: 0.2; +} +.ph-duotone.ph-align-right-simple:after { + content: "\eb13"; + margin-left: -1em; +} +.ph-duotone.ph-align-top:before { + content: "\e512"; + opacity: 0.2; +} +.ph-duotone.ph-align-top:after { + content: "\e513"; + margin-left: -1em; +} +.ph-duotone.ph-align-top-simple:before { + content: "\eb14"; + opacity: 0.2; +} +.ph-duotone.ph-align-top-simple:after { + content: "\eb15"; + margin-left: -1em; +} +.ph-duotone.ph-amazon-logo:before { + content: "\e96c"; + opacity: 0.2; +} +.ph-duotone.ph-amazon-logo:after { + content: "\e96d"; + margin-left: -1em; +} +.ph-duotone.ph-ambulance:before { + content: "\e572"; + opacity: 0.2; +} +.ph-duotone.ph-ambulance:after { + content: "\e573"; + margin-left: -1em; +} +.ph-duotone.ph-anchor:before { + content: "\e514"; + opacity: 0.2; +} +.ph-duotone.ph-anchor:after { + content: "\e515"; + margin-left: -1em; +} +.ph-duotone.ph-anchor-simple:before { + content: "\e5d8"; + opacity: 0.2; +} +.ph-duotone.ph-anchor-simple:after { + content: "\e5d9"; + margin-left: -1em; +} +.ph-duotone.ph-android-logo:before { + content: "\e008"; + opacity: 0.2; +} +.ph-duotone.ph-android-logo:after { + content: "\e009"; + margin-left: -1em; +} +.ph-duotone.ph-angle:before { + content: "\e7bc"; + opacity: 0.2; +} +.ph-duotone.ph-angle:after { + content: "\e7bd"; + margin-left: -1em; +} +.ph-duotone.ph-angular-logo:before { + content: "\eb80"; + opacity: 0.2; +} +.ph-duotone.ph-angular-logo:after { + content: "\eb81"; + margin-left: -1em; +} +.ph-duotone.ph-aperture:before { + content: "\e00a"; + opacity: 0.2; +} +.ph-duotone.ph-aperture:after { + content: "\e00b"; + margin-left: -1em; +} +.ph-duotone.ph-app-store-logo:before { + content: "\e974"; + opacity: 0.2; +} +.ph-duotone.ph-app-store-logo:after { + content: "\e975"; + margin-left: -1em; +} +.ph-duotone.ph-app-window:before { + content: "\e5da"; + opacity: 0.2; +} +.ph-duotone.ph-app-window:after { + content: "\e5db"; + margin-left: -1em; +} +.ph-duotone.ph-apple-logo:before { + content: "\e516"; + opacity: 0.2; +} +.ph-duotone.ph-apple-logo:after { + content: "\e517"; + margin-left: -1em; +} +.ph-duotone.ph-apple-podcasts-logo:before { + content: "\eb96"; + opacity: 0.2; +} +.ph-duotone.ph-apple-podcasts-logo:after { + content: "\eb97"; + margin-left: -1em; +} +.ph-duotone.ph-approximate-equals:before { + content: "\edaa"; + opacity: 0.2; +} +.ph-duotone.ph-approximate-equals:after { + content: "\edab"; + margin-left: -1em; +} +.ph-duotone.ph-archive:before { + content: "\e00c"; + opacity: 0.2; +} +.ph-duotone.ph-archive:after { + content: "\e00d"; + margin-left: -1em; +} +.ph-duotone.ph-armchair:before { + content: "\e012"; + opacity: 0.2; +} +.ph-duotone.ph-armchair:after { + content: "\e013"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-arc-left:before { + content: "\e014"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-arc-left:after { + content: "\e015"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-arc-right:before { + content: "\e016"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-arc-right:after { + content: "\e017"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-double-up-left:before { + content: "\e03a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-double-up-left:after { + content: "\e03b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-double-up-right:before { + content: "\e03c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-double-up-right:after { + content: "\e03d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-down-left:before { + content: "\e018"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-down-left:after { + content: "\e019"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-down-right:before { + content: "\e01a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-down-right:after { + content: "\e01b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-left-down:before { + content: "\e01c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-left-down:after { + content: "\e01d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-left-up:before { + content: "\e01e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-left-up:after { + content: "\e01f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-right-down:before { + content: "\e020"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-right-down:after { + content: "\e021"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-right-up:before { + content: "\e022"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-right-up:after { + content: "\e023"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-up-left:before { + content: "\e024"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-up-left:after { + content: "\e025"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-bend-up-right:before { + content: "\e026"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-bend-up-right:after { + content: "\e027"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-circle-down:before { + content: "\e028"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-circle-down:after { + content: "\e029"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-circle-down-left:before { + content: "\e02a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-circle-down-left:after { + content: "\e02b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-circle-down-right:before { + content: "\e02c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-circle-down-right:after { + content: "\e02d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-circle-left:before { + content: "\e05a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-circle-left:after { + content: "\e05b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-circle-right:before { + content: "\e02e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-circle-right:after { + content: "\e02f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-circle-up:before { + content: "\e030"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-circle-up:after { + content: "\e031"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-circle-up-left:before { + content: "\e032"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-circle-up-left:after { + content: "\e033"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-circle-up-right:before { + content: "\e034"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-circle-up-right:after { + content: "\e035"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-clockwise:before { + content: "\e036"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-clockwise:after { + content: "\e037"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-counter-clockwise:before { + content: "\e038"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-counter-clockwise:after { + content: "\e039"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-down:before { + content: "\e03e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-down:after { + content: "\e03f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-down-left:before { + content: "\e040"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-down-left:after { + content: "\e041"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-down-right:before { + content: "\e042"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-down-right:after { + content: "\e043"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-down-left:before { + content: "\e044"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-down-left:after { + content: "\e045"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-down-right:before { + content: "\e046"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-down-right:after { + content: "\e047"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-left:before { + content: "\e048"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-left:after { + content: "\e049"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-left-down:before { + content: "\e04a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-left-down:after { + content: "\e04b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-left-up:before { + content: "\e04c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-left-up:after { + content: "\e04d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-right:before { + content: "\e04e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-right:after { + content: "\e04f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-right-down:before { + content: "\e050"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-right-down:after { + content: "\e051"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-right-up:before { + content: "\e052"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-right-up:after { + content: "\e053"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-up-left:before { + content: "\e054"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-up-left:after { + content: "\e055"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-elbow-up-right:before { + content: "\e056"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-elbow-up-right:after { + content: "\e057"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-down:before { + content: "\e518"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-down:after { + content: "\e519"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-left:before { + content: "\e51a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-left:after { + content: "\e51b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-line-down:before { + content: "\e51c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-line-down:after { + content: "\e51d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-line-left:before { + content: "\e51e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-line-left:after { + content: "\e51f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-line-right:before { + content: "\e520"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-line-right:after { + content: "\e521"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-line-up:before { + content: "\e522"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-line-up:after { + content: "\e523"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-lines-down:before { + content: "\e524"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-lines-down:after { + content: "\e525"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-lines-left:before { + content: "\e526"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-lines-left:after { + content: "\e527"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-lines-right:before { + content: "\e528"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-lines-right:after { + content: "\e529"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-lines-up:before { + content: "\e52a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-lines-up:after { + content: "\e52b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-right:before { + content: "\e52c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-right:after { + content: "\e52d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-fat-up:before { + content: "\e52e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-fat-up:after { + content: "\e52f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-left:before { + content: "\e058"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-left:after { + content: "\e059"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-line-down:before { + content: "\e05c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-line-down:after { + content: "\e05d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-line-down-left:before { + content: "\e05e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-line-down-left:after { + content: "\e05f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-line-down-right:before { + content: "\e060"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-line-down-right:after { + content: "\e061"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-line-left:before { + content: "\e062"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-line-left:after { + content: "\e063"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-line-right:before { + content: "\e064"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-line-right:after { + content: "\e065"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-line-up:before { + content: "\e066"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-line-up:after { + content: "\e067"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-line-up-left:before { + content: "\e068"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-line-up-left:after { + content: "\e069"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-line-up-right:before { + content: "\e06a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-line-up-right:after { + content: "\e06b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-right:before { + content: "\e06c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-right:after { + content: "\e06d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-down:before { + content: "\e06e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-down:after { + content: "\e06f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-down-left:before { + content: "\e070"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-down-left:after { + content: "\e071"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-down-right:before { + content: "\e072"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-down-right:after { + content: "\e073"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-in:before { + content: "\e5dc"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-in:after { + content: "\e5dd"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-left:before { + content: "\e074"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-left:after { + content: "\e075"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-out:before { + content: "\e5de"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-out:after { + content: "\e5df"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-right:before { + content: "\e076"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-right:after { + content: "\e077"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-up:before { + content: "\e078"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-up:after { + content: "\e079"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-up-left:before { + content: "\e07a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-up-left:after { + content: "\e07b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-square-up-right:before { + content: "\e07c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-square-up-right:after { + content: "\e07d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-u-down-left:before { + content: "\e07e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-u-down-left:after { + content: "\e07f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-u-down-right:before { + content: "\e080"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-u-down-right:after { + content: "\e081"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-u-left-down:before { + content: "\e082"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-u-left-down:after { + content: "\e083"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-u-left-up:before { + content: "\e084"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-u-left-up:after { + content: "\e085"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-u-right-down:before { + content: "\e086"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-u-right-down:after { + content: "\e087"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-u-right-up:before { + content: "\e088"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-u-right-up:after { + content: "\e089"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-u-up-left:before { + content: "\e08a"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-u-up-left:after { + content: "\e08b"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-u-up-right:before { + content: "\e08c"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-u-up-right:after { + content: "\e08d"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-up:before { + content: "\e08e"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-up:after { + content: "\e08f"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-up-left:before { + content: "\e090"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-up-left:after { + content: "\e091"; + margin-left: -1em; +} +.ph-duotone.ph-arrow-up-right:before { + content: "\e092"; + opacity: 0.2; +} +.ph-duotone.ph-arrow-up-right:after { + content: "\e093"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-clockwise:before { + content: "\e094"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-clockwise:after { + content: "\e095"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-counter-clockwise:before { + content: "\e096"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-counter-clockwise:after { + content: "\e097"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-down-up:before { + content: "\e098"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-down-up:after { + content: "\e099"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-horizontal:before { + content: "\eb06"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-horizontal:after { + content: "\eb07"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-in:before { + content: "\e09a"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-in:after { + content: "\e09b"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-in-cardinal:before { + content: "\e09c"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-in-cardinal:after { + content: "\e09d"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-in-line-horizontal:before { + content: "\e530"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-in-line-horizontal:after { + content: "\e531"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-in-line-vertical:before { + content: "\e532"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-in-line-vertical:after { + content: "\e533"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-in-simple:before { + content: "\e09e"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-in-simple:after { + content: "\e09f"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-left-right:before { + content: "\e0a0"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-left-right:after { + content: "\e0a1"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-merge:before { + content: "\ed3e"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-merge:after { + content: "\ed3f"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-out:before { + content: "\e0a2"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-out:after { + content: "\e0a3"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-out-cardinal:before { + content: "\e0a4"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-out-cardinal:after { + content: "\e0a5"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-out-line-horizontal:before { + content: "\e534"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-out-line-horizontal:after { + content: "\e535"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-out-line-vertical:before { + content: "\e536"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-out-line-vertical:after { + content: "\e537"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-out-simple:before { + content: "\e0a6"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-out-simple:after { + content: "\e0a7"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-split:before { + content: "\ed3c"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-split:after { + content: "\ed3d"; + margin-left: -1em; +} +.ph-duotone.ph-arrows-vertical:before { + content: "\eb04"; + opacity: 0.2; +} +.ph-duotone.ph-arrows-vertical:after { + content: "\eb05"; + margin-left: -1em; +} +.ph-duotone.ph-article:before { + content: "\e0a8"; + opacity: 0.2; +} +.ph-duotone.ph-article:after { + content: "\e0a9"; + margin-left: -1em; +} +.ph-duotone.ph-article-medium:before { + content: "\e5e0"; + opacity: 0.2; +} +.ph-duotone.ph-article-medium:after { + content: "\e5e1"; + margin-left: -1em; +} +.ph-duotone.ph-article-ny-times:before { + content: "\e5e2"; + opacity: 0.2; +} +.ph-duotone.ph-article-ny-times:after { + content: "\e5e3"; + margin-left: -1em; +} +.ph-duotone.ph-asclepius:before { + content: "\ee34"; + opacity: 0.2; +} +.ph-duotone.ph-asclepius:after { + content: "\ee35"; + margin-left: -1em; +} +.ph-duotone.ph-asterisk:before { + content: "\e0aa"; + opacity: 0.2; +} +.ph-duotone.ph-asterisk:after { + content: "\e0ab"; + margin-left: -1em; +} +.ph-duotone.ph-asterisk-simple:before { + content: "\e832"; + opacity: 0.2; +} +.ph-duotone.ph-asterisk-simple:after { + content: "\e833"; + margin-left: -1em; +} +.ph-duotone.ph-at:before { + content: "\e0ac"; + opacity: 0.2; +} +.ph-duotone.ph-at:after { + content: "\e0ad"; + margin-left: -1em; +} +.ph-duotone.ph-atom:before { + content: "\e5e4"; + opacity: 0.2; +} +.ph-duotone.ph-atom:after { + content: "\e5e5"; + margin-left: -1em; +} +.ph-duotone.ph-avocado:before { + content: "\ee04"; + opacity: 0.2; +} +.ph-duotone.ph-avocado:after { + content: "\ee05"; + margin-left: -1em; +} +.ph-duotone.ph-axe:before { + content: "\e9fc"; + opacity: 0.2; +} +.ph-duotone.ph-axe:after { + content: "\e9fd"; + margin-left: -1em; +} +.ph-duotone.ph-baby:before { + content: "\e774"; + opacity: 0.2; +} +.ph-duotone.ph-baby:after { + content: "\e775"; + margin-left: -1em; +} +.ph-duotone.ph-baby-carriage:before { + content: "\e818"; + opacity: 0.2; +} +.ph-duotone.ph-baby-carriage:after { + content: "\e819"; + margin-left: -1em; +} +.ph-duotone.ph-backpack:before { + content: "\e922"; + opacity: 0.2; +} +.ph-duotone.ph-backpack:after { + content: "\e923"; + margin-left: -1em; +} +.ph-duotone.ph-backspace:before { + content: "\e0ae"; + opacity: 0.2; +} +.ph-duotone.ph-backspace:after { + content: "\e0af"; + margin-left: -1em; +} +.ph-duotone.ph-bag:before { + content: "\e0b0"; + opacity: 0.2; +} +.ph-duotone.ph-bag:after { + content: "\e0b1"; + margin-left: -1em; +} +.ph-duotone.ph-bag-simple:before { + content: "\e5e6"; + opacity: 0.2; +} +.ph-duotone.ph-bag-simple:after { + content: "\e5e7"; + margin-left: -1em; +} +.ph-duotone.ph-balloon:before { + content: "\e76c"; + opacity: 0.2; +} +.ph-duotone.ph-balloon:after { + content: "\e76d"; + margin-left: -1em; +} +.ph-duotone.ph-bandaids:before { + content: "\e0b2"; + opacity: 0.2; +} +.ph-duotone.ph-bandaids:after { + content: "\e0b3"; + margin-left: -1em; +} +.ph-duotone.ph-bank:before { + content: "\e0b4"; + opacity: 0.2; +} +.ph-duotone.ph-bank:after { + content: "\e0b5"; + margin-left: -1em; +} +.ph-duotone.ph-barbell:before { + content: "\e0b6"; + opacity: 0.2; +} +.ph-duotone.ph-barbell:after { + content: "\e0b7"; + margin-left: -1em; +} +.ph-duotone.ph-barcode:before { + content: "\e0b8"; + opacity: 0.2; +} +.ph-duotone.ph-barcode:after { + content: "\e0b9"; + margin-left: -1em; +} +.ph-duotone.ph-barn:before { + content: "\ec72"; + opacity: 0.2; +} +.ph-duotone.ph-barn:after { + content: "\ec73"; + margin-left: -1em; +} +.ph-duotone.ph-barricade:before { + content: "\e948"; + opacity: 0.2; +} +.ph-duotone.ph-barricade:after { + content: "\e949"; + margin-left: -1em; +} +.ph-duotone.ph-baseball:before { + content: "\e71a"; + opacity: 0.2; +} +.ph-duotone.ph-baseball:after { + content: "\e71b"; + margin-left: -1em; +} +.ph-duotone.ph-baseball-cap:before { + content: "\ea28"; + opacity: 0.2; +} +.ph-duotone.ph-baseball-cap:after { + content: "\ea29"; + margin-left: -1em; +} +.ph-duotone.ph-baseball-helmet:before { + content: "\ee4a"; + opacity: 0.2; +} +.ph-duotone.ph-baseball-helmet:after { + content: "\ee4b"; + margin-left: -1em; +} +.ph-duotone.ph-basket:before { + content: "\e964"; + opacity: 0.2; +} +.ph-duotone.ph-basket:after { + content: "\e965"; + margin-left: -1em; +} +.ph-duotone.ph-basketball:before { + content: "\e724"; + opacity: 0.2; +} +.ph-duotone.ph-basketball:after { + content: "\e725"; + margin-left: -1em; +} +.ph-duotone.ph-bathtub:before { + content: "\e81e"; + opacity: 0.2; +} +.ph-duotone.ph-bathtub:after { + content: "\e81f"; + margin-left: -1em; +} +.ph-duotone.ph-battery-charging:before { + content: "\e0ba"; + opacity: 0.2; +} +.ph-duotone.ph-battery-charging:after { + content: "\e0bb"; + margin-left: -1em; +} +.ph-duotone.ph-battery-charging-vertical:before { + content: "\e0bc"; + opacity: 0.2; +} +.ph-duotone.ph-battery-charging-vertical:after { + content: "\e0bd"; + margin-left: -1em; +} +.ph-duotone.ph-battery-empty:before { + content: "\e0be"; + opacity: 0.2; +} +.ph-duotone.ph-battery-empty:after { + content: "\e0bf"; + margin-left: -1em; +} +.ph-duotone.ph-battery-full:before { + content: "\e0c0"; + opacity: 0.2; +} +.ph-duotone.ph-battery-full:after { + content: "\e0c1"; + margin-left: -1em; +} +.ph-duotone.ph-battery-high:before { + content: "\e0c2"; + opacity: 0.2; +} +.ph-duotone.ph-battery-high:after { + content: "\e0c3"; + margin-left: -1em; +} +.ph-duotone.ph-battery-low:before { + content: "\e0c4"; + opacity: 0.2; +} +.ph-duotone.ph-battery-low:after { + content: "\e0c5"; + margin-left: -1em; +} +.ph-duotone.ph-battery-medium:before { + content: "\e0c6"; + opacity: 0.2; +} +.ph-duotone.ph-battery-medium:after { + content: "\e0c7"; + margin-left: -1em; +} +.ph-duotone.ph-battery-plus:before { + content: "\e808"; + opacity: 0.2; +} +.ph-duotone.ph-battery-plus:after { + content: "\e809"; + margin-left: -1em; +} +.ph-duotone.ph-battery-plus-vertical:before { + content: "\ec50"; + opacity: 0.2; +} +.ph-duotone.ph-battery-plus-vertical:after { + content: "\ec51"; + margin-left: -1em; +} +.ph-duotone.ph-battery-vertical-empty:before { + content: "\e7c6"; + opacity: 0.2; +} +.ph-duotone.ph-battery-vertical-empty:after { + content: "\e7c7"; + margin-left: -1em; +} +.ph-duotone.ph-battery-vertical-full:before { + content: "\e7c4"; + opacity: 0.2; +} +.ph-duotone.ph-battery-vertical-full:after { + content: "\e7c5"; + margin-left: -1em; +} +.ph-duotone.ph-battery-vertical-high:before { + content: "\e7c2"; + opacity: 0.2; +} +.ph-duotone.ph-battery-vertical-high:after { + content: "\e7c3"; + margin-left: -1em; +} +.ph-duotone.ph-battery-vertical-low:before { + content: "\e7be"; + opacity: 0.2; +} +.ph-duotone.ph-battery-vertical-low:after { + content: "\e7bf"; + margin-left: -1em; +} +.ph-duotone.ph-battery-vertical-medium:before { + content: "\e7c0"; + opacity: 0.2; +} +.ph-duotone.ph-battery-vertical-medium:after { + content: "\e7c1"; + margin-left: -1em; +} +.ph-duotone.ph-battery-warning:before { + content: "\e0c8"; + opacity: 0.2; +} +.ph-duotone.ph-battery-warning:after { + content: "\e0c9"; + margin-left: -1em; +} +.ph-duotone.ph-battery-warning-vertical:before { + content: "\e0ca"; + opacity: 0.2; +} +.ph-duotone.ph-battery-warning-vertical:after { + content: "\e0cb"; + margin-left: -1em; +} +.ph-duotone.ph-beach-ball:before { + content: "\ed24"; + opacity: 0.2; +} +.ph-duotone.ph-beach-ball:after { + content: "\ed25"; + margin-left: -1em; +} +.ph-duotone.ph-beanie:before { + content: "\ea2a"; + opacity: 0.2; +} +.ph-duotone.ph-beanie:after { + content: "\ea2b"; + margin-left: -1em; +} +.ph-duotone.ph-bed:before { + content: "\e0cc"; + opacity: 0.2; +} +.ph-duotone.ph-bed:after { + content: "\e0cd"; + margin-left: -1em; +} +.ph-duotone.ph-beer-bottle:before { + content: "\e7b0"; + opacity: 0.2; +} +.ph-duotone.ph-beer-bottle:after { + content: "\e7b1"; + margin-left: -1em; +} +.ph-duotone.ph-beer-stein:before { + content: "\eb62"; + opacity: 0.2; +} +.ph-duotone.ph-beer-stein:after { + content: "\eb63"; + margin-left: -1em; +} +.ph-duotone.ph-behance-logo:before { + content: "\e7f4"; + opacity: 0.2; +} +.ph-duotone.ph-behance-logo:after { + content: "\e7f5"; + margin-left: -1em; +} +.ph-duotone.ph-bell:before { + content: "\e0ce"; + opacity: 0.2; +} +.ph-duotone.ph-bell:after { + content: "\e0cf"; + margin-left: -1em; +} +.ph-duotone.ph-bell-ringing:before { + content: "\e5e8"; + opacity: 0.2; +} +.ph-duotone.ph-bell-ringing:after { + content: "\e5e9"; + margin-left: -1em; +} +.ph-duotone.ph-bell-simple:before { + content: "\e0d0"; + opacity: 0.2; +} +.ph-duotone.ph-bell-simple:after { + content: "\e0d1"; + margin-left: -1em; +} +.ph-duotone.ph-bell-simple-ringing:before { + content: "\e5ea"; + opacity: 0.2; +} +.ph-duotone.ph-bell-simple-ringing:after { + content: "\e5eb"; + margin-left: -1em; +} +.ph-duotone.ph-bell-simple-slash:before { + content: "\e0d2"; + opacity: 0.2; +} +.ph-duotone.ph-bell-simple-slash:after { + content: "\e0d3"; + margin-left: -1em; +} +.ph-duotone.ph-bell-simple-z:before { + content: "\e5ec"; + opacity: 0.2; +} +.ph-duotone.ph-bell-simple-z:after { + content: "\e5ed"; + margin-left: -1em; +} +.ph-duotone.ph-bell-slash:before { + content: "\e0d4"; + opacity: 0.2; +} +.ph-duotone.ph-bell-slash:after { + content: "\e0d5"; + margin-left: -1em; +} +.ph-duotone.ph-bell-z:before { + content: "\e5ee"; + opacity: 0.2; +} +.ph-duotone.ph-bell-z:after { + content: "\e5ef"; + margin-left: -1em; +} +.ph-duotone.ph-belt:before { + content: "\ea2c"; + opacity: 0.2; +} +.ph-duotone.ph-belt:after { + content: "\ea2d"; + margin-left: -1em; +} +.ph-duotone.ph-bezier-curve:before { + content: "\eb00"; + opacity: 0.2; +} +.ph-duotone.ph-bezier-curve:after { + content: "\eb01"; + margin-left: -1em; +} +.ph-duotone.ph-bicycle:before { + content: "\e0d6"; + opacity: 0.2; +} +.ph-duotone.ph-bicycle:after { + content: "\e0d7"; + margin-left: -1em; +} +.ph-duotone.ph-binary:before { + content: "\ee60"; + opacity: 0.2; +} +.ph-duotone.ph-binary:after { + content: "\ee61"; + margin-left: -1em; +} +.ph-duotone.ph-binoculars:before { + content: "\ea64"; + opacity: 0.2; +} +.ph-duotone.ph-binoculars:after { + content: "\ea65"; + margin-left: -1em; +} +.ph-duotone.ph-biohazard:before { + content: "\e9e0"; + opacity: 0.2; +} +.ph-duotone.ph-biohazard:after { + content: "\e9e1"; + margin-left: -1em; +} +.ph-duotone.ph-bird:before { + content: "\e72c"; + opacity: 0.2; +} +.ph-duotone.ph-bird:after { + content: "\e72d"; + margin-left: -1em; +} +.ph-duotone.ph-blueprint:before { + content: "\eda0"; + opacity: 0.2; +} +.ph-duotone.ph-blueprint:after { + content: "\eda1"; + margin-left: -1em; +} +.ph-duotone.ph-bluetooth:before { + content: "\e0da"; + opacity: 0.2; +} +.ph-duotone.ph-bluetooth:after { + content: "\e0db"; + margin-left: -1em; +} +.ph-duotone.ph-bluetooth-connected:before { + content: "\e0dc"; + opacity: 0.2; +} +.ph-duotone.ph-bluetooth-connected:after { + content: "\e0dd"; + margin-left: -1em; +} +.ph-duotone.ph-bluetooth-slash:before { + content: "\e0de"; + opacity: 0.2; +} +.ph-duotone.ph-bluetooth-slash:after { + content: "\e0df"; + margin-left: -1em; +} +.ph-duotone.ph-bluetooth-x:before { + content: "\e0e0"; + opacity: 0.2; +} +.ph-duotone.ph-bluetooth-x:after { + content: "\e0e1"; + margin-left: -1em; +} +.ph-duotone.ph-boat:before { + content: "\e786"; + opacity: 0.2; +} +.ph-duotone.ph-boat:after { + content: "\e787"; + margin-left: -1em; +} +.ph-duotone.ph-bomb:before { + content: "\ee0a"; + opacity: 0.2; +} +.ph-duotone.ph-bomb:after { + content: "\ee0b"; + margin-left: -1em; +} +.ph-duotone.ph-bone:before { + content: "\e7f2"; + opacity: 0.2; +} +.ph-duotone.ph-bone:after { + content: "\e7f3"; + margin-left: -1em; +} +.ph-duotone.ph-book:before { + content: "\e0e2"; + opacity: 0.2; +} +.ph-duotone.ph-book:after { + content: "\e0e3"; + margin-left: -1em; +} +.ph-duotone.ph-book-bookmark:before { + content: "\e0e4"; + opacity: 0.2; +} +.ph-duotone.ph-book-bookmark:after { + content: "\e0e5"; + margin-left: -1em; +} +.ph-duotone.ph-book-open:before { + content: "\e0e6"; + opacity: 0.2; +} +.ph-duotone.ph-book-open:after { + content: "\e0e7"; + margin-left: -1em; +} +.ph-duotone.ph-book-open-text:before { + content: "\e8f2"; + opacity: 0.2; +} +.ph-duotone.ph-book-open-text:after { + content: "\e8f3"; + margin-left: -1em; +} +.ph-duotone.ph-book-open-user:before { + content: "\ede0"; + opacity: 0.2; +} +.ph-duotone.ph-book-open-user:after { + content: "\ede1"; + margin-left: -1em; +} +.ph-duotone.ph-bookmark:before { + content: "\e0e8"; + opacity: 0.2; +} +.ph-duotone.ph-bookmark:after { + content: "\e0e9"; + margin-left: -1em; +} +.ph-duotone.ph-bookmark-simple:before { + content: "\e0ea"; + opacity: 0.2; +} +.ph-duotone.ph-bookmark-simple:after { + content: "\e0eb"; + margin-left: -1em; +} +.ph-duotone.ph-bookmarks:before { + content: "\e0ec"; + opacity: 0.2; +} +.ph-duotone.ph-bookmarks:after { + content: "\e0ed"; + margin-left: -1em; +} +.ph-duotone.ph-bookmarks-simple:before { + content: "\e5f0"; + opacity: 0.2; +} +.ph-duotone.ph-bookmarks-simple:after { + content: "\e5f1"; + margin-left: -1em; +} +.ph-duotone.ph-books:before { + content: "\e758"; + opacity: 0.2; +} +.ph-duotone.ph-books:after { + content: "\e759"; + margin-left: -1em; +} +.ph-duotone.ph-boot:before { + content: "\ecca"; + opacity: 0.2; +} +.ph-duotone.ph-boot:after { + content: "\eccb"; + margin-left: -1em; +} +.ph-duotone.ph-boules:before { + content: "\e722"; + opacity: 0.2; +} +.ph-duotone.ph-boules:after { + content: "\e723"; + margin-left: -1em; +} +.ph-duotone.ph-bounding-box:before { + content: "\e6ce"; + opacity: 0.2; +} +.ph-duotone.ph-bounding-box:after { + content: "\e6cf"; + margin-left: -1em; +} +.ph-duotone.ph-bowl-food:before { + content: "\eaa4"; + opacity: 0.2; +} +.ph-duotone.ph-bowl-food:after { + content: "\eaa5"; + margin-left: -1em; +} +.ph-duotone.ph-bowl-steam:before { + content: "\e8e4"; + opacity: 0.2; +} +.ph-duotone.ph-bowl-steam:after { + content: "\e8e5"; + margin-left: -1em; +} +.ph-duotone.ph-bowling-ball:before { + content: "\ea34"; + opacity: 0.2; +} +.ph-duotone.ph-bowling-ball:after { + content: "\ea35"; + margin-left: -1em; +} +.ph-duotone.ph-box-arrow-down:before { + content: "\e00e"; + opacity: 0.2; +} +.ph-duotone.ph-box-arrow-down:after { + content: "\e00f"; + margin-left: -1em; +} +.ph-duotone.ph-box-arrow-up:before { + content: "\ee54"; + opacity: 0.2; +} +.ph-duotone.ph-box-arrow-up:after { + content: "\ee55"; + margin-left: -1em; +} +.ph-duotone.ph-boxing-glove:before { + content: "\ea36"; + opacity: 0.2; +} +.ph-duotone.ph-boxing-glove:after { + content: "\ea37"; + margin-left: -1em; +} +.ph-duotone.ph-brackets-angle:before { + content: "\e862"; + opacity: 0.2; +} +.ph-duotone.ph-brackets-angle:after { + content: "\e863"; + margin-left: -1em; +} +.ph-duotone.ph-brackets-curly:before { + content: "\e860"; + opacity: 0.2; +} +.ph-duotone.ph-brackets-curly:after { + content: "\e861"; + margin-left: -1em; +} +.ph-duotone.ph-brackets-round:before { + content: "\e864"; + opacity: 0.2; +} +.ph-duotone.ph-brackets-round:after { + content: "\e865"; + margin-left: -1em; +} +.ph-duotone.ph-brackets-square:before { + content: "\e85e"; + opacity: 0.2; +} +.ph-duotone.ph-brackets-square:after { + content: "\e85f"; + margin-left: -1em; +} +.ph-duotone.ph-brain:before { + content: "\e74e"; + opacity: 0.2; +} +.ph-duotone.ph-brain:after { + content: "\e74f"; + margin-left: -1em; +} +.ph-duotone.ph-brandy:before { + content: "\e6b4"; + opacity: 0.2; +} +.ph-duotone.ph-brandy:after { + content: "\e6b5"; + margin-left: -1em; +} +.ph-duotone.ph-bread:before { + content: "\e81c"; + opacity: 0.2; +} +.ph-duotone.ph-bread:after { + content: "\e81d"; + margin-left: -1em; +} +.ph-duotone.ph-bridge:before { + content: "\ea68"; + opacity: 0.2; +} +.ph-duotone.ph-bridge:after { + content: "\ea69"; + margin-left: -1em; +} +.ph-duotone.ph-briefcase:before { + content: "\e0ee"; + opacity: 0.2; +} +.ph-duotone.ph-briefcase:after { + content: "\e0ef"; + margin-left: -1em; +} +.ph-duotone.ph-briefcase-metal:before { + content: "\e5f2"; + opacity: 0.2; +} +.ph-duotone.ph-briefcase-metal:after { + content: "\e5f3"; + margin-left: -1em; +} +.ph-duotone.ph-broadcast:before { + content: "\e0f2"; + opacity: 0.2; +} +.ph-duotone.ph-broadcast:after { + content: "\e0f3"; + margin-left: -1em; +} +.ph-duotone.ph-broom:before { + content: "\ec54"; + opacity: 0.2; +} +.ph-duotone.ph-broom:after { + content: "\ec55"; + margin-left: -1em; +} +.ph-duotone.ph-browser:before { + content: "\e0f4"; + opacity: 0.2; +} +.ph-duotone.ph-browser:after { + content: "\e0f5"; + margin-left: -1em; +} +.ph-duotone.ph-browsers:before { + content: "\e0f6"; + opacity: 0.2; +} +.ph-duotone.ph-browsers:after { + content: "\e0f7"; + margin-left: -1em; +} +.ph-duotone.ph-bug:before { + content: "\e5f4"; + opacity: 0.2; +} +.ph-duotone.ph-bug:after { + content: "\e5f5"; + margin-left: -1em; +} +.ph-duotone.ph-bug-beetle:before { + content: "\e5f6"; + opacity: 0.2; +} +.ph-duotone.ph-bug-beetle:after { + content: "\e5f7"; + margin-left: -1em; +} +.ph-duotone.ph-bug-droid:before { + content: "\e5f8"; + opacity: 0.2; +} +.ph-duotone.ph-bug-droid:after { + content: "\e5f9"; + margin-left: -1em; +} +.ph-duotone.ph-building:before { + content: "\e100"; + opacity: 0.2; +} +.ph-duotone.ph-building:after { + content: "\e101"; + margin-left: -1em; +} +.ph-duotone.ph-building-apartment:before { + content: "\e0fe"; + opacity: 0.2; +} +.ph-duotone.ph-building-apartment:after { + content: "\e103"; + margin-left: -1em; +} +.ph-duotone.ph-building-office:before { + content: "\e0ff"; + opacity: 0.2; +} +.ph-duotone.ph-building-office:after { + content: "\e104"; + margin-left: -1em; +} +.ph-duotone.ph-buildings:before { + content: "\e102"; + opacity: 0.2; +} +.ph-duotone.ph-buildings:after { + content: "\e105"; + margin-left: -1em; +} +.ph-duotone.ph-bulldozer:before { + content: "\ec6c"; + opacity: 0.2; +} +.ph-duotone.ph-bulldozer:after { + content: "\ec6d"; + margin-left: -1em; +} +.ph-duotone.ph-bus:before { + content: "\e106"; + opacity: 0.2; +} +.ph-duotone.ph-bus:after { + content: "\e107"; + margin-left: -1em; +} +.ph-duotone.ph-butterfly:before { + content: "\ea6e"; + opacity: 0.2; +} +.ph-duotone.ph-butterfly:after { + content: "\ea6f"; + margin-left: -1em; +} +.ph-duotone.ph-cable-car:before { + content: "\e49c"; + opacity: 0.2; +} +.ph-duotone.ph-cable-car:after { + content: "\e49d"; + margin-left: -1em; +} +.ph-duotone.ph-cactus:before { + content: "\e918"; + opacity: 0.2; +} +.ph-duotone.ph-cactus:after { + content: "\e919"; + margin-left: -1em; +} +.ph-duotone.ph-cake:before { + content: "\e780"; + opacity: 0.2; +} +.ph-duotone.ph-cake:after { + content: "\e781"; + margin-left: -1em; +} +.ph-duotone.ph-calculator:before { + content: "\e538"; + opacity: 0.2; +} +.ph-duotone.ph-calculator:after { + content: "\e539"; + margin-left: -1em; +} +.ph-duotone.ph-calendar:before { + content: "\e108"; + opacity: 0.2; +} +.ph-duotone.ph-calendar:after { + content: "\e109"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-blank:before { + content: "\e10a"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-blank:after { + content: "\e10b"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-check:before { + content: "\e712"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-check:after { + content: "\e713"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-dot:before { + content: "\e7b2"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-dot:after { + content: "\e7b3"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-dots:before { + content: "\e7b4"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-dots:after { + content: "\e7b5"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-heart:before { + content: "\e8b0"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-heart:after { + content: "\e8b1"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-minus:before { + content: "\ea14"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-minus:after { + content: "\ea15"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-plus:before { + content: "\e714"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-plus:after { + content: "\e715"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-slash:before { + content: "\ea12"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-slash:after { + content: "\ea13"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-star:before { + content: "\e8b2"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-star:after { + content: "\e8b3"; + margin-left: -1em; +} +.ph-duotone.ph-calendar-x:before { + content: "\e10c"; + opacity: 0.2; +} +.ph-duotone.ph-calendar-x:after { + content: "\e10d"; + margin-left: -1em; +} +.ph-duotone.ph-call-bell:before { + content: "\e7de"; + opacity: 0.2; +} +.ph-duotone.ph-call-bell:after { + content: "\e7df"; + margin-left: -1em; +} +.ph-duotone.ph-camera:before { + content: "\e10e"; + opacity: 0.2; +} +.ph-duotone.ph-camera:after { + content: "\e10f"; + margin-left: -1em; +} +.ph-duotone.ph-camera-plus:before { + content: "\ec58"; + opacity: 0.2; +} +.ph-duotone.ph-camera-plus:after { + content: "\ec59"; + margin-left: -1em; +} +.ph-duotone.ph-camera-rotate:before { + content: "\e7a4"; + opacity: 0.2; +} +.ph-duotone.ph-camera-rotate:after { + content: "\e7a5"; + margin-left: -1em; +} +.ph-duotone.ph-camera-slash:before { + content: "\e110"; + opacity: 0.2; +} +.ph-duotone.ph-camera-slash:after { + content: "\e111"; + margin-left: -1em; +} +.ph-duotone.ph-campfire:before { + content: "\e9d8"; + opacity: 0.2; +} +.ph-duotone.ph-campfire:after { + content: "\e9d9"; + margin-left: -1em; +} +.ph-duotone.ph-car:before { + content: "\e112"; + opacity: 0.2; +} +.ph-duotone.ph-car:after { + content: "\e113"; + margin-left: -1em; +} +.ph-duotone.ph-car-battery:before { + content: "\ee30"; + opacity: 0.2; +} +.ph-duotone.ph-car-battery:after { + content: "\ee31"; + margin-left: -1em; +} +.ph-duotone.ph-car-profile:before { + content: "\e8cc"; + opacity: 0.2; +} +.ph-duotone.ph-car-profile:after { + content: "\e8cd"; + margin-left: -1em; +} +.ph-duotone.ph-car-simple:before { + content: "\e114"; + opacity: 0.2; +} +.ph-duotone.ph-car-simple:after { + content: "\e115"; + margin-left: -1em; +} +.ph-duotone.ph-cardholder:before { + content: "\e5fa"; + opacity: 0.2; +} +.ph-duotone.ph-cardholder:after { + content: "\e5fb"; + margin-left: -1em; +} +.ph-duotone.ph-cards:before { + content: "\e0f8"; + opacity: 0.2; +} +.ph-duotone.ph-cards:after { + content: "\e0f9"; + margin-left: -1em; +} +.ph-duotone.ph-cards-three:before { + content: "\ee50"; + opacity: 0.2; +} +.ph-duotone.ph-cards-three:after { + content: "\ee51"; + margin-left: -1em; +} +.ph-duotone.ph-caret-circle-double-down:before { + content: "\e116"; + opacity: 0.2; +} +.ph-duotone.ph-caret-circle-double-down:after { + content: "\e117"; + margin-left: -1em; +} +.ph-duotone.ph-caret-circle-double-left:before { + content: "\e118"; + opacity: 0.2; +} +.ph-duotone.ph-caret-circle-double-left:after { + content: "\e119"; + margin-left: -1em; +} +.ph-duotone.ph-caret-circle-double-right:before { + content: "\e11a"; + opacity: 0.2; +} +.ph-duotone.ph-caret-circle-double-right:after { + content: "\e11b"; + margin-left: -1em; +} +.ph-duotone.ph-caret-circle-double-up:before { + content: "\e11c"; + opacity: 0.2; +} +.ph-duotone.ph-caret-circle-double-up:after { + content: "\e11d"; + margin-left: -1em; +} +.ph-duotone.ph-caret-circle-down:before { + content: "\e11e"; + opacity: 0.2; +} +.ph-duotone.ph-caret-circle-down:after { + content: "\e11f"; + margin-left: -1em; +} +.ph-duotone.ph-caret-circle-left:before { + content: "\e120"; + opacity: 0.2; +} +.ph-duotone.ph-caret-circle-left:after { + content: "\e121"; + margin-left: -1em; +} +.ph-duotone.ph-caret-circle-right:before { + content: "\e122"; + opacity: 0.2; +} +.ph-duotone.ph-caret-circle-right:after { + content: "\e123"; + margin-left: -1em; +} +.ph-duotone.ph-caret-circle-up:before { + content: "\e124"; + opacity: 0.2; +} +.ph-duotone.ph-caret-circle-up:after { + content: "\e125"; + margin-left: -1em; +} +.ph-duotone.ph-caret-circle-up-down:before { + content: "\e13e"; + opacity: 0.2; +} +.ph-duotone.ph-caret-circle-up-down:after { + content: "\e13f"; + margin-left: -1em; +} +.ph-duotone.ph-caret-double-down:before { + content: "\e126"; + opacity: 0.2; +} +.ph-duotone.ph-caret-double-down:after { + content: "\e127"; + margin-left: -1em; +} +.ph-duotone.ph-caret-double-left:before { + content: "\e128"; + opacity: 0.2; +} +.ph-duotone.ph-caret-double-left:after { + content: "\e129"; + margin-left: -1em; +} +.ph-duotone.ph-caret-double-right:before { + content: "\e12a"; + opacity: 0.2; +} +.ph-duotone.ph-caret-double-right:after { + content: "\e12b"; + margin-left: -1em; +} +.ph-duotone.ph-caret-double-up:before { + content: "\e12c"; + opacity: 0.2; +} +.ph-duotone.ph-caret-double-up:after { + content: "\e12d"; + margin-left: -1em; +} +.ph-duotone.ph-caret-down:before { + content: "\e136"; + opacity: 0.2; +} +.ph-duotone.ph-caret-down:after { + content: "\e137"; + margin-left: -1em; +} +.ph-duotone.ph-caret-left:before { + content: "\e138"; + opacity: 0.2; +} +.ph-duotone.ph-caret-left:after { + content: "\e139"; + margin-left: -1em; +} +.ph-duotone.ph-caret-line-down:before { + content: "\e134"; + opacity: 0.2; +} +.ph-duotone.ph-caret-line-down:after { + content: "\e135"; + margin-left: -1em; +} +.ph-duotone.ph-caret-line-left:before { + content: "\e132"; + opacity: 0.2; +} +.ph-duotone.ph-caret-line-left:after { + content: "\e133"; + margin-left: -1em; +} +.ph-duotone.ph-caret-line-right:before { + content: "\e130"; + opacity: 0.2; +} +.ph-duotone.ph-caret-line-right:after { + content: "\e131"; + margin-left: -1em; +} +.ph-duotone.ph-caret-line-up:before { + content: "\e12e"; + opacity: 0.2; +} +.ph-duotone.ph-caret-line-up:after { + content: "\e12f"; + margin-left: -1em; +} +.ph-duotone.ph-caret-right:before { + content: "\e13a"; + opacity: 0.2; +} +.ph-duotone.ph-caret-right:after { + content: "\e13b"; + margin-left: -1em; +} +.ph-duotone.ph-caret-up:before { + content: "\e13c"; + opacity: 0.2; +} +.ph-duotone.ph-caret-up:after { + content: "\e13d"; + margin-left: -1em; +} +.ph-duotone.ph-caret-up-down:before { + content: "\e140"; + opacity: 0.2; +} +.ph-duotone.ph-caret-up-down:after { + content: "\e141"; + margin-left: -1em; +} +.ph-duotone.ph-carrot:before { + content: "\ed38"; + opacity: 0.2; +} +.ph-duotone.ph-carrot:after { + content: "\ed39"; + margin-left: -1em; +} +.ph-duotone.ph-cash-register:before { + content: "\ed80"; + opacity: 0.2; +} +.ph-duotone.ph-cash-register:after { + content: "\ed81"; + margin-left: -1em; +} +.ph-duotone.ph-cassette-tape:before { + content: "\ed2e"; + opacity: 0.2; +} +.ph-duotone.ph-cassette-tape:after { + content: "\ed2f"; + margin-left: -1em; +} +.ph-duotone.ph-castle-turret:before { + content: "\e9d0"; + opacity: 0.2; +} +.ph-duotone.ph-castle-turret:after { + content: "\e9d1"; + margin-left: -1em; +} +.ph-duotone.ph-cat:before { + content: "\e748"; + opacity: 0.2; +} +.ph-duotone.ph-cat:after { + content: "\e749"; + margin-left: -1em; +} +.ph-duotone.ph-cell-signal-full:before { + content: "\e142"; + opacity: 0.2; +} +.ph-duotone.ph-cell-signal-full:after { + content: "\e143"; + margin-left: -1em; +} +.ph-duotone.ph-cell-signal-high:before { + content: "\e144"; + opacity: 0.2; +} +.ph-duotone.ph-cell-signal-high:after { + content: "\e145"; + margin-left: -1em; +} +.ph-duotone.ph-cell-signal-low:before { + content: "\e146"; + opacity: 0.2; +} +.ph-duotone.ph-cell-signal-low:after { + content: "\e147"; + margin-left: -1em; +} +.ph-duotone.ph-cell-signal-medium:before { + content: "\e148"; + opacity: 0.2; +} +.ph-duotone.ph-cell-signal-medium:after { + content: "\e149"; + margin-left: -1em; +} +.ph-duotone.ph-cell-signal-none:before { + content: "\e14a"; + color: #444; +} +.ph-duotone.ph-cell-signal-slash:before { + content: "\e14c"; + opacity: 0.2; +} +.ph-duotone.ph-cell-signal-slash:after { + content: "\e14d"; + margin-left: -1em; +} +.ph-duotone.ph-cell-signal-x:before { + content: "\e14e"; + opacity: 0.2; +} +.ph-duotone.ph-cell-signal-x:after { + content: "\e14f"; + margin-left: -1em; +} +.ph-duotone.ph-cell-tower:before { + content: "\ebaa"; + opacity: 0.2; +} +.ph-duotone.ph-cell-tower:after { + content: "\ebab"; + margin-left: -1em; +} +.ph-duotone.ph-certificate:before { + content: "\e766"; + opacity: 0.2; +} +.ph-duotone.ph-certificate:after { + content: "\e767"; + margin-left: -1em; +} +.ph-duotone.ph-chair:before { + content: "\e950"; + opacity: 0.2; +} +.ph-duotone.ph-chair:after { + content: "\e951"; + margin-left: -1em; +} +.ph-duotone.ph-chalkboard:before { + content: "\e5fc"; + opacity: 0.2; +} +.ph-duotone.ph-chalkboard:after { + content: "\e5fd"; + margin-left: -1em; +} +.ph-duotone.ph-chalkboard-simple:before { + content: "\e5fe"; + opacity: 0.2; +} +.ph-duotone.ph-chalkboard-simple:after { + content: "\e5ff"; + margin-left: -1em; +} +.ph-duotone.ph-chalkboard-teacher:before { + content: "\e600"; + opacity: 0.2; +} +.ph-duotone.ph-chalkboard-teacher:after { + content: "\e601"; + margin-left: -1em; +} +.ph-duotone.ph-champagne:before { + content: "\eaca"; + opacity: 0.2; +} +.ph-duotone.ph-champagne:after { + content: "\eacb"; + margin-left: -1em; +} +.ph-duotone.ph-charging-station:before { + content: "\e8d0"; + opacity: 0.2; +} +.ph-duotone.ph-charging-station:after { + content: "\e8d1"; + margin-left: -1em; +} +.ph-duotone.ph-chart-bar:before { + content: "\e150"; + opacity: 0.2; +} +.ph-duotone.ph-chart-bar:after { + content: "\e151"; + margin-left: -1em; +} +.ph-duotone.ph-chart-bar-horizontal:before { + content: "\e152"; + opacity: 0.2; +} +.ph-duotone.ph-chart-bar-horizontal:after { + content: "\e153"; + margin-left: -1em; +} +.ph-duotone.ph-chart-donut:before { + content: "\eaa6"; + opacity: 0.2; +} +.ph-duotone.ph-chart-donut:after { + content: "\eaa7"; + margin-left: -1em; +} +.ph-duotone.ph-chart-line:before { + content: "\e154"; + opacity: 0.2; +} +.ph-duotone.ph-chart-line:after { + content: "\e155"; + margin-left: -1em; +} +.ph-duotone.ph-chart-line-down:before { + content: "\e8b6"; + opacity: 0.2; +} +.ph-duotone.ph-chart-line-down:after { + content: "\e8b7"; + margin-left: -1em; +} +.ph-duotone.ph-chart-line-up:before { + content: "\e156"; + opacity: 0.2; +} +.ph-duotone.ph-chart-line-up:after { + content: "\e157"; + margin-left: -1em; +} +.ph-duotone.ph-chart-pie:before { + content: "\e158"; + opacity: 0.2; +} +.ph-duotone.ph-chart-pie:after { + content: "\e159"; + margin-left: -1em; +} +.ph-duotone.ph-chart-pie-slice:before { + content: "\e15a"; + opacity: 0.2; +} +.ph-duotone.ph-chart-pie-slice:after { + content: "\e15b"; + margin-left: -1em; +} +.ph-duotone.ph-chart-polar:before { + content: "\eaa8"; + opacity: 0.2; +} +.ph-duotone.ph-chart-polar:after { + content: "\eaa9"; + margin-left: -1em; +} +.ph-duotone.ph-chart-scatter:before { + content: "\eaac"; + opacity: 0.2; +} +.ph-duotone.ph-chart-scatter:after { + content: "\eaad"; + margin-left: -1em; +} +.ph-duotone.ph-chat:before { + content: "\e15c"; + opacity: 0.2; +} +.ph-duotone.ph-chat:after { + content: "\e15d"; + margin-left: -1em; +} +.ph-duotone.ph-chat-centered:before { + content: "\e160"; + opacity: 0.2; +} +.ph-duotone.ph-chat-centered:after { + content: "\e161"; + margin-left: -1em; +} +.ph-duotone.ph-chat-centered-dots:before { + content: "\e164"; + opacity: 0.2; +} +.ph-duotone.ph-chat-centered-dots:after { + content: "\e165"; + margin-left: -1em; +} +.ph-duotone.ph-chat-centered-slash:before { + content: "\e162"; + opacity: 0.2; +} +.ph-duotone.ph-chat-centered-slash:after { + content: "\e163"; + margin-left: -1em; +} +.ph-duotone.ph-chat-centered-text:before { + content: "\e166"; + opacity: 0.2; +} +.ph-duotone.ph-chat-centered-text:after { + content: "\e167"; + margin-left: -1em; +} +.ph-duotone.ph-chat-circle:before { + content: "\e168"; + opacity: 0.2; +} +.ph-duotone.ph-chat-circle:after { + content: "\e169"; + margin-left: -1em; +} +.ph-duotone.ph-chat-circle-dots:before { + content: "\e16c"; + opacity: 0.2; +} +.ph-duotone.ph-chat-circle-dots:after { + content: "\e16d"; + margin-left: -1em; +} +.ph-duotone.ph-chat-circle-slash:before { + content: "\e16a"; + opacity: 0.2; +} +.ph-duotone.ph-chat-circle-slash:after { + content: "\e16b"; + margin-left: -1em; +} +.ph-duotone.ph-chat-circle-text:before { + content: "\e16e"; + opacity: 0.2; +} +.ph-duotone.ph-chat-circle-text:after { + content: "\e16f"; + margin-left: -1em; +} +.ph-duotone.ph-chat-dots:before { + content: "\e170"; + opacity: 0.2; +} +.ph-duotone.ph-chat-dots:after { + content: "\e171"; + margin-left: -1em; +} +.ph-duotone.ph-chat-slash:before { + content: "\e15e"; + opacity: 0.2; +} +.ph-duotone.ph-chat-slash:after { + content: "\e15f"; + margin-left: -1em; +} +.ph-duotone.ph-chat-teardrop:before { + content: "\e172"; + opacity: 0.2; +} +.ph-duotone.ph-chat-teardrop:after { + content: "\e173"; + margin-left: -1em; +} +.ph-duotone.ph-chat-teardrop-dots:before { + content: "\e176"; + opacity: 0.2; +} +.ph-duotone.ph-chat-teardrop-dots:after { + content: "\e177"; + margin-left: -1em; +} +.ph-duotone.ph-chat-teardrop-slash:before { + content: "\e174"; + opacity: 0.2; +} +.ph-duotone.ph-chat-teardrop-slash:after { + content: "\e175"; + margin-left: -1em; +} +.ph-duotone.ph-chat-teardrop-text:before { + content: "\e178"; + opacity: 0.2; +} +.ph-duotone.ph-chat-teardrop-text:after { + content: "\e179"; + margin-left: -1em; +} +.ph-duotone.ph-chat-text:before { + content: "\e17a"; + opacity: 0.2; +} +.ph-duotone.ph-chat-text:after { + content: "\e17b"; + margin-left: -1em; +} +.ph-duotone.ph-chats:before { + content: "\e17c"; + opacity: 0.2; +} +.ph-duotone.ph-chats:after { + content: "\e17d"; + margin-left: -1em; +} +.ph-duotone.ph-chats-circle:before { + content: "\e17e"; + opacity: 0.2; +} +.ph-duotone.ph-chats-circle:after { + content: "\e17f"; + margin-left: -1em; +} +.ph-duotone.ph-chats-teardrop:before { + content: "\e180"; + opacity: 0.2; +} +.ph-duotone.ph-chats-teardrop:after { + content: "\e181"; + margin-left: -1em; +} +.ph-duotone.ph-check:before { + content: "\e182"; + opacity: 0.2; +} +.ph-duotone.ph-check:after { + content: "\e183"; + margin-left: -1em; +} +.ph-duotone.ph-check-circle:before { + content: "\e184"; + opacity: 0.2; +} +.ph-duotone.ph-check-circle:after { + content: "\e185"; + margin-left: -1em; +} +.ph-duotone.ph-check-fat:before { + content: "\eba6"; + opacity: 0.2; +} +.ph-duotone.ph-check-fat:after { + content: "\eba7"; + margin-left: -1em; +} +.ph-duotone.ph-check-square:before { + content: "\e186"; + opacity: 0.2; +} +.ph-duotone.ph-check-square:after { + content: "\e187"; + margin-left: -1em; +} +.ph-duotone.ph-check-square-offset:before { + content: "\e188"; + opacity: 0.2; +} +.ph-duotone.ph-check-square-offset:after { + content: "\e189"; + margin-left: -1em; +} +.ph-duotone.ph-checkerboard:before { + content: "\e8c4"; + opacity: 0.2; +} +.ph-duotone.ph-checkerboard:after { + content: "\e8c5"; + margin-left: -1em; +} +.ph-duotone.ph-checks:before { + content: "\e53a"; + opacity: 0.2; +} +.ph-duotone.ph-checks:after { + content: "\e53b"; + margin-left: -1em; +} +.ph-duotone.ph-cheers:before { + content: "\ea4a"; + opacity: 0.2; +} +.ph-duotone.ph-cheers:after { + content: "\ea4b"; + margin-left: -1em; +} +.ph-duotone.ph-cheese:before { + content: "\e9fe"; + opacity: 0.2; +} +.ph-duotone.ph-cheese:after { + content: "\e9ff"; + margin-left: -1em; +} +.ph-duotone.ph-chef-hat:before { + content: "\ed8e"; + opacity: 0.2; +} +.ph-duotone.ph-chef-hat:after { + content: "\ed8f"; + margin-left: -1em; +} +.ph-duotone.ph-cherries:before { + content: "\e830"; + opacity: 0.2; +} +.ph-duotone.ph-cherries:after { + content: "\e831"; + margin-left: -1em; +} +.ph-duotone.ph-church:before { + content: "\ecea"; + opacity: 0.2; +} +.ph-duotone.ph-church:after { + content: "\eceb"; + margin-left: -1em; +} +.ph-duotone.ph-cigarette:before { + content: "\ed90"; + opacity: 0.2; +} +.ph-duotone.ph-cigarette:after { + content: "\ed91"; + margin-left: -1em; +} +.ph-duotone.ph-cigarette-slash:before { + content: "\ed92"; + opacity: 0.2; +} +.ph-duotone.ph-cigarette-slash:after { + content: "\ed93"; + margin-left: -1em; +} +.ph-duotone.ph-circle:before { + content: "\e18a"; + opacity: 0.2; +} +.ph-duotone.ph-circle:after { + content: "\e18b"; + margin-left: -1em; +} +.ph-duotone.ph-circle-dashed:before { + content: "\e602"; + opacity: 0.2; +} +.ph-duotone.ph-circle-dashed:after { + content: "\e603"; + margin-left: -1em; +} +.ph-duotone.ph-circle-half:before { + content: "\e18c"; + opacity: 0.2; +} +.ph-duotone.ph-circle-half:after { + content: "\e18d"; + margin-left: -1em; +} +.ph-duotone.ph-circle-half-tilt:before { + content: "\e18e"; + opacity: 0.2; +} +.ph-duotone.ph-circle-half-tilt:after { + content: "\e18f"; + margin-left: -1em; +} +.ph-duotone.ph-circle-notch:before { + content: "\eb44"; + opacity: 0.2; +} +.ph-duotone.ph-circle-notch:after { + content: "\eb45"; + margin-left: -1em; +} +.ph-duotone.ph-circles-four:before { + content: "\e190"; + opacity: 0.2; +} +.ph-duotone.ph-circles-four:after { + content: "\e191"; + margin-left: -1em; +} +.ph-duotone.ph-circles-three:before { + content: "\e192"; + opacity: 0.2; +} +.ph-duotone.ph-circles-three:after { + content: "\e193"; + margin-left: -1em; +} +.ph-duotone.ph-circles-three-plus:before { + content: "\e194"; + opacity: 0.2; +} +.ph-duotone.ph-circles-three-plus:after { + content: "\e195"; + margin-left: -1em; +} +.ph-duotone.ph-circuitry:before { + content: "\e9c2"; + opacity: 0.2; +} +.ph-duotone.ph-circuitry:after { + content: "\e9c3"; + margin-left: -1em; +} +.ph-duotone.ph-city:before { + content: "\ea6a"; + opacity: 0.2; +} +.ph-duotone.ph-city:after { + content: "\ea6b"; + margin-left: -1em; +} +.ph-duotone.ph-clipboard:before { + content: "\e196"; + opacity: 0.2; +} +.ph-duotone.ph-clipboard:after { + content: "\e197"; + margin-left: -1em; +} +.ph-duotone.ph-clipboard-text:before { + content: "\e198"; + opacity: 0.2; +} +.ph-duotone.ph-clipboard-text:after { + content: "\e199"; + margin-left: -1em; +} +.ph-duotone.ph-clock:before { + content: "\e19a"; + opacity: 0.2; +} +.ph-duotone.ph-clock:after { + content: "\e19b"; + margin-left: -1em; +} +.ph-duotone.ph-clock-afternoon:before { + content: "\e19c"; + opacity: 0.2; +} +.ph-duotone.ph-clock-afternoon:after { + content: "\e19d"; + margin-left: -1em; +} +.ph-duotone.ph-clock-clockwise:before { + content: "\e19e"; + opacity: 0.2; +} +.ph-duotone.ph-clock-clockwise:after { + content: "\e19f"; + margin-left: -1em; +} +.ph-duotone.ph-clock-countdown:before { + content: "\ed2c"; + opacity: 0.2; +} +.ph-duotone.ph-clock-countdown:after { + content: "\ed2d"; + margin-left: -1em; +} +.ph-duotone.ph-clock-counter-clockwise:before { + content: "\e1a0"; + opacity: 0.2; +} +.ph-duotone.ph-clock-counter-clockwise:after { + content: "\e1a1"; + margin-left: -1em; +} +.ph-duotone.ph-clock-user:before { + content: "\edec"; + opacity: 0.2; +} +.ph-duotone.ph-clock-user:after { + content: "\eded"; + margin-left: -1em; +} +.ph-duotone.ph-closed-captioning:before { + content: "\e1a4"; + opacity: 0.2; +} +.ph-duotone.ph-closed-captioning:after { + content: "\e1a5"; + margin-left: -1em; +} +.ph-duotone.ph-cloud:before { + content: "\e1aa"; + opacity: 0.2; +} +.ph-duotone.ph-cloud:after { + content: "\e1ab"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-arrow-down:before { + content: "\e1ac"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-arrow-down:after { + content: "\e1ad"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-arrow-up:before { + content: "\e1ae"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-arrow-up:after { + content: "\e1af"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-check:before { + content: "\e1b0"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-check:after { + content: "\e1b1"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-fog:before { + content: "\e53c"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-fog:after { + content: "\e53d"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-lightning:before { + content: "\e1b2"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-lightning:after { + content: "\e1b3"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-moon:before { + content: "\e53e"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-moon:after { + content: "\e53f"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-rain:before { + content: "\e1b4"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-rain:after { + content: "\e1b5"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-slash:before { + content: "\e1b6"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-slash:after { + content: "\e1b7"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-snow:before { + content: "\e1b8"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-snow:after { + content: "\e1b9"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-sun:before { + content: "\e540"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-sun:after { + content: "\e541"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-warning:before { + content: "\ea98"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-warning:after { + content: "\ea99"; + margin-left: -1em; +} +.ph-duotone.ph-cloud-x:before { + content: "\ea96"; + opacity: 0.2; +} +.ph-duotone.ph-cloud-x:after { + content: "\ea97"; + margin-left: -1em; +} +.ph-duotone.ph-clover:before { + content: "\edc8"; + opacity: 0.2; +} +.ph-duotone.ph-clover:after { + content: "\edc9"; + margin-left: -1em; +} +.ph-duotone.ph-club:before { + content: "\e1ba"; + opacity: 0.2; +} +.ph-duotone.ph-club:after { + content: "\e1bb"; + margin-left: -1em; +} +.ph-duotone.ph-coat-hanger:before { + content: "\e7fe"; + opacity: 0.2; +} +.ph-duotone.ph-coat-hanger:after { + content: "\e7ff"; + margin-left: -1em; +} +.ph-duotone.ph-coda-logo:before { + content: "\e7ce"; + opacity: 0.2; +} +.ph-duotone.ph-coda-logo:after { + content: "\e7cf"; + margin-left: -1em; +} +.ph-duotone.ph-code:before { + content: "\e1bc"; + opacity: 0.2; +} +.ph-duotone.ph-code:after { + content: "\e1bd"; + margin-left: -1em; +} +.ph-duotone.ph-code-block:before { + content: "\eafe"; + opacity: 0.2; +} +.ph-duotone.ph-code-block:after { + content: "\eaff"; + margin-left: -1em; +} +.ph-duotone.ph-code-simple:before { + content: "\e1be"; + opacity: 0.2; +} +.ph-duotone.ph-code-simple:after { + content: "\e1bf"; + margin-left: -1em; +} +.ph-duotone.ph-codepen-logo:before { + content: "\e978"; + opacity: 0.2; +} +.ph-duotone.ph-codepen-logo:after { + content: "\e979"; + margin-left: -1em; +} +.ph-duotone.ph-codesandbox-logo:before { + content: "\ea06"; + opacity: 0.2; +} +.ph-duotone.ph-codesandbox-logo:after { + content: "\ea07"; + margin-left: -1em; +} +.ph-duotone.ph-coffee:before { + content: "\e1c2"; + opacity: 0.2; +} +.ph-duotone.ph-coffee:after { + content: "\e1c3"; + margin-left: -1em; +} +.ph-duotone.ph-coffee-bean:before { + content: "\e1c0"; + opacity: 0.2; +} +.ph-duotone.ph-coffee-bean:after { + content: "\e1c1"; + margin-left: -1em; +} +.ph-duotone.ph-coin:before { + content: "\e60e"; + opacity: 0.2; +} +.ph-duotone.ph-coin:after { + content: "\e60f"; + margin-left: -1em; +} +.ph-duotone.ph-coin-vertical:before { + content: "\eb48"; + opacity: 0.2; +} +.ph-duotone.ph-coin-vertical:after { + content: "\eb49"; + margin-left: -1em; +} +.ph-duotone.ph-coins:before { + content: "\e78e"; + opacity: 0.2; +} +.ph-duotone.ph-coins:after { + content: "\e78f"; + margin-left: -1em; +} +.ph-duotone.ph-columns:before { + content: "\e546"; + opacity: 0.2; +} +.ph-duotone.ph-columns:after { + content: "\e547"; + margin-left: -1em; +} +.ph-duotone.ph-columns-plus-left:before { + content: "\e544"; + opacity: 0.2; +} +.ph-duotone.ph-columns-plus-left:after { + content: "\e545"; + margin-left: -1em; +} +.ph-duotone.ph-columns-plus-right:before { + content: "\e542"; + opacity: 0.2; +} +.ph-duotone.ph-columns-plus-right:after { + content: "\e543"; + margin-left: -1em; +} +.ph-duotone.ph-command:before { + content: "\e1c4"; + opacity: 0.2; +} +.ph-duotone.ph-command:after { + content: "\e1c5"; + margin-left: -1em; +} +.ph-duotone.ph-compass:before { + content: "\e1c8"; + opacity: 0.2; +} +.ph-duotone.ph-compass:after { + content: "\e1c9"; + margin-left: -1em; +} +.ph-duotone.ph-compass-rose:before { + content: "\e1c6"; + opacity: 0.2; +} +.ph-duotone.ph-compass-rose:after { + content: "\e1c7"; + margin-left: -1em; +} +.ph-duotone.ph-compass-tool:before { + content: "\ea0e"; + opacity: 0.2; +} +.ph-duotone.ph-compass-tool:after { + content: "\ea0f"; + margin-left: -1em; +} +.ph-duotone.ph-computer-tower:before { + content: "\e548"; + opacity: 0.2; +} +.ph-duotone.ph-computer-tower:after { + content: "\e549"; + margin-left: -1em; +} +.ph-duotone.ph-confetti:before { + content: "\e81a"; + opacity: 0.2; +} +.ph-duotone.ph-confetti:after { + content: "\e81b"; + margin-left: -1em; +} +.ph-duotone.ph-contactless-payment:before { + content: "\ed42"; + opacity: 0.2; +} +.ph-duotone.ph-contactless-payment:after { + content: "\ed43"; + margin-left: -1em; +} +.ph-duotone.ph-control:before { + content: "\eca6"; + opacity: 0.2; +} +.ph-duotone.ph-control:after { + content: "\eca7"; + margin-left: -1em; +} +.ph-duotone.ph-cookie:before { + content: "\e6ca"; + opacity: 0.2; +} +.ph-duotone.ph-cookie:after { + content: "\e6cb"; + margin-left: -1em; +} +.ph-duotone.ph-cooking-pot:before { + content: "\e764"; + opacity: 0.2; +} +.ph-duotone.ph-cooking-pot:after { + content: "\e765"; + margin-left: -1em; +} +.ph-duotone.ph-copy:before { + content: "\e1ca"; + opacity: 0.2; +} +.ph-duotone.ph-copy:after { + content: "\e1cb"; + margin-left: -1em; +} +.ph-duotone.ph-copy-simple:before { + content: "\e1cc"; + opacity: 0.2; +} +.ph-duotone.ph-copy-simple:after { + content: "\e1cd"; + margin-left: -1em; +} +.ph-duotone.ph-copyleft:before { + content: "\e86a"; + opacity: 0.2; +} +.ph-duotone.ph-copyleft:after { + content: "\e86b"; + margin-left: -1em; +} +.ph-duotone.ph-copyright:before { + content: "\e54a"; + opacity: 0.2; +} +.ph-duotone.ph-copyright:after { + content: "\e54b"; + margin-left: -1em; +} +.ph-duotone.ph-corners-in:before { + content: "\e1ce"; + opacity: 0.2; +} +.ph-duotone.ph-corners-in:after { + content: "\e1cf"; + margin-left: -1em; +} +.ph-duotone.ph-corners-out:before { + content: "\e1d0"; + opacity: 0.2; +} +.ph-duotone.ph-corners-out:after { + content: "\e1d1"; + margin-left: -1em; +} +.ph-duotone.ph-couch:before { + content: "\e7f6"; + opacity: 0.2; +} +.ph-duotone.ph-couch:after { + content: "\e7f7"; + margin-left: -1em; +} +.ph-duotone.ph-court-basketball:before { + content: "\ee36"; + opacity: 0.2; +} +.ph-duotone.ph-court-basketball:after { + content: "\ee37"; + margin-left: -1em; +} +.ph-duotone.ph-cow:before { + content: "\eabe"; + opacity: 0.2; +} +.ph-duotone.ph-cow:after { + content: "\eabf"; + margin-left: -1em; +} +.ph-duotone.ph-cowboy-hat:before { + content: "\ed12"; + opacity: 0.2; +} +.ph-duotone.ph-cowboy-hat:after { + content: "\ed13"; + margin-left: -1em; +} +.ph-duotone.ph-cpu:before { + content: "\e610"; + opacity: 0.2; +} +.ph-duotone.ph-cpu:after { + content: "\e611"; + margin-left: -1em; +} +.ph-duotone.ph-crane:before { + content: "\ed48"; + opacity: 0.2; +} +.ph-duotone.ph-crane:after { + content: "\ed4b"; + margin-left: -1em; +} +.ph-duotone.ph-crane-tower:before { + content: "\ed49"; + opacity: 0.2; +} +.ph-duotone.ph-crane-tower:after { + content: "\ed4d"; + margin-left: -1em; +} +.ph-duotone.ph-credit-card:before { + content: "\e1d2"; + opacity: 0.2; +} +.ph-duotone.ph-credit-card:after { + content: "\e1d3"; + margin-left: -1em; +} +.ph-duotone.ph-cricket:before { + content: "\ee12"; + opacity: 0.2; +} +.ph-duotone.ph-cricket:after { + content: "\ee13"; + margin-left: -1em; +} +.ph-duotone.ph-crop:before { + content: "\e1d4"; + opacity: 0.2; +} +.ph-duotone.ph-crop:after { + content: "\e1d5"; + margin-left: -1em; +} +.ph-duotone.ph-cross:before { + content: "\e8a0"; + opacity: 0.2; +} +.ph-duotone.ph-cross:after { + content: "\e8a1"; + margin-left: -1em; +} +.ph-duotone.ph-crosshair:before { + content: "\e1d6"; + opacity: 0.2; +} +.ph-duotone.ph-crosshair:after { + content: "\e1d7"; + margin-left: -1em; +} +.ph-duotone.ph-crosshair-simple:before { + content: "\e1d8"; + opacity: 0.2; +} +.ph-duotone.ph-crosshair-simple:after { + content: "\e1d9"; + margin-left: -1em; +} +.ph-duotone.ph-crown:before { + content: "\e614"; + opacity: 0.2; +} +.ph-duotone.ph-crown:after { + content: "\e615"; + margin-left: -1em; +} +.ph-duotone.ph-crown-cross:before { + content: "\ee5e"; + opacity: 0.2; +} +.ph-duotone.ph-crown-cross:after { + content: "\ee5f"; + margin-left: -1em; +} +.ph-duotone.ph-crown-simple:before { + content: "\e616"; + opacity: 0.2; +} +.ph-duotone.ph-crown-simple:after { + content: "\e617"; + margin-left: -1em; +} +.ph-duotone.ph-cube:before { + content: "\e1da"; + opacity: 0.2; +} +.ph-duotone.ph-cube:after { + content: "\e1db"; + margin-left: -1em; +} +.ph-duotone.ph-cube-focus:before { + content: "\ed0a"; + opacity: 0.2; +} +.ph-duotone.ph-cube-focus:after { + content: "\ed0b"; + margin-left: -1em; +} +.ph-duotone.ph-cube-transparent:before { + content: "\ec7c"; + opacity: 0.2; +} +.ph-duotone.ph-cube-transparent:after { + content: "\ec7d"; + margin-left: -1em; +} +.ph-duotone.ph-currency-btc:before { + content: "\e618"; + opacity: 0.2; +} +.ph-duotone.ph-currency-btc:after { + content: "\e619"; + margin-left: -1em; +} +.ph-duotone.ph-currency-circle-dollar:before { + content: "\e54c"; + opacity: 0.2; +} +.ph-duotone.ph-currency-circle-dollar:after { + content: "\e54d"; + margin-left: -1em; +} +.ph-duotone.ph-currency-cny:before { + content: "\e54e"; + opacity: 0.2; +} +.ph-duotone.ph-currency-cny:after { + content: "\e54f"; + margin-left: -1em; +} +.ph-duotone.ph-currency-dollar:before { + content: "\e550"; + opacity: 0.2; +} +.ph-duotone.ph-currency-dollar:after { + content: "\e551"; + margin-left: -1em; +} +.ph-duotone.ph-currency-dollar-simple:before { + content: "\e552"; + opacity: 0.2; +} +.ph-duotone.ph-currency-dollar-simple:after { + content: "\e553"; + margin-left: -1em; +} +.ph-duotone.ph-currency-eth:before { + content: "\eada"; + opacity: 0.2; +} +.ph-duotone.ph-currency-eth:after { + content: "\eadb"; + margin-left: -1em; +} +.ph-duotone.ph-currency-eur:before { + content: "\e554"; + opacity: 0.2; +} +.ph-duotone.ph-currency-eur:after { + content: "\e555"; + margin-left: -1em; +} +.ph-duotone.ph-currency-gbp:before { + content: "\e556"; + opacity: 0.2; +} +.ph-duotone.ph-currency-gbp:after { + content: "\e557"; + margin-left: -1em; +} +.ph-duotone.ph-currency-inr:before { + content: "\e558"; + opacity: 0.2; +} +.ph-duotone.ph-currency-inr:after { + content: "\e559"; + margin-left: -1em; +} +.ph-duotone.ph-currency-jpy:before { + content: "\e55a"; + opacity: 0.2; +} +.ph-duotone.ph-currency-jpy:after { + content: "\e55b"; + margin-left: -1em; +} +.ph-duotone.ph-currency-krw:before { + content: "\e55c"; + opacity: 0.2; +} +.ph-duotone.ph-currency-krw:after { + content: "\e55d"; + margin-left: -1em; +} +.ph-duotone.ph-currency-kzt:before { + content: "\ec4c"; + opacity: 0.2; +} +.ph-duotone.ph-currency-kzt:after { + content: "\ec4d"; + margin-left: -1em; +} +.ph-duotone.ph-currency-ngn:before { + content: "\eb52"; + opacity: 0.2; +} +.ph-duotone.ph-currency-ngn:after { + content: "\eb53"; + margin-left: -1em; +} +.ph-duotone.ph-currency-rub:before { + content: "\e55e"; + opacity: 0.2; +} +.ph-duotone.ph-currency-rub:after { + content: "\e55f"; + margin-left: -1em; +} +.ph-duotone.ph-cursor:before { + content: "\e1dc"; + opacity: 0.2; +} +.ph-duotone.ph-cursor:after { + content: "\e1dd"; + margin-left: -1em; +} +.ph-duotone.ph-cursor-click:before { + content: "\e7c8"; + opacity: 0.2; +} +.ph-duotone.ph-cursor-click:after { + content: "\e7c9"; + margin-left: -1em; +} +.ph-duotone.ph-cursor-text:before { + content: "\e7d8"; + opacity: 0.2; +} +.ph-duotone.ph-cursor-text:after { + content: "\e7d9"; + margin-left: -1em; +} +.ph-duotone.ph-cylinder:before { + content: "\e8fc"; + opacity: 0.2; +} +.ph-duotone.ph-cylinder:after { + content: "\e8fd"; + margin-left: -1em; +} +.ph-duotone.ph-database:before { + content: "\e1de"; + opacity: 0.2; +} +.ph-duotone.ph-database:after { + content: "\e1df"; + margin-left: -1em; +} +.ph-duotone.ph-desk:before { + content: "\ed16"; + opacity: 0.2; +} +.ph-duotone.ph-desk:after { + content: "\ed17"; + margin-left: -1em; +} +.ph-duotone.ph-desktop:before { + content: "\e560"; + opacity: 0.2; +} +.ph-duotone.ph-desktop:after { + content: "\e561"; + margin-left: -1em; +} +.ph-duotone.ph-desktop-tower:before { + content: "\e562"; + opacity: 0.2; +} +.ph-duotone.ph-desktop-tower:after { + content: "\e563"; + margin-left: -1em; +} +.ph-duotone.ph-detective:before { + content: "\e83e"; + opacity: 0.2; +} +.ph-duotone.ph-detective:after { + content: "\e83f"; + margin-left: -1em; +} +.ph-duotone.ph-dev-to-logo:before { + content: "\ed0e"; + opacity: 0.2; +} +.ph-duotone.ph-dev-to-logo:after { + content: "\ed0f"; + margin-left: -1em; +} +.ph-duotone.ph-device-mobile:before { + content: "\e1e0"; + opacity: 0.2; +} +.ph-duotone.ph-device-mobile:after { + content: "\e1e1"; + margin-left: -1em; +} +.ph-duotone.ph-device-mobile-camera:before { + content: "\e1e2"; + opacity: 0.2; +} +.ph-duotone.ph-device-mobile-camera:after { + content: "\e1e3"; + margin-left: -1em; +} +.ph-duotone.ph-device-mobile-slash:before { + content: "\ee46"; + opacity: 0.2; +} +.ph-duotone.ph-device-mobile-slash:after { + content: "\ee47"; + margin-left: -1em; +} +.ph-duotone.ph-device-mobile-speaker:before { + content: "\e1e4"; + opacity: 0.2; +} +.ph-duotone.ph-device-mobile-speaker:after { + content: "\e1e5"; + margin-left: -1em; +} +.ph-duotone.ph-device-rotate:before { + content: "\edf2"; + opacity: 0.2; +} +.ph-duotone.ph-device-rotate:after { + content: "\edf3"; + margin-left: -1em; +} +.ph-duotone.ph-device-tablet:before { + content: "\e1e6"; + opacity: 0.2; +} +.ph-duotone.ph-device-tablet:after { + content: "\e1e7"; + margin-left: -1em; +} +.ph-duotone.ph-device-tablet-camera:before { + content: "\e1e8"; + opacity: 0.2; +} +.ph-duotone.ph-device-tablet-camera:after { + content: "\e1e9"; + margin-left: -1em; +} +.ph-duotone.ph-device-tablet-speaker:before { + content: "\e1ea"; + opacity: 0.2; +} +.ph-duotone.ph-device-tablet-speaker:after { + content: "\e1eb"; + margin-left: -1em; +} +.ph-duotone.ph-devices:before { + content: "\eba4"; + opacity: 0.2; +} +.ph-duotone.ph-devices:after { + content: "\eba5"; + margin-left: -1em; +} +.ph-duotone.ph-diamond:before { + content: "\e1ec"; + opacity: 0.2; +} +.ph-duotone.ph-diamond:after { + content: "\e1ed"; + margin-left: -1em; +} +.ph-duotone.ph-diamonds-four:before { + content: "\e8f4"; + opacity: 0.2; +} +.ph-duotone.ph-diamonds-four:after { + content: "\e8f5"; + margin-left: -1em; +} +.ph-duotone.ph-dice-five:before { + content: "\e1ee"; + opacity: 0.2; +} +.ph-duotone.ph-dice-five:after { + content: "\e1ef"; + margin-left: -1em; +} +.ph-duotone.ph-dice-four:before { + content: "\e1f0"; + opacity: 0.2; +} +.ph-duotone.ph-dice-four:after { + content: "\e1f1"; + margin-left: -1em; +} +.ph-duotone.ph-dice-one:before { + content: "\e1f2"; + opacity: 0.2; +} +.ph-duotone.ph-dice-one:after { + content: "\e1f3"; + margin-left: -1em; +} +.ph-duotone.ph-dice-six:before { + content: "\e1f4"; + opacity: 0.2; +} +.ph-duotone.ph-dice-six:after { + content: "\e1f5"; + margin-left: -1em; +} +.ph-duotone.ph-dice-three:before { + content: "\e1f6"; + opacity: 0.2; +} +.ph-duotone.ph-dice-three:after { + content: "\e1f7"; + margin-left: -1em; +} +.ph-duotone.ph-dice-two:before { + content: "\e1f8"; + opacity: 0.2; +} +.ph-duotone.ph-dice-two:after { + content: "\e1f9"; + margin-left: -1em; +} +.ph-duotone.ph-disc:before { + content: "\e564"; + opacity: 0.2; +} +.ph-duotone.ph-disc:after { + content: "\e565"; + margin-left: -1em; +} +.ph-duotone.ph-disco-ball:before { + content: "\ed98"; + opacity: 0.2; +} +.ph-duotone.ph-disco-ball:after { + content: "\ed99"; + margin-left: -1em; +} +.ph-duotone.ph-discord-logo:before { + content: "\e61a"; + opacity: 0.2; +} +.ph-duotone.ph-discord-logo:after { + content: "\e61b"; + margin-left: -1em; +} +.ph-duotone.ph-divide:before { + content: "\e1fa"; + opacity: 0.2; +} +.ph-duotone.ph-divide:after { + content: "\e1fb"; + margin-left: -1em; +} +.ph-duotone.ph-dna:before { + content: "\e924"; + opacity: 0.2; +} +.ph-duotone.ph-dna:after { + content: "\e925"; + margin-left: -1em; +} +.ph-duotone.ph-dog:before { + content: "\e74a"; + opacity: 0.2; +} +.ph-duotone.ph-dog:after { + content: "\e74b"; + margin-left: -1em; +} +.ph-duotone.ph-door:before { + content: "\e61c"; + opacity: 0.2; +} +.ph-duotone.ph-door:after { + content: "\e61d"; + margin-left: -1em; +} +.ph-duotone.ph-door-open:before { + content: "\e7e6"; + opacity: 0.2; +} +.ph-duotone.ph-door-open:after { + content: "\e7e7"; + margin-left: -1em; +} +.ph-duotone.ph-dot:before { + content: "\ecde"; + opacity: 0.2; +} +.ph-duotone.ph-dot:after { + content: "\ecdf"; + margin-left: -1em; +} +.ph-duotone.ph-dot-outline:before { + content: "\ece0"; + opacity: 0.2; +} +.ph-duotone.ph-dot-outline:after { + content: "\ece1"; + margin-left: -1em; +} +.ph-duotone.ph-dots-nine:before { + content: "\e1fc"; + opacity: 0.2; +} +.ph-duotone.ph-dots-nine:after { + content: "\e1fd"; + margin-left: -1em; +} +.ph-duotone.ph-dots-six:before { + content: "\e794"; + opacity: 0.2; +} +.ph-duotone.ph-dots-six:after { + content: "\e795"; + margin-left: -1em; +} +.ph-duotone.ph-dots-six-vertical:before { + content: "\eae2"; + opacity: 0.2; +} +.ph-duotone.ph-dots-six-vertical:after { + content: "\eae3"; + margin-left: -1em; +} +.ph-duotone.ph-dots-three:before { + content: "\e1fe"; + opacity: 0.2; +} +.ph-duotone.ph-dots-three:after { + content: "\e1ff"; + margin-left: -1em; +} +.ph-duotone.ph-dots-three-circle:before { + content: "\e200"; + opacity: 0.2; +} +.ph-duotone.ph-dots-three-circle:after { + content: "\e201"; + margin-left: -1em; +} +.ph-duotone.ph-dots-three-circle-vertical:before { + content: "\e202"; + opacity: 0.2; +} +.ph-duotone.ph-dots-three-circle-vertical:after { + content: "\e203"; + margin-left: -1em; +} +.ph-duotone.ph-dots-three-outline:before { + content: "\e204"; + opacity: 0.2; +} +.ph-duotone.ph-dots-three-outline:after { + content: "\e205"; + margin-left: -1em; +} +.ph-duotone.ph-dots-three-outline-vertical:before { + content: "\e206"; + opacity: 0.2; +} +.ph-duotone.ph-dots-three-outline-vertical:after { + content: "\e207"; + margin-left: -1em; +} +.ph-duotone.ph-dots-three-vertical:before { + content: "\e208"; + opacity: 0.2; +} +.ph-duotone.ph-dots-three-vertical:after { + content: "\e209"; + margin-left: -1em; +} +.ph-duotone.ph-download:before { + content: "\e20a"; + opacity: 0.2; +} +.ph-duotone.ph-download:after { + content: "\e20b"; + margin-left: -1em; +} +.ph-duotone.ph-download-simple:before { + content: "\e20c"; + opacity: 0.2; +} +.ph-duotone.ph-download-simple:after { + content: "\e20d"; + margin-left: -1em; +} +.ph-duotone.ph-dress:before { + content: "\ea7e"; + opacity: 0.2; +} +.ph-duotone.ph-dress:after { + content: "\ea7f"; + margin-left: -1em; +} +.ph-duotone.ph-dresser:before { + content: "\e94e"; + opacity: 0.2; +} +.ph-duotone.ph-dresser:after { + content: "\e94f"; + margin-left: -1em; +} +.ph-duotone.ph-dribbble-logo:before { + content: "\e20e"; + opacity: 0.2; +} +.ph-duotone.ph-dribbble-logo:after { + content: "\e20f"; + margin-left: -1em; +} +.ph-duotone.ph-drone:before { + content: "\ed74"; + opacity: 0.2; +} +.ph-duotone.ph-drone:after { + content: "\ed75"; + margin-left: -1em; +} +.ph-duotone.ph-drop:before { + content: "\e210"; + opacity: 0.2; +} +.ph-duotone.ph-drop:after { + content: "\e211"; + margin-left: -1em; +} +.ph-duotone.ph-drop-half:before { + content: "\e566"; + opacity: 0.2; +} +.ph-duotone.ph-drop-half:after { + content: "\e567"; + margin-left: -1em; +} +.ph-duotone.ph-drop-half-bottom:before { + content: "\eb40"; + opacity: 0.2; +} +.ph-duotone.ph-drop-half-bottom:after { + content: "\eb41"; + margin-left: -1em; +} +.ph-duotone.ph-drop-simple:before { + content: "\ee32"; + opacity: 0.2; +} +.ph-duotone.ph-drop-simple:after { + content: "\ee33"; + margin-left: -1em; +} +.ph-duotone.ph-drop-slash:before { + content: "\e954"; + opacity: 0.2; +} +.ph-duotone.ph-drop-slash:after { + content: "\e955"; + margin-left: -1em; +} +.ph-duotone.ph-dropbox-logo:before { + content: "\e7d0"; + opacity: 0.2; +} +.ph-duotone.ph-dropbox-logo:after { + content: "\e7d1"; + margin-left: -1em; +} +.ph-duotone.ph-ear:before { + content: "\e70c"; + opacity: 0.2; +} +.ph-duotone.ph-ear:after { + content: "\e70d"; + margin-left: -1em; +} +.ph-duotone.ph-ear-slash:before { + content: "\e70e"; + opacity: 0.2; +} +.ph-duotone.ph-ear-slash:after { + content: "\e70f"; + margin-left: -1em; +} +.ph-duotone.ph-egg:before { + content: "\e812"; + opacity: 0.2; +} +.ph-duotone.ph-egg:after { + content: "\e813"; + margin-left: -1em; +} +.ph-duotone.ph-egg-crack:before { + content: "\eb64"; + opacity: 0.2; +} +.ph-duotone.ph-egg-crack:after { + content: "\eb65"; + margin-left: -1em; +} +.ph-duotone.ph-eject:before { + content: "\e212"; + opacity: 0.2; +} +.ph-duotone.ph-eject:after { + content: "\e213"; + margin-left: -1em; +} +.ph-duotone.ph-eject-simple:before { + content: "\e6ae"; + opacity: 0.2; +} +.ph-duotone.ph-eject-simple:after { + content: "\e6af"; + margin-left: -1em; +} +.ph-duotone.ph-elevator:before { + content: "\ecc0"; + opacity: 0.2; +} +.ph-duotone.ph-elevator:after { + content: "\ecc1"; + margin-left: -1em; +} +.ph-duotone.ph-empty:before { + content: "\edbc"; + opacity: 0.2; +} +.ph-duotone.ph-empty:after { + content: "\edbd"; + margin-left: -1em; +} +.ph-duotone.ph-engine:before { + content: "\ea80"; + opacity: 0.2; +} +.ph-duotone.ph-engine:after { + content: "\ea81"; + margin-left: -1em; +} +.ph-duotone.ph-envelope:before { + content: "\e214"; + opacity: 0.2; +} +.ph-duotone.ph-envelope:after { + content: "\e215"; + margin-left: -1em; +} +.ph-duotone.ph-envelope-open:before { + content: "\e216"; + opacity: 0.2; +} +.ph-duotone.ph-envelope-open:after { + content: "\e217"; + margin-left: -1em; +} +.ph-duotone.ph-envelope-simple:before { + content: "\e218"; + opacity: 0.2; +} +.ph-duotone.ph-envelope-simple:after { + content: "\e219"; + margin-left: -1em; +} +.ph-duotone.ph-envelope-simple-open:before { + content: "\e21a"; + opacity: 0.2; +} +.ph-duotone.ph-envelope-simple-open:after { + content: "\e21b"; + margin-left: -1em; +} +.ph-duotone.ph-equalizer:before { + content: "\ebbc"; + opacity: 0.2; +} +.ph-duotone.ph-equalizer:after { + content: "\ebbd"; + margin-left: -1em; +} +.ph-duotone.ph-equals:before { + content: "\e21c"; + opacity: 0.2; +} +.ph-duotone.ph-equals:after { + content: "\e21d"; + margin-left: -1em; +} +.ph-duotone.ph-eraser:before { + content: "\e21e"; + opacity: 0.2; +} +.ph-duotone.ph-eraser:after { + content: "\e21f"; + margin-left: -1em; +} +.ph-duotone.ph-escalator-down:before { + content: "\ecba"; + opacity: 0.2; +} +.ph-duotone.ph-escalator-down:after { + content: "\ecbb"; + margin-left: -1em; +} +.ph-duotone.ph-escalator-up:before { + content: "\ecbc"; + opacity: 0.2; +} +.ph-duotone.ph-escalator-up:after { + content: "\ecbd"; + margin-left: -1em; +} +.ph-duotone.ph-exam:before { + content: "\e742"; + opacity: 0.2; +} +.ph-duotone.ph-exam:after { + content: "\e743"; + margin-left: -1em; +} +.ph-duotone.ph-exclamation-mark:before { + content: "\ee44"; + opacity: 0.2; +} +.ph-duotone.ph-exclamation-mark:after { + content: "\ee45"; + margin-left: -1em; +} +.ph-duotone.ph-exclude:before { + content: "\e882"; + opacity: 0.2; +} +.ph-duotone.ph-exclude:after { + content: "\e883"; + margin-left: -1em; +} +.ph-duotone.ph-exclude-square:before { + content: "\e880"; + opacity: 0.2; +} +.ph-duotone.ph-exclude-square:after { + content: "\e881"; + margin-left: -1em; +} +.ph-duotone.ph-export:before { + content: "\eaf0"; + opacity: 0.2; +} +.ph-duotone.ph-export:after { + content: "\eaf1"; + margin-left: -1em; +} +.ph-duotone.ph-eye:before { + content: "\e220"; + opacity: 0.2; +} +.ph-duotone.ph-eye:after { + content: "\e221"; + margin-left: -1em; +} +.ph-duotone.ph-eye-closed:before { + content: "\e222"; + opacity: 0.2; +} +.ph-duotone.ph-eye-closed:after { + content: "\e223"; + margin-left: -1em; +} +.ph-duotone.ph-eye-slash:before { + content: "\e224"; + opacity: 0.2; +} +.ph-duotone.ph-eye-slash:after { + content: "\e225"; + margin-left: -1em; +} +.ph-duotone.ph-eyedropper:before { + content: "\e568"; + opacity: 0.2; +} +.ph-duotone.ph-eyedropper:after { + content: "\e569"; + margin-left: -1em; +} +.ph-duotone.ph-eyedropper-sample:before { + content: "\eac4"; + opacity: 0.2; +} +.ph-duotone.ph-eyedropper-sample:after { + content: "\eac5"; + margin-left: -1em; +} +.ph-duotone.ph-eyeglasses:before { + content: "\e7ba"; + opacity: 0.2; +} +.ph-duotone.ph-eyeglasses:after { + content: "\e7bb"; + margin-left: -1em; +} +.ph-duotone.ph-eyes:before { + content: "\ee5c"; + opacity: 0.2; +} +.ph-duotone.ph-eyes:after { + content: "\ee5d"; + margin-left: -1em; +} +.ph-duotone.ph-face-mask:before { + content: "\e56a"; + opacity: 0.2; +} +.ph-duotone.ph-face-mask:after { + content: "\e56b"; + margin-left: -1em; +} +.ph-duotone.ph-facebook-logo:before { + content: "\e226"; + opacity: 0.2; +} +.ph-duotone.ph-facebook-logo:after { + content: "\e227"; + margin-left: -1em; +} +.ph-duotone.ph-factory:before { + content: "\e760"; + opacity: 0.2; +} +.ph-duotone.ph-factory:after { + content: "\e761"; + margin-left: -1em; +} +.ph-duotone.ph-faders:before { + content: "\e228"; + opacity: 0.2; +} +.ph-duotone.ph-faders:after { + content: "\e229"; + margin-left: -1em; +} +.ph-duotone.ph-faders-horizontal:before { + content: "\e22a"; + opacity: 0.2; +} +.ph-duotone.ph-faders-horizontal:after { + content: "\e22b"; + margin-left: -1em; +} +.ph-duotone.ph-fallout-shelter:before { + content: "\e9de"; + opacity: 0.2; +} +.ph-duotone.ph-fallout-shelter:after { + content: "\e9df"; + margin-left: -1em; +} +.ph-duotone.ph-fan:before { + content: "\e9f2"; + opacity: 0.2; +} +.ph-duotone.ph-fan:after { + content: "\e9f3"; + margin-left: -1em; +} +.ph-duotone.ph-farm:before { + content: "\ec70"; + opacity: 0.2; +} +.ph-duotone.ph-farm:after { + content: "\ec71"; + margin-left: -1em; +} +.ph-duotone.ph-fast-forward:before { + content: "\e6a6"; + opacity: 0.2; +} +.ph-duotone.ph-fast-forward:after { + content: "\e6a7"; + margin-left: -1em; +} +.ph-duotone.ph-fast-forward-circle:before { + content: "\e22c"; + opacity: 0.2; +} +.ph-duotone.ph-fast-forward-circle:after { + content: "\e22d"; + margin-left: -1em; +} +.ph-duotone.ph-feather:before { + content: "\e9c0"; + opacity: 0.2; +} +.ph-duotone.ph-feather:after { + content: "\e9c1"; + margin-left: -1em; +} +.ph-duotone.ph-fediverse-logo:before { + content: "\ed66"; + opacity: 0.2; +} +.ph-duotone.ph-fediverse-logo:after { + content: "\ed67"; + margin-left: -1em; +} +.ph-duotone.ph-figma-logo:before { + content: "\e22e"; + opacity: 0.2; +} +.ph-duotone.ph-figma-logo:after { + content: "\e22f"; + margin-left: -1em; +} +.ph-duotone.ph-file:before { + content: "\e230"; + opacity: 0.2; +} +.ph-duotone.ph-file:after { + content: "\e231"; + margin-left: -1em; +} +.ph-duotone.ph-file-archive:before { + content: "\eb2a"; + opacity: 0.2; +} +.ph-duotone.ph-file-archive:after { + content: "\eb2b"; + margin-left: -1em; +} +.ph-duotone.ph-file-arrow-down:before { + content: "\e232"; + opacity: 0.2; +} +.ph-duotone.ph-file-arrow-down:after { + content: "\e233"; + margin-left: -1em; +} +.ph-duotone.ph-file-arrow-up:before { + content: "\e61e"; + opacity: 0.2; +} +.ph-duotone.ph-file-arrow-up:after { + content: "\e61f"; + margin-left: -1em; +} +.ph-duotone.ph-file-audio:before { + content: "\ea20"; + opacity: 0.2; +} +.ph-duotone.ph-file-audio:after { + content: "\ea21"; + margin-left: -1em; +} +.ph-duotone.ph-file-c:before { + content: "\eb32"; + opacity: 0.2; +} +.ph-duotone.ph-file-c:after { + content: "\eb36"; + margin-left: -1em; +} +.ph-duotone.ph-file-c-sharp:before { + content: "\eb30"; + opacity: 0.2; +} +.ph-duotone.ph-file-c-sharp:after { + content: "\eb31"; + margin-left: -1em; +} +.ph-duotone.ph-file-cloud:before { + content: "\e95e"; + opacity: 0.2; +} +.ph-duotone.ph-file-cloud:after { + content: "\e95f"; + margin-left: -1em; +} +.ph-duotone.ph-file-code:before { + content: "\e914"; + opacity: 0.2; +} +.ph-duotone.ph-file-code:after { + content: "\e915"; + margin-left: -1em; +} +.ph-duotone.ph-file-cpp:before { + content: "\eb2e"; + opacity: 0.2; +} +.ph-duotone.ph-file-cpp:after { + content: "\eb2f"; + margin-left: -1em; +} +.ph-duotone.ph-file-css:before { + content: "\eb34"; + opacity: 0.2; +} +.ph-duotone.ph-file-css:after { + content: "\eb37"; + margin-left: -1em; +} +.ph-duotone.ph-file-csv:before { + content: "\eb1c"; + opacity: 0.2; +} +.ph-duotone.ph-file-csv:after { + content: "\eb1d"; + margin-left: -1em; +} +.ph-duotone.ph-file-dashed:before { + content: "\e704"; + opacity: 0.2; +} +.ph-duotone.ph-file-dashed:after { + content: "\e705"; + margin-left: -1em; +} +.ph-duotone.ph-file-doc:before { + content: "\eb1e"; + opacity: 0.2; +} +.ph-duotone.ph-file-doc:after { + content: "\eb1f"; + margin-left: -1em; +} +.ph-duotone.ph-file-html:before { + content: "\eb38"; + opacity: 0.2; +} +.ph-duotone.ph-file-html:after { + content: "\eb39"; + margin-left: -1em; +} +.ph-duotone.ph-file-image:before { + content: "\ea24"; + opacity: 0.2; +} +.ph-duotone.ph-file-image:after { + content: "\ea25"; + margin-left: -1em; +} +.ph-duotone.ph-file-ini:before { + content: "\eb33"; + opacity: 0.2; +} +.ph-duotone.ph-file-ini:after { + content: "\eb3b"; + margin-left: -1em; +} +.ph-duotone.ph-file-jpg:before { + content: "\eb1a"; + opacity: 0.2; +} +.ph-duotone.ph-file-jpg:after { + content: "\eb1b"; + margin-left: -1em; +} +.ph-duotone.ph-file-js:before { + content: "\eb24"; + opacity: 0.2; +} +.ph-duotone.ph-file-js:after { + content: "\eb25"; + margin-left: -1em; +} +.ph-duotone.ph-file-jsx:before { + content: "\eb3a"; + opacity: 0.2; +} +.ph-duotone.ph-file-jsx:after { + content: "\eb3d"; + margin-left: -1em; +} +.ph-duotone.ph-file-lock:before { + content: "\e95c"; + opacity: 0.2; +} +.ph-duotone.ph-file-lock:after { + content: "\e95d"; + margin-left: -1em; +} +.ph-duotone.ph-file-magnifying-glass:before { + content: "\e238"; + opacity: 0.2; +} +.ph-duotone.ph-file-magnifying-glass:after { + content: "\e239"; + margin-left: -1em; +} +.ph-duotone.ph-file-md:before { + content: "\ed50"; + opacity: 0.2; +} +.ph-duotone.ph-file-md:after { + content: "\ed51"; + margin-left: -1em; +} +.ph-duotone.ph-file-minus:before { + content: "\e234"; + opacity: 0.2; +} +.ph-duotone.ph-file-minus:after { + content: "\e235"; + margin-left: -1em; +} +.ph-duotone.ph-file-pdf:before { + content: "\e702"; + opacity: 0.2; +} +.ph-duotone.ph-file-pdf:after { + content: "\e703"; + margin-left: -1em; +} +.ph-duotone.ph-file-plus:before { + content: "\e236"; + opacity: 0.2; +} +.ph-duotone.ph-file-plus:after { + content: "\e237"; + margin-left: -1em; +} +.ph-duotone.ph-file-png:before { + content: "\eb18"; + opacity: 0.2; +} +.ph-duotone.ph-file-png:after { + content: "\eb19"; + margin-left: -1em; +} +.ph-duotone.ph-file-ppt:before { + content: "\eb20"; + opacity: 0.2; +} +.ph-duotone.ph-file-ppt:after { + content: "\eb21"; + margin-left: -1em; +} +.ph-duotone.ph-file-py:before { + content: "\eb2c"; + opacity: 0.2; +} +.ph-duotone.ph-file-py:after { + content: "\eb2d"; + margin-left: -1em; +} +.ph-duotone.ph-file-rs:before { + content: "\eb28"; + opacity: 0.2; +} +.ph-duotone.ph-file-rs:after { + content: "\eb29"; + margin-left: -1em; +} +.ph-duotone.ph-file-sql:before { + content: "\ed4e"; + opacity: 0.2; +} +.ph-duotone.ph-file-sql:after { + content: "\ed4f"; + margin-left: -1em; +} +.ph-duotone.ph-file-svg:before { + content: "\ed08"; + opacity: 0.2; +} +.ph-duotone.ph-file-svg:after { + content: "\ed09"; + margin-left: -1em; +} +.ph-duotone.ph-file-text:before { + content: "\e23a"; + opacity: 0.2; +} +.ph-duotone.ph-file-text:after { + content: "\e23b"; + margin-left: -1em; +} +.ph-duotone.ph-file-ts:before { + content: "\eb26"; + opacity: 0.2; +} +.ph-duotone.ph-file-ts:after { + content: "\eb27"; + margin-left: -1em; +} +.ph-duotone.ph-file-tsx:before { + content: "\eb3c"; + opacity: 0.2; +} +.ph-duotone.ph-file-tsx:after { + content: "\eb3f"; + margin-left: -1em; +} +.ph-duotone.ph-file-txt:before { + content: "\eb35"; + opacity: 0.2; +} +.ph-duotone.ph-file-txt:after { + content: "\eb43"; + margin-left: -1em; +} +.ph-duotone.ph-file-video:before { + content: "\ea22"; + opacity: 0.2; +} +.ph-duotone.ph-file-video:after { + content: "\ea23"; + margin-left: -1em; +} +.ph-duotone.ph-file-vue:before { + content: "\eb3e"; + opacity: 0.2; +} +.ph-duotone.ph-file-vue:after { + content: "\eb47"; + margin-left: -1em; +} +.ph-duotone.ph-file-x:before { + content: "\e23c"; + opacity: 0.2; +} +.ph-duotone.ph-file-x:after { + content: "\e23d"; + margin-left: -1em; +} +.ph-duotone.ph-file-xls:before { + content: "\eb22"; + opacity: 0.2; +} +.ph-duotone.ph-file-xls:after { + content: "\eb23"; + margin-left: -1em; +} +.ph-duotone.ph-file-zip:before { + content: "\e958"; + opacity: 0.2; +} +.ph-duotone.ph-file-zip:after { + content: "\e959"; + margin-left: -1em; +} +.ph-duotone.ph-files:before { + content: "\e710"; + opacity: 0.2; +} +.ph-duotone.ph-files:after { + content: "\e711"; + margin-left: -1em; +} +.ph-duotone.ph-film-reel:before { + content: "\e8c0"; + opacity: 0.2; +} +.ph-duotone.ph-film-reel:after { + content: "\e8c1"; + margin-left: -1em; +} +.ph-duotone.ph-film-script:before { + content: "\eb50"; + opacity: 0.2; +} +.ph-duotone.ph-film-script:after { + content: "\eb51"; + margin-left: -1em; +} +.ph-duotone.ph-film-slate:before { + content: "\e8c2"; + opacity: 0.2; +} +.ph-duotone.ph-film-slate:after { + content: "\e8c3"; + margin-left: -1em; +} +.ph-duotone.ph-film-strip:before { + content: "\e792"; + opacity: 0.2; +} +.ph-duotone.ph-film-strip:after { + content: "\e793"; + margin-left: -1em; +} +.ph-duotone.ph-fingerprint:before { + content: "\e23e"; + opacity: 0.2; +} +.ph-duotone.ph-fingerprint:after { + content: "\e23f"; + margin-left: -1em; +} +.ph-duotone.ph-fingerprint-simple:before { + content: "\e240"; + opacity: 0.2; +} +.ph-duotone.ph-fingerprint-simple:after { + content: "\e241"; + margin-left: -1em; +} +.ph-duotone.ph-finn-the-human:before { + content: "\e56c"; + opacity: 0.2; +} +.ph-duotone.ph-finn-the-human:after { + content: "\e56d"; + margin-left: -1em; +} +.ph-duotone.ph-fire:before { + content: "\e242"; + opacity: 0.2; +} +.ph-duotone.ph-fire:after { + content: "\e243"; + margin-left: -1em; +} +.ph-duotone.ph-fire-extinguisher:before { + content: "\e9e8"; + opacity: 0.2; +} +.ph-duotone.ph-fire-extinguisher:after { + content: "\e9e9"; + margin-left: -1em; +} +.ph-duotone.ph-fire-simple:before { + content: "\e620"; + opacity: 0.2; +} +.ph-duotone.ph-fire-simple:after { + content: "\e621"; + margin-left: -1em; +} +.ph-duotone.ph-fire-truck:before { + content: "\e574"; + opacity: 0.2; +} +.ph-duotone.ph-fire-truck:after { + content: "\e575"; + margin-left: -1em; +} +.ph-duotone.ph-first-aid:before { + content: "\e56e"; + opacity: 0.2; +} +.ph-duotone.ph-first-aid:after { + content: "\e56f"; + margin-left: -1em; +} +.ph-duotone.ph-first-aid-kit:before { + content: "\e570"; + opacity: 0.2; +} +.ph-duotone.ph-first-aid-kit:after { + content: "\e571"; + margin-left: -1em; +} +.ph-duotone.ph-fish:before { + content: "\e728"; + opacity: 0.2; +} +.ph-duotone.ph-fish:after { + content: "\e729"; + margin-left: -1em; +} +.ph-duotone.ph-fish-simple:before { + content: "\e72a"; + opacity: 0.2; +} +.ph-duotone.ph-fish-simple:after { + content: "\e72b"; + margin-left: -1em; +} +.ph-duotone.ph-flag:before { + content: "\e244"; + opacity: 0.2; +} +.ph-duotone.ph-flag:after { + content: "\e245"; + margin-left: -1em; +} +.ph-duotone.ph-flag-banner:before { + content: "\e622"; + opacity: 0.2; +} +.ph-duotone.ph-flag-banner:after { + content: "\e623"; + margin-left: -1em; +} +.ph-duotone.ph-flag-banner-fold:before { + content: "\ecf2"; + opacity: 0.2; +} +.ph-duotone.ph-flag-banner-fold:after { + content: "\ecf3"; + margin-left: -1em; +} +.ph-duotone.ph-flag-checkered:before { + content: "\ea38"; + opacity: 0.2; +} +.ph-duotone.ph-flag-checkered:after { + content: "\ea39"; + margin-left: -1em; +} +.ph-duotone.ph-flag-pennant:before { + content: "\ecf0"; + opacity: 0.2; +} +.ph-duotone.ph-flag-pennant:after { + content: "\ecf1"; + margin-left: -1em; +} +.ph-duotone.ph-flame:before { + content: "\e624"; + opacity: 0.2; +} +.ph-duotone.ph-flame:after { + content: "\e625"; + margin-left: -1em; +} +.ph-duotone.ph-flashlight:before { + content: "\e246"; + opacity: 0.2; +} +.ph-duotone.ph-flashlight:after { + content: "\e247"; + margin-left: -1em; +} +.ph-duotone.ph-flask:before { + content: "\e79e"; + opacity: 0.2; +} +.ph-duotone.ph-flask:after { + content: "\e79f"; + margin-left: -1em; +} +.ph-duotone.ph-flip-horizontal:before { + content: "\ed6a"; + opacity: 0.2; +} +.ph-duotone.ph-flip-horizontal:after { + content: "\ed6b"; + margin-left: -1em; +} +.ph-duotone.ph-flip-vertical:before { + content: "\ed6c"; + opacity: 0.2; +} +.ph-duotone.ph-flip-vertical:after { + content: "\ed6d"; + margin-left: -1em; +} +.ph-duotone.ph-floppy-disk:before { + content: "\e248"; + opacity: 0.2; +} +.ph-duotone.ph-floppy-disk:after { + content: "\e249"; + margin-left: -1em; +} +.ph-duotone.ph-floppy-disk-back:before { + content: "\eaf4"; + opacity: 0.2; +} +.ph-duotone.ph-floppy-disk-back:after { + content: "\eaf5"; + margin-left: -1em; +} +.ph-duotone.ph-flow-arrow:before { + content: "\e6ec"; + opacity: 0.2; +} +.ph-duotone.ph-flow-arrow:after { + content: "\e6ed"; + margin-left: -1em; +} +.ph-duotone.ph-flower:before { + content: "\e75e"; + opacity: 0.2; +} +.ph-duotone.ph-flower:after { + content: "\e75f"; + margin-left: -1em; +} +.ph-duotone.ph-flower-lotus:before { + content: "\e6cc"; + opacity: 0.2; +} +.ph-duotone.ph-flower-lotus:after { + content: "\e6cd"; + margin-left: -1em; +} +.ph-duotone.ph-flower-tulip:before { + content: "\eacc"; + opacity: 0.2; +} +.ph-duotone.ph-flower-tulip:after { + content: "\eacd"; + margin-left: -1em; +} +.ph-duotone.ph-flying-saucer:before { + content: "\eb4a"; + opacity: 0.2; +} +.ph-duotone.ph-flying-saucer:after { + content: "\eb4b"; + margin-left: -1em; +} +.ph-duotone.ph-folder:before { + content: "\e24a"; + opacity: 0.2; +} +.ph-duotone.ph-folder:after { + content: "\e24b"; + margin-left: -1em; +} +.ph-duotone.ph-folder-dashed:before { + content: "\e8f8"; + opacity: 0.2; +} +.ph-duotone.ph-folder-dashed:after { + content: "\e8f9"; + margin-left: -1em; +} +.ph-duotone.ph-folder-lock:before { + content: "\ea3c"; + opacity: 0.2; +} +.ph-duotone.ph-folder-lock:after { + content: "\ea3d"; + margin-left: -1em; +} +.ph-duotone.ph-folder-minus:before { + content: "\e254"; + opacity: 0.2; +} +.ph-duotone.ph-folder-minus:after { + content: "\e255"; + margin-left: -1em; +} +.ph-duotone.ph-folder-open:before { + content: "\e256"; + opacity: 0.2; +} +.ph-duotone.ph-folder-open:after { + content: "\e257"; + margin-left: -1em; +} +.ph-duotone.ph-folder-plus:before { + content: "\e258"; + opacity: 0.2; +} +.ph-duotone.ph-folder-plus:after { + content: "\e259"; + margin-left: -1em; +} +.ph-duotone.ph-folder-simple:before { + content: "\e25a"; + opacity: 0.2; +} +.ph-duotone.ph-folder-simple:after { + content: "\e25b"; + margin-left: -1em; +} +.ph-duotone.ph-folder-simple-dashed:before { + content: "\ec2a"; + opacity: 0.2; +} +.ph-duotone.ph-folder-simple-dashed:after { + content: "\ec2b"; + margin-left: -1em; +} +.ph-duotone.ph-folder-simple-lock:before { + content: "\eb5e"; + opacity: 0.2; +} +.ph-duotone.ph-folder-simple-lock:after { + content: "\eb5f"; + margin-left: -1em; +} +.ph-duotone.ph-folder-simple-minus:before { + content: "\e25c"; + opacity: 0.2; +} +.ph-duotone.ph-folder-simple-minus:after { + content: "\e25d"; + margin-left: -1em; +} +.ph-duotone.ph-folder-simple-plus:before { + content: "\e25e"; + opacity: 0.2; +} +.ph-duotone.ph-folder-simple-plus:after { + content: "\e25f"; + margin-left: -1em; +} +.ph-duotone.ph-folder-simple-star:before { + content: "\ec2e"; + opacity: 0.2; +} +.ph-duotone.ph-folder-simple-star:after { + content: "\ec2f"; + margin-left: -1em; +} +.ph-duotone.ph-folder-simple-user:before { + content: "\eb60"; + opacity: 0.2; +} +.ph-duotone.ph-folder-simple-user:after { + content: "\eb61"; + margin-left: -1em; +} +.ph-duotone.ph-folder-star:before { + content: "\ea86"; + opacity: 0.2; +} +.ph-duotone.ph-folder-star:after { + content: "\ea87"; + margin-left: -1em; +} +.ph-duotone.ph-folder-user:before { + content: "\eb46"; + opacity: 0.2; +} +.ph-duotone.ph-folder-user:after { + content: "\eb4c"; + margin-left: -1em; +} +.ph-duotone.ph-folders:before { + content: "\e260"; + opacity: 0.2; +} +.ph-duotone.ph-folders:after { + content: "\e261"; + margin-left: -1em; +} +.ph-duotone.ph-football:before { + content: "\e718"; + opacity: 0.2; +} +.ph-duotone.ph-football:after { + content: "\e719"; + margin-left: -1em; +} +.ph-duotone.ph-football-helmet:before { + content: "\ee4c"; + opacity: 0.2; +} +.ph-duotone.ph-football-helmet:after { + content: "\ee4d"; + margin-left: -1em; +} +.ph-duotone.ph-footprints:before { + content: "\ea88"; + opacity: 0.2; +} +.ph-duotone.ph-footprints:after { + content: "\ea89"; + margin-left: -1em; +} +.ph-duotone.ph-fork-knife:before { + content: "\e262"; + opacity: 0.2; +} +.ph-duotone.ph-fork-knife:after { + content: "\e263"; + margin-left: -1em; +} +.ph-duotone.ph-four-k:before { + content: "\ea5c"; + opacity: 0.2; +} +.ph-duotone.ph-four-k:after { + content: "\ea5d"; + margin-left: -1em; +} +.ph-duotone.ph-frame-corners:before { + content: "\e626"; + opacity: 0.2; +} +.ph-duotone.ph-frame-corners:after { + content: "\e627"; + margin-left: -1em; +} +.ph-duotone.ph-framer-logo:before { + content: "\e264"; + opacity: 0.2; +} +.ph-duotone.ph-framer-logo:after { + content: "\e265"; + margin-left: -1em; +} +.ph-duotone.ph-function:before { + content: "\ebe4"; + opacity: 0.2; +} +.ph-duotone.ph-function:after { + content: "\ebe5"; + margin-left: -1em; +} +.ph-duotone.ph-funnel:before { + content: "\e266"; + opacity: 0.2; +} +.ph-duotone.ph-funnel:after { + content: "\e267"; + margin-left: -1em; +} +.ph-duotone.ph-funnel-simple:before { + content: "\e268"; + opacity: 0.2; +} +.ph-duotone.ph-funnel-simple:after { + content: "\e269"; + margin-left: -1em; +} +.ph-duotone.ph-funnel-simple-x:before { + content: "\e26a"; + opacity: 0.2; +} +.ph-duotone.ph-funnel-simple-x:after { + content: "\e26b"; + margin-left: -1em; +} +.ph-duotone.ph-funnel-x:before { + content: "\e26c"; + opacity: 0.2; +} +.ph-duotone.ph-funnel-x:after { + content: "\e26d"; + margin-left: -1em; +} +.ph-duotone.ph-game-controller:before { + content: "\e26e"; + opacity: 0.2; +} +.ph-duotone.ph-game-controller:after { + content: "\e26f"; + margin-left: -1em; +} +.ph-duotone.ph-garage:before { + content: "\ecd6"; + opacity: 0.2; +} +.ph-duotone.ph-garage:after { + content: "\ecd7"; + margin-left: -1em; +} +.ph-duotone.ph-gas-can:before { + content: "\e8ce"; + opacity: 0.2; +} +.ph-duotone.ph-gas-can:after { + content: "\e8cf"; + margin-left: -1em; +} +.ph-duotone.ph-gas-pump:before { + content: "\e768"; + opacity: 0.2; +} +.ph-duotone.ph-gas-pump:after { + content: "\e769"; + margin-left: -1em; +} +.ph-duotone.ph-gauge:before { + content: "\e628"; + opacity: 0.2; +} +.ph-duotone.ph-gauge:after { + content: "\e629"; + margin-left: -1em; +} +.ph-duotone.ph-gavel:before { + content: "\ea32"; + opacity: 0.2; +} +.ph-duotone.ph-gavel:after { + content: "\ea33"; + margin-left: -1em; +} +.ph-duotone.ph-gear:before { + content: "\e270"; + opacity: 0.2; +} +.ph-duotone.ph-gear:after { + content: "\e271"; + margin-left: -1em; +} +.ph-duotone.ph-gear-fine:before { + content: "\e87c"; + opacity: 0.2; +} +.ph-duotone.ph-gear-fine:after { + content: "\e87d"; + margin-left: -1em; +} +.ph-duotone.ph-gear-six:before { + content: "\e272"; + opacity: 0.2; +} +.ph-duotone.ph-gear-six:after { + content: "\e273"; + margin-left: -1em; +} +.ph-duotone.ph-gender-female:before { + content: "\e6e0"; + opacity: 0.2; +} +.ph-duotone.ph-gender-female:after { + content: "\e6e1"; + margin-left: -1em; +} +.ph-duotone.ph-gender-intersex:before { + content: "\e6e6"; + opacity: 0.2; +} +.ph-duotone.ph-gender-intersex:after { + content: "\e6e7"; + margin-left: -1em; +} +.ph-duotone.ph-gender-male:before { + content: "\e6e2"; + opacity: 0.2; +} +.ph-duotone.ph-gender-male:after { + content: "\e6e3"; + margin-left: -1em; +} +.ph-duotone.ph-gender-neuter:before { + content: "\e6ea"; + opacity: 0.2; +} +.ph-duotone.ph-gender-neuter:after { + content: "\e6eb"; + margin-left: -1em; +} +.ph-duotone.ph-gender-nonbinary:before { + content: "\e6e4"; + opacity: 0.2; +} +.ph-duotone.ph-gender-nonbinary:after { + content: "\e6e5"; + margin-left: -1em; +} +.ph-duotone.ph-gender-transgender:before { + content: "\e6e8"; + opacity: 0.2; +} +.ph-duotone.ph-gender-transgender:after { + content: "\e6e9"; + margin-left: -1em; +} +.ph-duotone.ph-ghost:before { + content: "\e62a"; + opacity: 0.2; +} +.ph-duotone.ph-ghost:after { + content: "\e62b"; + margin-left: -1em; +} +.ph-duotone.ph-gif:before { + content: "\e274"; + opacity: 0.2; +} +.ph-duotone.ph-gif:after { + content: "\e275"; + margin-left: -1em; +} +.ph-duotone.ph-gift:before { + content: "\e276"; + opacity: 0.2; +} +.ph-duotone.ph-gift:after { + content: "\e277"; + margin-left: -1em; +} +.ph-duotone.ph-git-branch:before { + content: "\e278"; + opacity: 0.2; +} +.ph-duotone.ph-git-branch:after { + content: "\e279"; + margin-left: -1em; +} +.ph-duotone.ph-git-commit:before { + content: "\e27a"; + opacity: 0.2; +} +.ph-duotone.ph-git-commit:after { + content: "\e27b"; + margin-left: -1em; +} +.ph-duotone.ph-git-diff:before { + content: "\e27c"; + opacity: 0.2; +} +.ph-duotone.ph-git-diff:after { + content: "\e27d"; + margin-left: -1em; +} +.ph-duotone.ph-git-fork:before { + content: "\e27e"; + opacity: 0.2; +} +.ph-duotone.ph-git-fork:after { + content: "\e27f"; + margin-left: -1em; +} +.ph-duotone.ph-git-merge:before { + content: "\e280"; + opacity: 0.2; +} +.ph-duotone.ph-git-merge:after { + content: "\e281"; + margin-left: -1em; +} +.ph-duotone.ph-git-pull-request:before { + content: "\e282"; + opacity: 0.2; +} +.ph-duotone.ph-git-pull-request:after { + content: "\e283"; + margin-left: -1em; +} +.ph-duotone.ph-github-logo:before { + content: "\e576"; + opacity: 0.2; +} +.ph-duotone.ph-github-logo:after { + content: "\e577"; + margin-left: -1em; +} +.ph-duotone.ph-gitlab-logo:before { + content: "\e694"; + opacity: 0.2; +} +.ph-duotone.ph-gitlab-logo:after { + content: "\e695"; + margin-left: -1em; +} +.ph-duotone.ph-gitlab-logo-simple:before { + content: "\e696"; + opacity: 0.2; +} +.ph-duotone.ph-gitlab-logo-simple:after { + content: "\e697"; + margin-left: -1em; +} +.ph-duotone.ph-globe:before { + content: "\e288"; + opacity: 0.2; +} +.ph-duotone.ph-globe:after { + content: "\e289"; + margin-left: -1em; +} +.ph-duotone.ph-globe-hemisphere-east:before { + content: "\e28a"; + opacity: 0.2; +} +.ph-duotone.ph-globe-hemisphere-east:after { + content: "\e28b"; + margin-left: -1em; +} +.ph-duotone.ph-globe-hemisphere-west:before { + content: "\e28c"; + opacity: 0.2; +} +.ph-duotone.ph-globe-hemisphere-west:after { + content: "\e28d"; + margin-left: -1em; +} +.ph-duotone.ph-globe-simple:before { + content: "\e28e"; + opacity: 0.2; +} +.ph-duotone.ph-globe-simple:after { + content: "\e28f"; + margin-left: -1em; +} +.ph-duotone.ph-globe-simple-x:before { + content: "\e284"; + opacity: 0.2; +} +.ph-duotone.ph-globe-simple-x:after { + content: "\e285"; + margin-left: -1em; +} +.ph-duotone.ph-globe-stand:before { + content: "\e290"; + opacity: 0.2; +} +.ph-duotone.ph-globe-stand:after { + content: "\e291"; + margin-left: -1em; +} +.ph-duotone.ph-globe-x:before { + content: "\e286"; + opacity: 0.2; +} +.ph-duotone.ph-globe-x:after { + content: "\e287"; + margin-left: -1em; +} +.ph-duotone.ph-goggles:before { + content: "\ecb4"; + opacity: 0.2; +} +.ph-duotone.ph-goggles:after { + content: "\ecb5"; + margin-left: -1em; +} +.ph-duotone.ph-golf:before { + content: "\ea3e"; + opacity: 0.2; +} +.ph-duotone.ph-golf:after { + content: "\ea3f"; + margin-left: -1em; +} +.ph-duotone.ph-goodreads-logo:before { + content: "\ed10"; + opacity: 0.2; +} +.ph-duotone.ph-goodreads-logo:after { + content: "\ed11"; + margin-left: -1em; +} +.ph-duotone.ph-google-cardboard-logo:before { + content: "\e7b6"; + opacity: 0.2; +} +.ph-duotone.ph-google-cardboard-logo:after { + content: "\e7b7"; + margin-left: -1em; +} +.ph-duotone.ph-google-chrome-logo:before { + content: "\e976"; + opacity: 0.2; +} +.ph-duotone.ph-google-chrome-logo:after { + content: "\e977"; + margin-left: -1em; +} +.ph-duotone.ph-google-drive-logo:before { + content: "\e8f6"; + opacity: 0.2; +} +.ph-duotone.ph-google-drive-logo:after { + content: "\e8f7"; + margin-left: -1em; +} +.ph-duotone.ph-google-logo:before { + content: "\e292"; + opacity: 0.2; +} +.ph-duotone.ph-google-logo:after { + content: "\e293"; + margin-left: -1em; +} +.ph-duotone.ph-google-photos-logo:before { + content: "\eb92"; + opacity: 0.2; +} +.ph-duotone.ph-google-photos-logo:after { + content: "\eb93"; + margin-left: -1em; +} +.ph-duotone.ph-google-play-logo:before { + content: "\e294"; + opacity: 0.2; +} +.ph-duotone.ph-google-play-logo:after { + content: "\e295"; + margin-left: -1em; +} +.ph-duotone.ph-google-podcasts-logo:before { + content: "\eb94"; + opacity: 0.2; +} +.ph-duotone.ph-google-podcasts-logo:after { + content: "\eb95"; + margin-left: -1em; +} +.ph-duotone.ph-gps:before { + content: "\edd8"; + opacity: 0.2; +} +.ph-duotone.ph-gps:after { + content: "\edd9"; + margin-left: -1em; +} +.ph-duotone.ph-gps-fix:before { + content: "\edd6"; + opacity: 0.2; +} +.ph-duotone.ph-gps-fix:after { + content: "\edd7"; + margin-left: -1em; +} +.ph-duotone.ph-gps-slash:before { + content: "\edd4"; + opacity: 0.2; +} +.ph-duotone.ph-gps-slash:after { + content: "\edd5"; + margin-left: -1em; +} +.ph-duotone.ph-gradient:before { + content: "\eb42"; + opacity: 0.2; +} +.ph-duotone.ph-gradient:after { + content: "\eb4d"; + margin-left: -1em; +} +.ph-duotone.ph-graduation-cap:before { + content: "\e62c"; + opacity: 0.2; +} +.ph-duotone.ph-graduation-cap:after { + content: "\e62d"; + margin-left: -1em; +} +.ph-duotone.ph-grains:before { + content: "\ec68"; + opacity: 0.2; +} +.ph-duotone.ph-grains:after { + content: "\ec69"; + margin-left: -1em; +} +.ph-duotone.ph-grains-slash:before { + content: "\ec6a"; + opacity: 0.2; +} +.ph-duotone.ph-grains-slash:after { + content: "\ec6b"; + margin-left: -1em; +} +.ph-duotone.ph-graph:before { + content: "\eb58"; + opacity: 0.2; +} +.ph-duotone.ph-graph:after { + content: "\eb59"; + margin-left: -1em; +} +.ph-duotone.ph-graphics-card:before { + content: "\e612"; + opacity: 0.2; +} +.ph-duotone.ph-graphics-card:after { + content: "\e613"; + margin-left: -1em; +} +.ph-duotone.ph-greater-than:before { + content: "\edc4"; + opacity: 0.2; +} +.ph-duotone.ph-greater-than:after { + content: "\edc5"; + margin-left: -1em; +} +.ph-duotone.ph-greater-than-or-equal:before { + content: "\eda2"; + opacity: 0.2; +} +.ph-duotone.ph-greater-than-or-equal:after { + content: "\eda3"; + margin-left: -1em; +} +.ph-duotone.ph-grid-four:before { + content: "\e296"; + opacity: 0.2; +} +.ph-duotone.ph-grid-four:after { + content: "\e297"; + margin-left: -1em; +} +.ph-duotone.ph-grid-nine:before { + content: "\ec8c"; + opacity: 0.2; +} +.ph-duotone.ph-grid-nine:after { + content: "\ec8d"; + margin-left: -1em; +} +.ph-duotone.ph-guitar:before { + content: "\ea8a"; + opacity: 0.2; +} +.ph-duotone.ph-guitar:after { + content: "\ea8b"; + margin-left: -1em; +} +.ph-duotone.ph-hair-dryer:before { + content: "\ea66"; + opacity: 0.2; +} +.ph-duotone.ph-hair-dryer:after { + content: "\ea67"; + margin-left: -1em; +} +.ph-duotone.ph-hamburger:before { + content: "\e790"; + opacity: 0.2; +} +.ph-duotone.ph-hamburger:after { + content: "\e791"; + margin-left: -1em; +} +.ph-duotone.ph-hammer:before { + content: "\e80e"; + opacity: 0.2; +} +.ph-duotone.ph-hammer:after { + content: "\e80f"; + margin-left: -1em; +} +.ph-duotone.ph-hand:before { + content: "\e298"; + opacity: 0.2; +} +.ph-duotone.ph-hand:after { + content: "\e299"; + margin-left: -1em; +} +.ph-duotone.ph-hand-arrow-down:before { + content: "\ea4e"; + opacity: 0.2; +} +.ph-duotone.ph-hand-arrow-down:after { + content: "\ea4f"; + margin-left: -1em; +} +.ph-duotone.ph-hand-arrow-up:before { + content: "\ee5a"; + opacity: 0.2; +} +.ph-duotone.ph-hand-arrow-up:after { + content: "\ee5b"; + margin-left: -1em; +} +.ph-duotone.ph-hand-coins:before { + content: "\ea8c"; + opacity: 0.2; +} +.ph-duotone.ph-hand-coins:after { + content: "\ea8d"; + margin-left: -1em; +} +.ph-duotone.ph-hand-deposit:before { + content: "\ee82"; + opacity: 0.2; +} +.ph-duotone.ph-hand-deposit:after { + content: "\ee83"; + margin-left: -1em; +} +.ph-duotone.ph-hand-eye:before { + content: "\ea4c"; + opacity: 0.2; +} +.ph-duotone.ph-hand-eye:after { + content: "\ea4d"; + margin-left: -1em; +} +.ph-duotone.ph-hand-fist:before { + content: "\e57a"; + opacity: 0.2; +} +.ph-duotone.ph-hand-fist:after { + content: "\e57b"; + margin-left: -1em; +} +.ph-duotone.ph-hand-grabbing:before { + content: "\e57c"; + opacity: 0.2; +} +.ph-duotone.ph-hand-grabbing:after { + content: "\e57d"; + margin-left: -1em; +} +.ph-duotone.ph-hand-heart:before { + content: "\e810"; + opacity: 0.2; +} +.ph-duotone.ph-hand-heart:after { + content: "\e811"; + margin-left: -1em; +} +.ph-duotone.ph-hand-palm:before { + content: "\e57e"; + opacity: 0.2; +} +.ph-duotone.ph-hand-palm:after { + content: "\e57f"; + margin-left: -1em; +} +.ph-duotone.ph-hand-peace:before { + content: "\e7cc"; + opacity: 0.2; +} +.ph-duotone.ph-hand-peace:after { + content: "\e7cd"; + margin-left: -1em; +} +.ph-duotone.ph-hand-pointing:before { + content: "\e29a"; + opacity: 0.2; +} +.ph-duotone.ph-hand-pointing:after { + content: "\e29b"; + margin-left: -1em; +} +.ph-duotone.ph-hand-soap:before { + content: "\e630"; + opacity: 0.2; +} +.ph-duotone.ph-hand-soap:after { + content: "\e631"; + margin-left: -1em; +} +.ph-duotone.ph-hand-swipe-left:before { + content: "\ec94"; + opacity: 0.2; +} +.ph-duotone.ph-hand-swipe-left:after { + content: "\ec95"; + margin-left: -1em; +} +.ph-duotone.ph-hand-swipe-right:before { + content: "\ec92"; + opacity: 0.2; +} +.ph-duotone.ph-hand-swipe-right:after { + content: "\ec93"; + margin-left: -1em; +} +.ph-duotone.ph-hand-tap:before { + content: "\ec90"; + opacity: 0.2; +} +.ph-duotone.ph-hand-tap:after { + content: "\ec91"; + margin-left: -1em; +} +.ph-duotone.ph-hand-waving:before { + content: "\e580"; + opacity: 0.2; +} +.ph-duotone.ph-hand-waving:after { + content: "\e581"; + margin-left: -1em; +} +.ph-duotone.ph-hand-withdraw:before { + content: "\ee80"; + opacity: 0.2; +} +.ph-duotone.ph-hand-withdraw:after { + content: "\ee81"; + margin-left: -1em; +} +.ph-duotone.ph-handbag:before { + content: "\e29c"; + opacity: 0.2; +} +.ph-duotone.ph-handbag:after { + content: "\e29d"; + margin-left: -1em; +} +.ph-duotone.ph-handbag-simple:before { + content: "\e62e"; + opacity: 0.2; +} +.ph-duotone.ph-handbag-simple:after { + content: "\e62f"; + margin-left: -1em; +} +.ph-duotone.ph-hands-clapping:before { + content: "\e6a0"; + opacity: 0.2; +} +.ph-duotone.ph-hands-clapping:after { + content: "\e6a1"; + margin-left: -1em; +} +.ph-duotone.ph-hands-praying:before { + content: "\ecc8"; + opacity: 0.2; +} +.ph-duotone.ph-hands-praying:after { + content: "\ecc9"; + margin-left: -1em; +} +.ph-duotone.ph-handshake:before { + content: "\e582"; + opacity: 0.2; +} +.ph-duotone.ph-handshake:after { + content: "\e583"; + margin-left: -1em; +} +.ph-duotone.ph-hard-drive:before { + content: "\e29e"; + opacity: 0.2; +} +.ph-duotone.ph-hard-drive:after { + content: "\e29f"; + margin-left: -1em; +} +.ph-duotone.ph-hard-drives:before { + content: "\e2a0"; + opacity: 0.2; +} +.ph-duotone.ph-hard-drives:after { + content: "\e2a1"; + margin-left: -1em; +} +.ph-duotone.ph-hard-hat:before { + content: "\ed46"; + opacity: 0.2; +} +.ph-duotone.ph-hard-hat:after { + content: "\ed47"; + margin-left: -1em; +} +.ph-duotone.ph-hash:before { + content: "\e2a2"; + opacity: 0.2; +} +.ph-duotone.ph-hash:after { + content: "\e2a3"; + margin-left: -1em; +} +.ph-duotone.ph-hash-straight:before { + content: "\e2a4"; + opacity: 0.2; +} +.ph-duotone.ph-hash-straight:after { + content: "\e2a5"; + margin-left: -1em; +} +.ph-duotone.ph-head-circuit:before { + content: "\e7d4"; + opacity: 0.2; +} +.ph-duotone.ph-head-circuit:after { + content: "\e7d5"; + margin-left: -1em; +} +.ph-duotone.ph-headlights:before { + content: "\e6fe"; + opacity: 0.2; +} +.ph-duotone.ph-headlights:after { + content: "\e6ff"; + margin-left: -1em; +} +.ph-duotone.ph-headphones:before { + content: "\e2a6"; + opacity: 0.2; +} +.ph-duotone.ph-headphones:after { + content: "\e2a7"; + margin-left: -1em; +} +.ph-duotone.ph-headset:before { + content: "\e584"; + opacity: 0.2; +} +.ph-duotone.ph-headset:after { + content: "\e585"; + margin-left: -1em; +} +.ph-duotone.ph-heart:before { + content: "\e2a8"; + opacity: 0.2; +} +.ph-duotone.ph-heart:after { + content: "\e2a9"; + margin-left: -1em; +} +.ph-duotone.ph-heart-break:before { + content: "\ebe8"; + opacity: 0.2; +} +.ph-duotone.ph-heart-break:after { + content: "\ebe9"; + margin-left: -1em; +} +.ph-duotone.ph-heart-half:before { + content: "\ec48"; + opacity: 0.2; +} +.ph-duotone.ph-heart-half:after { + content: "\ec49"; + margin-left: -1em; +} +.ph-duotone.ph-heart-straight:before { + content: "\e2aa"; + opacity: 0.2; +} +.ph-duotone.ph-heart-straight:after { + content: "\e2ab"; + margin-left: -1em; +} +.ph-duotone.ph-heart-straight-break:before { + content: "\eb98"; + opacity: 0.2; +} +.ph-duotone.ph-heart-straight-break:after { + content: "\eb99"; + margin-left: -1em; +} +.ph-duotone.ph-heartbeat:before { + content: "\e2ac"; + opacity: 0.2; +} +.ph-duotone.ph-heartbeat:after { + content: "\e2ad"; + margin-left: -1em; +} +.ph-duotone.ph-hexagon:before { + content: "\e2ae"; + opacity: 0.2; +} +.ph-duotone.ph-hexagon:after { + content: "\e2af"; + margin-left: -1em; +} +.ph-duotone.ph-high-definition:before { + content: "\ea8e"; + opacity: 0.2; +} +.ph-duotone.ph-high-definition:after { + content: "\ea8f"; + margin-left: -1em; +} +.ph-duotone.ph-high-heel:before { + content: "\e8e8"; + opacity: 0.2; +} +.ph-duotone.ph-high-heel:after { + content: "\e8e9"; + margin-left: -1em; +} +.ph-duotone.ph-highlighter:before { + content: "\ec76"; + opacity: 0.2; +} +.ph-duotone.ph-highlighter:after { + content: "\ec77"; + margin-left: -1em; +} +.ph-duotone.ph-highlighter-circle:before { + content: "\e632"; + opacity: 0.2; +} +.ph-duotone.ph-highlighter-circle:after { + content: "\e633"; + margin-left: -1em; +} +.ph-duotone.ph-hockey:before { + content: "\ec86"; + opacity: 0.2; +} +.ph-duotone.ph-hockey:after { + content: "\ec87"; + margin-left: -1em; +} +.ph-duotone.ph-hoodie:before { + content: "\ecd0"; + opacity: 0.2; +} +.ph-duotone.ph-hoodie:after { + content: "\ecd1"; + margin-left: -1em; +} +.ph-duotone.ph-horse:before { + content: "\e2b0"; + opacity: 0.2; +} +.ph-duotone.ph-horse:after { + content: "\e2b1"; + margin-left: -1em; +} +.ph-duotone.ph-hospital:before { + content: "\e844"; + opacity: 0.2; +} +.ph-duotone.ph-hospital:after { + content: "\e845"; + margin-left: -1em; +} +.ph-duotone.ph-hourglass:before { + content: "\e2b2"; + opacity: 0.2; +} +.ph-duotone.ph-hourglass:after { + content: "\e2b3"; + margin-left: -1em; +} +.ph-duotone.ph-hourglass-high:before { + content: "\e2b4"; + opacity: 0.2; +} +.ph-duotone.ph-hourglass-high:after { + content: "\e2b5"; + margin-left: -1em; +} +.ph-duotone.ph-hourglass-low:before { + content: "\e2b6"; + opacity: 0.2; +} +.ph-duotone.ph-hourglass-low:after { + content: "\e2b7"; + margin-left: -1em; +} +.ph-duotone.ph-hourglass-medium:before { + content: "\e2b8"; + opacity: 0.2; +} +.ph-duotone.ph-hourglass-medium:after { + content: "\e2b9"; + margin-left: -1em; +} +.ph-duotone.ph-hourglass-simple:before { + content: "\e2ba"; + opacity: 0.2; +} +.ph-duotone.ph-hourglass-simple:after { + content: "\e2bb"; + margin-left: -1em; +} +.ph-duotone.ph-hourglass-simple-high:before { + content: "\e2bc"; + opacity: 0.2; +} +.ph-duotone.ph-hourglass-simple-high:after { + content: "\e2bd"; + margin-left: -1em; +} +.ph-duotone.ph-hourglass-simple-low:before { + content: "\e2be"; + opacity: 0.2; +} +.ph-duotone.ph-hourglass-simple-low:after { + content: "\e2bf"; + margin-left: -1em; +} +.ph-duotone.ph-hourglass-simple-medium:before { + content: "\e2c0"; + opacity: 0.2; +} +.ph-duotone.ph-hourglass-simple-medium:after { + content: "\e2c1"; + margin-left: -1em; +} +.ph-duotone.ph-house:before { + content: "\e2c2"; + opacity: 0.2; +} +.ph-duotone.ph-house:after { + content: "\e2c3"; + margin-left: -1em; +} +.ph-duotone.ph-house-line:before { + content: "\e2c4"; + opacity: 0.2; +} +.ph-duotone.ph-house-line:after { + content: "\e2c5"; + margin-left: -1em; +} +.ph-duotone.ph-house-simple:before { + content: "\e2c6"; + opacity: 0.2; +} +.ph-duotone.ph-house-simple:after { + content: "\e2c7"; + margin-left: -1em; +} +.ph-duotone.ph-hurricane:before { + content: "\e88e"; + opacity: 0.2; +} +.ph-duotone.ph-hurricane:after { + content: "\e88f"; + margin-left: -1em; +} +.ph-duotone.ph-ice-cream:before { + content: "\e804"; + opacity: 0.2; +} +.ph-duotone.ph-ice-cream:after { + content: "\e805"; + margin-left: -1em; +} +.ph-duotone.ph-identification-badge:before { + content: "\e6f6"; + opacity: 0.2; +} +.ph-duotone.ph-identification-badge:after { + content: "\e6f7"; + margin-left: -1em; +} +.ph-duotone.ph-identification-card:before { + content: "\e2c8"; + opacity: 0.2; +} +.ph-duotone.ph-identification-card:after { + content: "\e2c9"; + margin-left: -1em; +} +.ph-duotone.ph-image:before { + content: "\e2ca"; + opacity: 0.2; +} +.ph-duotone.ph-image:after { + content: "\e2cb"; + margin-left: -1em; +} +.ph-duotone.ph-image-broken:before { + content: "\e7a8"; + opacity: 0.2; +} +.ph-duotone.ph-image-broken:after { + content: "\e7a9"; + margin-left: -1em; +} +.ph-duotone.ph-image-square:before { + content: "\e2cc"; + opacity: 0.2; +} +.ph-duotone.ph-image-square:after { + content: "\e2cd"; + margin-left: -1em; +} +.ph-duotone.ph-images:before { + content: "\e836"; + opacity: 0.2; +} +.ph-duotone.ph-images:after { + content: "\e837"; + margin-left: -1em; +} +.ph-duotone.ph-images-square:before { + content: "\e834"; + opacity: 0.2; +} +.ph-duotone.ph-images-square:after { + content: "\e835"; + margin-left: -1em; +} +.ph-duotone.ph-infinity:before { + content: "\e634"; + opacity: 0.2; +} +.ph-duotone.ph-infinity:after { + content: "\e635"; + margin-left: -1em; +} +.ph-duotone.ph-info:before { + content: "\e2ce"; + opacity: 0.2; +} +.ph-duotone.ph-info:after { + content: "\e2cf"; + margin-left: -1em; +} +.ph-duotone.ph-instagram-logo:before { + content: "\e2d0"; + opacity: 0.2; +} +.ph-duotone.ph-instagram-logo:after { + content: "\e2d1"; + margin-left: -1em; +} +.ph-duotone.ph-intersect:before { + content: "\e2d2"; + opacity: 0.2; +} +.ph-duotone.ph-intersect:after { + content: "\e2d3"; + margin-left: -1em; +} +.ph-duotone.ph-intersect-square:before { + content: "\e87a"; + opacity: 0.2; +} +.ph-duotone.ph-intersect-square:after { + content: "\e87b"; + margin-left: -1em; +} +.ph-duotone.ph-intersect-three:before { + content: "\ecc4"; + opacity: 0.2; +} +.ph-duotone.ph-intersect-three:after { + content: "\ecc5"; + margin-left: -1em; +} +.ph-duotone.ph-intersection:before { + content: "\edba"; + opacity: 0.2; +} +.ph-duotone.ph-intersection:after { + content: "\edbb"; + margin-left: -1em; +} +.ph-duotone.ph-invoice:before { + content: "\ee42"; + opacity: 0.2; +} +.ph-duotone.ph-invoice:after { + content: "\ee43"; + margin-left: -1em; +} +.ph-duotone.ph-island:before { + content: "\ee06"; + opacity: 0.2; +} +.ph-duotone.ph-island:after { + content: "\ee07"; + margin-left: -1em; +} +.ph-duotone.ph-jar:before { + content: "\e7e0"; + opacity: 0.2; +} +.ph-duotone.ph-jar:after { + content: "\e7e3"; + margin-left: -1em; +} +.ph-duotone.ph-jar-label:before { + content: "\e7e1"; + opacity: 0.2; +} +.ph-duotone.ph-jar-label:after { + content: "\e7e5"; + margin-left: -1em; +} +.ph-duotone.ph-jeep:before { + content: "\e2d4"; + opacity: 0.2; +} +.ph-duotone.ph-jeep:after { + content: "\e2d5"; + margin-left: -1em; +} +.ph-duotone.ph-joystick:before { + content: "\ea5e"; + opacity: 0.2; +} +.ph-duotone.ph-joystick:after { + content: "\ea5f"; + margin-left: -1em; +} +.ph-duotone.ph-kanban:before { + content: "\eb54"; + opacity: 0.2; +} +.ph-duotone.ph-kanban:after { + content: "\eb55"; + margin-left: -1em; +} +.ph-duotone.ph-key:before { + content: "\e2d6"; + opacity: 0.2; +} +.ph-duotone.ph-key:after { + content: "\e2d7"; + margin-left: -1em; +} +.ph-duotone.ph-key-return:before { + content: "\e782"; + opacity: 0.2; +} +.ph-duotone.ph-key-return:after { + content: "\e783"; + margin-left: -1em; +} +.ph-duotone.ph-keyboard:before { + content: "\e2d8"; + opacity: 0.2; +} +.ph-duotone.ph-keyboard:after { + content: "\e2d9"; + margin-left: -1em; +} +.ph-duotone.ph-keyhole:before { + content: "\ea78"; + opacity: 0.2; +} +.ph-duotone.ph-keyhole:after { + content: "\ea79"; + margin-left: -1em; +} +.ph-duotone.ph-knife:before { + content: "\e636"; + opacity: 0.2; +} +.ph-duotone.ph-knife:after { + content: "\e637"; + margin-left: -1em; +} +.ph-duotone.ph-ladder:before { + content: "\e9e4"; + opacity: 0.2; +} +.ph-duotone.ph-ladder:after { + content: "\e9e5"; + margin-left: -1em; +} +.ph-duotone.ph-ladder-simple:before { + content: "\ec26"; + opacity: 0.2; +} +.ph-duotone.ph-ladder-simple:after { + content: "\ec27"; + margin-left: -1em; +} +.ph-duotone.ph-lamp:before { + content: "\e638"; + opacity: 0.2; +} +.ph-duotone.ph-lamp:after { + content: "\e639"; + margin-left: -1em; +} +.ph-duotone.ph-lamp-pendant:before { + content: "\ee2e"; + opacity: 0.2; +} +.ph-duotone.ph-lamp-pendant:after { + content: "\ee2f"; + margin-left: -1em; +} +.ph-duotone.ph-laptop:before { + content: "\e586"; + opacity: 0.2; +} +.ph-duotone.ph-laptop:after { + content: "\e587"; + margin-left: -1em; +} +.ph-duotone.ph-lasso:before { + content: "\edc6"; + opacity: 0.2; +} +.ph-duotone.ph-lasso:after { + content: "\edc7"; + margin-left: -1em; +} +.ph-duotone.ph-lastfm-logo:before { + content: "\e842"; + opacity: 0.2; +} +.ph-duotone.ph-lastfm-logo:after { + content: "\e843"; + margin-left: -1em; +} +.ph-duotone.ph-layout:before { + content: "\e6d6"; + opacity: 0.2; +} +.ph-duotone.ph-layout:after { + content: "\e6d7"; + margin-left: -1em; +} +.ph-duotone.ph-leaf:before { + content: "\e2da"; + opacity: 0.2; +} +.ph-duotone.ph-leaf:after { + content: "\e2db"; + margin-left: -1em; +} +.ph-duotone.ph-lectern:before { + content: "\e95a"; + opacity: 0.2; +} +.ph-duotone.ph-lectern:after { + content: "\e95b"; + margin-left: -1em; +} +.ph-duotone.ph-lego:before { + content: "\e8c6"; + opacity: 0.2; +} +.ph-duotone.ph-lego:after { + content: "\e8c8"; + margin-left: -1em; +} +.ph-duotone.ph-lego-smiley:before { + content: "\e8c7"; + opacity: 0.2; +} +.ph-duotone.ph-lego-smiley:after { + content: "\e8c9"; + margin-left: -1em; +} +.ph-duotone.ph-less-than:before { + content: "\edac"; + opacity: 0.2; +} +.ph-duotone.ph-less-than:after { + content: "\edad"; + margin-left: -1em; +} +.ph-duotone.ph-less-than-or-equal:before { + content: "\eda4"; + opacity: 0.2; +} +.ph-duotone.ph-less-than-or-equal:after { + content: "\eda5"; + margin-left: -1em; +} +.ph-duotone.ph-letter-circle-h:before { + content: "\ebf8"; + opacity: 0.2; +} +.ph-duotone.ph-letter-circle-h:after { + content: "\ebf9"; + margin-left: -1em; +} +.ph-duotone.ph-letter-circle-p:before { + content: "\ec08"; + opacity: 0.2; +} +.ph-duotone.ph-letter-circle-p:after { + content: "\ec09"; + margin-left: -1em; +} +.ph-duotone.ph-letter-circle-v:before { + content: "\ec14"; + opacity: 0.2; +} +.ph-duotone.ph-letter-circle-v:after { + content: "\ec15"; + margin-left: -1em; +} +.ph-duotone.ph-lifebuoy:before { + content: "\e63a"; + opacity: 0.2; +} +.ph-duotone.ph-lifebuoy:after { + content: "\e63b"; + margin-left: -1em; +} +.ph-duotone.ph-lightbulb:before { + content: "\e2dc"; + opacity: 0.2; +} +.ph-duotone.ph-lightbulb:after { + content: "\e2dd"; + margin-left: -1em; +} +.ph-duotone.ph-lightbulb-filament:before { + content: "\e63c"; + opacity: 0.2; +} +.ph-duotone.ph-lightbulb-filament:after { + content: "\e63d"; + margin-left: -1em; +} +.ph-duotone.ph-lighthouse:before { + content: "\e9f6"; + opacity: 0.2; +} +.ph-duotone.ph-lighthouse:after { + content: "\e9f7"; + margin-left: -1em; +} +.ph-duotone.ph-lightning:before { + content: "\e2de"; + opacity: 0.2; +} +.ph-duotone.ph-lightning:after { + content: "\e2df"; + margin-left: -1em; +} +.ph-duotone.ph-lightning-a:before { + content: "\ea84"; + opacity: 0.2; +} +.ph-duotone.ph-lightning-a:after { + content: "\ea85"; + margin-left: -1em; +} +.ph-duotone.ph-lightning-slash:before { + content: "\e2e0"; + opacity: 0.2; +} +.ph-duotone.ph-lightning-slash:after { + content: "\e2e1"; + margin-left: -1em; +} +.ph-duotone.ph-line-segment:before { + content: "\e6d2"; + opacity: 0.2; +} +.ph-duotone.ph-line-segment:after { + content: "\e6d3"; + margin-left: -1em; +} +.ph-duotone.ph-line-segments:before { + content: "\e6d4"; + opacity: 0.2; +} +.ph-duotone.ph-line-segments:after { + content: "\e6d5"; + margin-left: -1em; +} +.ph-duotone.ph-line-vertical:before { + content: "\ed70"; + opacity: 0.2; +} +.ph-duotone.ph-line-vertical:after { + content: "\ed71"; + margin-left: -1em; +} +.ph-duotone.ph-link:before { + content: "\e2e2"; + opacity: 0.2; +} +.ph-duotone.ph-link:after { + content: "\e2e3"; + margin-left: -1em; +} +.ph-duotone.ph-link-break:before { + content: "\e2e4"; + opacity: 0.2; +} +.ph-duotone.ph-link-break:after { + content: "\e2e5"; + margin-left: -1em; +} +.ph-duotone.ph-link-simple:before { + content: "\e2e6"; + opacity: 0.2; +} +.ph-duotone.ph-link-simple:after { + content: "\e2e7"; + margin-left: -1em; +} +.ph-duotone.ph-link-simple-break:before { + content: "\e2e8"; + opacity: 0.2; +} +.ph-duotone.ph-link-simple-break:after { + content: "\e2e9"; + margin-left: -1em; +} +.ph-duotone.ph-link-simple-horizontal:before { + content: "\e2ea"; + opacity: 0.2; +} +.ph-duotone.ph-link-simple-horizontal:after { + content: "\e2eb"; + margin-left: -1em; +} +.ph-duotone.ph-link-simple-horizontal-break:before { + content: "\e2ec"; + opacity: 0.2; +} +.ph-duotone.ph-link-simple-horizontal-break:after { + content: "\e2ed"; + margin-left: -1em; +} +.ph-duotone.ph-linkedin-logo:before { + content: "\e2ee"; + opacity: 0.2; +} +.ph-duotone.ph-linkedin-logo:after { + content: "\e2ef"; + margin-left: -1em; +} +.ph-duotone.ph-linktree-logo:before { + content: "\edee"; + opacity: 0.2; +} +.ph-duotone.ph-linktree-logo:after { + content: "\edef"; + margin-left: -1em; +} +.ph-duotone.ph-linux-logo:before { + content: "\eb02"; + opacity: 0.2; +} +.ph-duotone.ph-linux-logo:after { + content: "\eb03"; + margin-left: -1em; +} +.ph-duotone.ph-list:before { + content: "\e2f0"; + opacity: 0.2; +} +.ph-duotone.ph-list:after { + content: "\e2f1"; + margin-left: -1em; +} +.ph-duotone.ph-list-bullets:before { + content: "\e2f2"; + opacity: 0.2; +} +.ph-duotone.ph-list-bullets:after { + content: "\e2f3"; + margin-left: -1em; +} +.ph-duotone.ph-list-checks:before { + content: "\eadc"; + opacity: 0.2; +} +.ph-duotone.ph-list-checks:after { + content: "\eadd"; + margin-left: -1em; +} +.ph-duotone.ph-list-dashes:before { + content: "\e2f4"; + opacity: 0.2; +} +.ph-duotone.ph-list-dashes:after { + content: "\e2f5"; + margin-left: -1em; +} +.ph-duotone.ph-list-heart:before { + content: "\ebde"; + opacity: 0.2; +} +.ph-duotone.ph-list-heart:after { + content: "\ebdf"; + margin-left: -1em; +} +.ph-duotone.ph-list-magnifying-glass:before { + content: "\ebe0"; + opacity: 0.2; +} +.ph-duotone.ph-list-magnifying-glass:after { + content: "\ebe1"; + margin-left: -1em; +} +.ph-duotone.ph-list-numbers:before { + content: "\e2f6"; + opacity: 0.2; +} +.ph-duotone.ph-list-numbers:after { + content: "\e2f7"; + margin-left: -1em; +} +.ph-duotone.ph-list-plus:before { + content: "\e2f8"; + opacity: 0.2; +} +.ph-duotone.ph-list-plus:after { + content: "\e2f9"; + margin-left: -1em; +} +.ph-duotone.ph-list-star:before { + content: "\ebdc"; + opacity: 0.2; +} +.ph-duotone.ph-list-star:after { + content: "\ebdd"; + margin-left: -1em; +} +.ph-duotone.ph-lock:before { + content: "\e2fa"; + opacity: 0.2; +} +.ph-duotone.ph-lock:after { + content: "\e2fb"; + margin-left: -1em; +} +.ph-duotone.ph-lock-key:before { + content: "\e2fe"; + opacity: 0.2; +} +.ph-duotone.ph-lock-key:after { + content: "\e2ff"; + margin-left: -1em; +} +.ph-duotone.ph-lock-key-open:before { + content: "\e300"; + opacity: 0.2; +} +.ph-duotone.ph-lock-key-open:after { + content: "\e301"; + margin-left: -1em; +} +.ph-duotone.ph-lock-laminated:before { + content: "\e302"; + opacity: 0.2; +} +.ph-duotone.ph-lock-laminated:after { + content: "\e303"; + margin-left: -1em; +} +.ph-duotone.ph-lock-laminated-open:before { + content: "\e304"; + opacity: 0.2; +} +.ph-duotone.ph-lock-laminated-open:after { + content: "\e305"; + margin-left: -1em; +} +.ph-duotone.ph-lock-open:before { + content: "\e306"; + opacity: 0.2; +} +.ph-duotone.ph-lock-open:after { + content: "\e307"; + margin-left: -1em; +} +.ph-duotone.ph-lock-simple:before { + content: "\e308"; + opacity: 0.2; +} +.ph-duotone.ph-lock-simple:after { + content: "\e309"; + margin-left: -1em; +} +.ph-duotone.ph-lock-simple-open:before { + content: "\e30a"; + opacity: 0.2; +} +.ph-duotone.ph-lock-simple-open:after { + content: "\e30b"; + margin-left: -1em; +} +.ph-duotone.ph-lockers:before { + content: "\ecb8"; + opacity: 0.2; +} +.ph-duotone.ph-lockers:after { + content: "\ecb9"; + margin-left: -1em; +} +.ph-duotone.ph-log:before { + content: "\ed82"; + opacity: 0.2; +} +.ph-duotone.ph-log:after { + content: "\ed83"; + margin-left: -1em; +} +.ph-duotone.ph-magic-wand:before { + content: "\e6b6"; + opacity: 0.2; +} +.ph-duotone.ph-magic-wand:after { + content: "\e6b7"; + margin-left: -1em; +} +.ph-duotone.ph-magnet:before { + content: "\e680"; + opacity: 0.2; +} +.ph-duotone.ph-magnet:after { + content: "\e681"; + margin-left: -1em; +} +.ph-duotone.ph-magnet-straight:before { + content: "\e682"; + opacity: 0.2; +} +.ph-duotone.ph-magnet-straight:after { + content: "\e683"; + margin-left: -1em; +} +.ph-duotone.ph-magnifying-glass:before { + content: "\e30c"; + opacity: 0.2; +} +.ph-duotone.ph-magnifying-glass:after { + content: "\e30d"; + margin-left: -1em; +} +.ph-duotone.ph-magnifying-glass-minus:before { + content: "\e30e"; + opacity: 0.2; +} +.ph-duotone.ph-magnifying-glass-minus:after { + content: "\e30f"; + margin-left: -1em; +} +.ph-duotone.ph-magnifying-glass-plus:before { + content: "\e310"; + opacity: 0.2; +} +.ph-duotone.ph-magnifying-glass-plus:after { + content: "\e311"; + margin-left: -1em; +} +.ph-duotone.ph-mailbox:before { + content: "\ec1e"; + opacity: 0.2; +} +.ph-duotone.ph-mailbox:after { + content: "\ec1f"; + margin-left: -1em; +} +.ph-duotone.ph-map-pin:before { + content: "\e316"; + opacity: 0.2; +} +.ph-duotone.ph-map-pin:after { + content: "\e317"; + margin-left: -1em; +} +.ph-duotone.ph-map-pin-area:before { + content: "\ee3a"; + opacity: 0.2; +} +.ph-duotone.ph-map-pin-area:after { + content: "\ee3b"; + margin-left: -1em; +} +.ph-duotone.ph-map-pin-line:before { + content: "\e318"; + opacity: 0.2; +} +.ph-duotone.ph-map-pin-line:after { + content: "\e319"; + margin-left: -1em; +} +.ph-duotone.ph-map-pin-plus:before { + content: "\e314"; + opacity: 0.2; +} +.ph-duotone.ph-map-pin-plus:after { + content: "\e315"; + margin-left: -1em; +} +.ph-duotone.ph-map-pin-simple:before { + content: "\ee3e"; + opacity: 0.2; +} +.ph-duotone.ph-map-pin-simple:after { + content: "\ee3f"; + margin-left: -1em; +} +.ph-duotone.ph-map-pin-simple-area:before { + content: "\ee3c"; + opacity: 0.2; +} +.ph-duotone.ph-map-pin-simple-area:after { + content: "\ee3d"; + margin-left: -1em; +} +.ph-duotone.ph-map-pin-simple-line:before { + content: "\ee38"; + opacity: 0.2; +} +.ph-duotone.ph-map-pin-simple-line:after { + content: "\ee39"; + margin-left: -1em; +} +.ph-duotone.ph-map-trifold:before { + content: "\e31a"; + opacity: 0.2; +} +.ph-duotone.ph-map-trifold:after { + content: "\e31b"; + margin-left: -1em; +} +.ph-duotone.ph-markdown-logo:before { + content: "\e508"; + opacity: 0.2; +} +.ph-duotone.ph-markdown-logo:after { + content: "\e509"; + margin-left: -1em; +} +.ph-duotone.ph-marker-circle:before { + content: "\e640"; + opacity: 0.2; +} +.ph-duotone.ph-marker-circle:after { + content: "\e641"; + margin-left: -1em; +} +.ph-duotone.ph-martini:before { + content: "\e31c"; + opacity: 0.2; +} +.ph-duotone.ph-martini:after { + content: "\e31d"; + margin-left: -1em; +} +.ph-duotone.ph-mask-happy:before { + content: "\e9f4"; + opacity: 0.2; +} +.ph-duotone.ph-mask-happy:after { + content: "\e9f5"; + margin-left: -1em; +} +.ph-duotone.ph-mask-sad:before { + content: "\eb9e"; + opacity: 0.2; +} +.ph-duotone.ph-mask-sad:after { + content: "\eb9f"; + margin-left: -1em; +} +.ph-duotone.ph-mastodon-logo:before { + content: "\ed68"; + opacity: 0.2; +} +.ph-duotone.ph-mastodon-logo:after { + content: "\ed69"; + margin-left: -1em; +} +.ph-duotone.ph-math-operations:before { + content: "\e31e"; + opacity: 0.2; +} +.ph-duotone.ph-math-operations:after { + content: "\e31f"; + margin-left: -1em; +} +.ph-duotone.ph-matrix-logo:before { + content: "\ed64"; + opacity: 0.2; +} +.ph-duotone.ph-matrix-logo:after { + content: "\ed65"; + margin-left: -1em; +} +.ph-duotone.ph-medal:before { + content: "\e320"; + opacity: 0.2; +} +.ph-duotone.ph-medal:after { + content: "\e321"; + margin-left: -1em; +} +.ph-duotone.ph-medal-military:before { + content: "\ecfc"; + opacity: 0.2; +} +.ph-duotone.ph-medal-military:after { + content: "\ecfd"; + margin-left: -1em; +} +.ph-duotone.ph-medium-logo:before { + content: "\e322"; + opacity: 0.2; +} +.ph-duotone.ph-medium-logo:after { + content: "\e323"; + margin-left: -1em; +} +.ph-duotone.ph-megaphone:before { + content: "\e324"; + opacity: 0.2; +} +.ph-duotone.ph-megaphone:after { + content: "\e325"; + margin-left: -1em; +} +.ph-duotone.ph-megaphone-simple:before { + content: "\e642"; + opacity: 0.2; +} +.ph-duotone.ph-megaphone-simple:after { + content: "\e643"; + margin-left: -1em; +} +.ph-duotone.ph-member-of:before { + content: "\edc2"; + opacity: 0.2; +} +.ph-duotone.ph-member-of:after { + content: "\edc3"; + margin-left: -1em; +} +.ph-duotone.ph-memory:before { + content: "\e9c4"; + opacity: 0.2; +} +.ph-duotone.ph-memory:after { + content: "\e9c5"; + margin-left: -1em; +} +.ph-duotone.ph-messenger-logo:before { + content: "\e6d8"; + opacity: 0.2; +} +.ph-duotone.ph-messenger-logo:after { + content: "\e6d9"; + margin-left: -1em; +} +.ph-duotone.ph-meta-logo:before { + content: "\ed02"; + opacity: 0.2; +} +.ph-duotone.ph-meta-logo:after { + content: "\ed03"; + margin-left: -1em; +} +.ph-duotone.ph-meteor:before { + content: "\e9ba"; + opacity: 0.2; +} +.ph-duotone.ph-meteor:after { + content: "\e9bb"; + margin-left: -1em; +} +.ph-duotone.ph-metronome:before { + content: "\ec8e"; + opacity: 0.2; +} +.ph-duotone.ph-metronome:after { + content: "\ec8f"; + margin-left: -1em; +} +.ph-duotone.ph-microphone:before { + content: "\e326"; + opacity: 0.2; +} +.ph-duotone.ph-microphone:after { + content: "\e327"; + margin-left: -1em; +} +.ph-duotone.ph-microphone-slash:before { + content: "\e328"; + opacity: 0.2; +} +.ph-duotone.ph-microphone-slash:after { + content: "\e329"; + margin-left: -1em; +} +.ph-duotone.ph-microphone-stage:before { + content: "\e75c"; + opacity: 0.2; +} +.ph-duotone.ph-microphone-stage:after { + content: "\e75d"; + margin-left: -1em; +} +.ph-duotone.ph-microscope:before { + content: "\ec7a"; + opacity: 0.2; +} +.ph-duotone.ph-microscope:after { + content: "\ec7b"; + margin-left: -1em; +} +.ph-duotone.ph-microsoft-excel-logo:before { + content: "\eb6c"; + opacity: 0.2; +} +.ph-duotone.ph-microsoft-excel-logo:after { + content: "\eb6d"; + margin-left: -1em; +} +.ph-duotone.ph-microsoft-outlook-logo:before { + content: "\eb70"; + opacity: 0.2; +} +.ph-duotone.ph-microsoft-outlook-logo:after { + content: "\eb71"; + margin-left: -1em; +} +.ph-duotone.ph-microsoft-powerpoint-logo:before { + content: "\eace"; + opacity: 0.2; +} +.ph-duotone.ph-microsoft-powerpoint-logo:after { + content: "\eacf"; + margin-left: -1em; +} +.ph-duotone.ph-microsoft-teams-logo:before { + content: "\eb66"; + opacity: 0.2; +} +.ph-duotone.ph-microsoft-teams-logo:after { + content: "\eb67"; + margin-left: -1em; +} +.ph-duotone.ph-microsoft-word-logo:before { + content: "\eb6a"; + opacity: 0.2; +} +.ph-duotone.ph-microsoft-word-logo:after { + content: "\eb6b"; + margin-left: -1em; +} +.ph-duotone.ph-minus:before { + content: "\e32a"; + opacity: 0.2; +} +.ph-duotone.ph-minus:after { + content: "\e32b"; + margin-left: -1em; +} +.ph-duotone.ph-minus-circle:before { + content: "\e32c"; + opacity: 0.2; +} +.ph-duotone.ph-minus-circle:after { + content: "\e32d"; + margin-left: -1em; +} +.ph-duotone.ph-minus-square:before { + content: "\ed4c"; + opacity: 0.2; +} +.ph-duotone.ph-minus-square:after { + content: "\ed53"; + margin-left: -1em; +} +.ph-duotone.ph-money:before { + content: "\e588"; + opacity: 0.2; +} +.ph-duotone.ph-money:after { + content: "\e589"; + margin-left: -1em; +} +.ph-duotone.ph-money-wavy:before { + content: "\ee68"; + opacity: 0.2; +} +.ph-duotone.ph-money-wavy:after { + content: "\ee69"; + margin-left: -1em; +} +.ph-duotone.ph-monitor:before { + content: "\e32e"; + opacity: 0.2; +} +.ph-duotone.ph-monitor:after { + content: "\e32f"; + margin-left: -1em; +} +.ph-duotone.ph-monitor-arrow-up:before { + content: "\e58a"; + opacity: 0.2; +} +.ph-duotone.ph-monitor-arrow-up:after { + content: "\e58b"; + margin-left: -1em; +} +.ph-duotone.ph-monitor-play:before { + content: "\e58c"; + opacity: 0.2; +} +.ph-duotone.ph-monitor-play:after { + content: "\e58d"; + margin-left: -1em; +} +.ph-duotone.ph-moon:before { + content: "\e330"; + opacity: 0.2; +} +.ph-duotone.ph-moon:after { + content: "\e331"; + margin-left: -1em; +} +.ph-duotone.ph-moon-stars:before { + content: "\e58e"; + opacity: 0.2; +} +.ph-duotone.ph-moon-stars:after { + content: "\e58f"; + margin-left: -1em; +} +.ph-duotone.ph-moped:before { + content: "\e824"; + opacity: 0.2; +} +.ph-duotone.ph-moped:after { + content: "\e825"; + margin-left: -1em; +} +.ph-duotone.ph-moped-front:before { + content: "\e822"; + opacity: 0.2; +} +.ph-duotone.ph-moped-front:after { + content: "\e823"; + margin-left: -1em; +} +.ph-duotone.ph-mosque:before { + content: "\ecee"; + opacity: 0.2; +} +.ph-duotone.ph-mosque:after { + content: "\ecef"; + margin-left: -1em; +} +.ph-duotone.ph-motorcycle:before { + content: "\e80a"; + opacity: 0.2; +} +.ph-duotone.ph-motorcycle:after { + content: "\e80b"; + margin-left: -1em; +} +.ph-duotone.ph-mountains:before { + content: "\e7ae"; + opacity: 0.2; +} +.ph-duotone.ph-mountains:after { + content: "\e7af"; + margin-left: -1em; +} +.ph-duotone.ph-mouse:before { + content: "\e33a"; + opacity: 0.2; +} +.ph-duotone.ph-mouse:after { + content: "\e33b"; + margin-left: -1em; +} +.ph-duotone.ph-mouse-left-click:before { + content: "\e334"; + opacity: 0.2; +} +.ph-duotone.ph-mouse-left-click:after { + content: "\e335"; + margin-left: -1em; +} +.ph-duotone.ph-mouse-middle-click:before { + content: "\e338"; + opacity: 0.2; +} +.ph-duotone.ph-mouse-middle-click:after { + content: "\e339"; + margin-left: -1em; +} +.ph-duotone.ph-mouse-right-click:before { + content: "\e336"; + opacity: 0.2; +} +.ph-duotone.ph-mouse-right-click:after { + content: "\e337"; + margin-left: -1em; +} +.ph-duotone.ph-mouse-scroll:before { + content: "\e332"; + opacity: 0.2; +} +.ph-duotone.ph-mouse-scroll:after { + content: "\e333"; + margin-left: -1em; +} +.ph-duotone.ph-mouse-simple:before { + content: "\e644"; + opacity: 0.2; +} +.ph-duotone.ph-mouse-simple:after { + content: "\e645"; + margin-left: -1em; +} +.ph-duotone.ph-music-note:before { + content: "\e33c"; + opacity: 0.2; +} +.ph-duotone.ph-music-note:after { + content: "\e33d"; + margin-left: -1em; +} +.ph-duotone.ph-music-note-simple:before { + content: "\e33e"; + opacity: 0.2; +} +.ph-duotone.ph-music-note-simple:after { + content: "\e33f"; + margin-left: -1em; +} +.ph-duotone.ph-music-notes:before { + content: "\e340"; + opacity: 0.2; +} +.ph-duotone.ph-music-notes:after { + content: "\e341"; + margin-left: -1em; +} +.ph-duotone.ph-music-notes-minus:before { + content: "\ee0c"; + opacity: 0.2; +} +.ph-duotone.ph-music-notes-minus:after { + content: "\ee0d"; + margin-left: -1em; +} +.ph-duotone.ph-music-notes-plus:before { + content: "\eb7c"; + opacity: 0.2; +} +.ph-duotone.ph-music-notes-plus:after { + content: "\eb7d"; + margin-left: -1em; +} +.ph-duotone.ph-music-notes-simple:before { + content: "\e342"; + opacity: 0.2; +} +.ph-duotone.ph-music-notes-simple:after { + content: "\e343"; + margin-left: -1em; +} +.ph-duotone.ph-navigation-arrow:before { + content: "\eade"; + opacity: 0.2; +} +.ph-duotone.ph-navigation-arrow:after { + content: "\eadf"; + margin-left: -1em; +} +.ph-duotone.ph-needle:before { + content: "\e82e"; + opacity: 0.2; +} +.ph-duotone.ph-needle:after { + content: "\e82f"; + margin-left: -1em; +} +.ph-duotone.ph-network:before { + content: "\edde"; + opacity: 0.2; +} +.ph-duotone.ph-network:after { + content: "\eddf"; + margin-left: -1em; +} +.ph-duotone.ph-network-slash:before { + content: "\eddc"; + opacity: 0.2; +} +.ph-duotone.ph-network-slash:after { + content: "\eddd"; + margin-left: -1em; +} +.ph-duotone.ph-network-x:before { + content: "\edda"; + opacity: 0.2; +} +.ph-duotone.ph-network-x:after { + content: "\eddb"; + margin-left: -1em; +} +.ph-duotone.ph-newspaper:before { + content: "\e344"; + opacity: 0.2; +} +.ph-duotone.ph-newspaper:after { + content: "\e345"; + margin-left: -1em; +} +.ph-duotone.ph-newspaper-clipping:before { + content: "\e346"; + opacity: 0.2; +} +.ph-duotone.ph-newspaper-clipping:after { + content: "\e347"; + margin-left: -1em; +} +.ph-duotone.ph-not-equals:before { + content: "\eda6"; + opacity: 0.2; +} +.ph-duotone.ph-not-equals:after { + content: "\eda7"; + margin-left: -1em; +} +.ph-duotone.ph-not-member-of:before { + content: "\edae"; + opacity: 0.2; +} +.ph-duotone.ph-not-member-of:after { + content: "\edaf"; + margin-left: -1em; +} +.ph-duotone.ph-not-subset-of:before { + content: "\edb0"; + opacity: 0.2; +} +.ph-duotone.ph-not-subset-of:after { + content: "\edb1"; + margin-left: -1em; +} +.ph-duotone.ph-not-superset-of:before { + content: "\edb2"; + opacity: 0.2; +} +.ph-duotone.ph-not-superset-of:after { + content: "\edb3"; + margin-left: -1em; +} +.ph-duotone.ph-notches:before { + content: "\ed3a"; + opacity: 0.2; +} +.ph-duotone.ph-notches:after { + content: "\ed3b"; + margin-left: -1em; +} +.ph-duotone.ph-note:before { + content: "\e348"; + opacity: 0.2; +} +.ph-duotone.ph-note:after { + content: "\e349"; + margin-left: -1em; +} +.ph-duotone.ph-note-blank:before { + content: "\e34a"; + opacity: 0.2; +} +.ph-duotone.ph-note-blank:after { + content: "\e34b"; + margin-left: -1em; +} +.ph-duotone.ph-note-pencil:before { + content: "\e34c"; + opacity: 0.2; +} +.ph-duotone.ph-note-pencil:after { + content: "\e34d"; + margin-left: -1em; +} +.ph-duotone.ph-notebook:before { + content: "\e34e"; + opacity: 0.2; +} +.ph-duotone.ph-notebook:after { + content: "\e34f"; + margin-left: -1em; +} +.ph-duotone.ph-notepad:before { + content: "\e63e"; + opacity: 0.2; +} +.ph-duotone.ph-notepad:after { + content: "\e63f"; + margin-left: -1em; +} +.ph-duotone.ph-notification:before { + content: "\e6fa"; + opacity: 0.2; +} +.ph-duotone.ph-notification:after { + content: "\e6fb"; + margin-left: -1em; +} +.ph-duotone.ph-notion-logo:before { + content: "\e9a0"; + opacity: 0.2; +} +.ph-duotone.ph-notion-logo:after { + content: "\e9a1"; + margin-left: -1em; +} +.ph-duotone.ph-nuclear-plant:before { + content: "\ed7c"; + opacity: 0.2; +} +.ph-duotone.ph-nuclear-plant:after { + content: "\ed7d"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-eight:before { + content: "\e352"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-eight:after { + content: "\e353"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-five:before { + content: "\e358"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-five:after { + content: "\e359"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-four:before { + content: "\e35e"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-four:after { + content: "\e35f"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-nine:before { + content: "\e364"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-nine:after { + content: "\e365"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-one:before { + content: "\e36a"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-one:after { + content: "\e36b"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-seven:before { + content: "\e370"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-seven:after { + content: "\e371"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-six:before { + content: "\e376"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-six:after { + content: "\e377"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-three:before { + content: "\e37c"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-three:after { + content: "\e37d"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-two:before { + content: "\e382"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-two:after { + content: "\e383"; + margin-left: -1em; +} +.ph-duotone.ph-number-circle-zero:before { + content: "\e388"; + opacity: 0.2; +} +.ph-duotone.ph-number-circle-zero:after { + content: "\e389"; + margin-left: -1em; +} +.ph-duotone.ph-number-eight:before { + content: "\e350"; + opacity: 0.2; +} +.ph-duotone.ph-number-eight:after { + content: "\e351"; + margin-left: -1em; +} +.ph-duotone.ph-number-five:before { + content: "\e356"; + opacity: 0.2; +} +.ph-duotone.ph-number-five:after { + content: "\e357"; + margin-left: -1em; +} +.ph-duotone.ph-number-four:before { + content: "\e35c"; + opacity: 0.2; +} +.ph-duotone.ph-number-four:after { + content: "\e35d"; + margin-left: -1em; +} +.ph-duotone.ph-number-nine:before { + content: "\e362"; + opacity: 0.2; +} +.ph-duotone.ph-number-nine:after { + content: "\e363"; + margin-left: -1em; +} +.ph-duotone.ph-number-one:before { + content: "\e368"; + opacity: 0.2; +} +.ph-duotone.ph-number-one:after { + content: "\e369"; + margin-left: -1em; +} +.ph-duotone.ph-number-seven:before { + content: "\e36e"; + opacity: 0.2; +} +.ph-duotone.ph-number-seven:after { + content: "\e36f"; + margin-left: -1em; +} +.ph-duotone.ph-number-six:before { + content: "\e374"; + opacity: 0.2; +} +.ph-duotone.ph-number-six:after { + content: "\e375"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-eight:before { + content: "\e354"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-eight:after { + content: "\e355"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-five:before { + content: "\e35a"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-five:after { + content: "\e35b"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-four:before { + content: "\e360"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-four:after { + content: "\e361"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-nine:before { + content: "\e366"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-nine:after { + content: "\e367"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-one:before { + content: "\e36c"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-one:after { + content: "\e36d"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-seven:before { + content: "\e372"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-seven:after { + content: "\e373"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-six:before { + content: "\e378"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-six:after { + content: "\e379"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-three:before { + content: "\e37e"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-three:after { + content: "\e37f"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-two:before { + content: "\e384"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-two:after { + content: "\e385"; + margin-left: -1em; +} +.ph-duotone.ph-number-square-zero:before { + content: "\e38a"; + opacity: 0.2; +} +.ph-duotone.ph-number-square-zero:after { + content: "\e38b"; + margin-left: -1em; +} +.ph-duotone.ph-number-three:before { + content: "\e37a"; + opacity: 0.2; +} +.ph-duotone.ph-number-three:after { + content: "\e37b"; + margin-left: -1em; +} +.ph-duotone.ph-number-two:before { + content: "\e380"; + opacity: 0.2; +} +.ph-duotone.ph-number-two:after { + content: "\e381"; + margin-left: -1em; +} +.ph-duotone.ph-number-zero:before { + content: "\e386"; + opacity: 0.2; +} +.ph-duotone.ph-number-zero:after { + content: "\e387"; + margin-left: -1em; +} +.ph-duotone.ph-numpad:before { + content: "\e3c8"; + opacity: 0.2; +} +.ph-duotone.ph-numpad:after { + content: "\e3c9"; + margin-left: -1em; +} +.ph-duotone.ph-nut:before { + content: "\e38c"; + opacity: 0.2; +} +.ph-duotone.ph-nut:after { + content: "\e38d"; + margin-left: -1em; +} +.ph-duotone.ph-ny-times-logo:before { + content: "\e646"; + opacity: 0.2; +} +.ph-duotone.ph-ny-times-logo:after { + content: "\e647"; + margin-left: -1em; +} +.ph-duotone.ph-octagon:before { + content: "\e38e"; + opacity: 0.2; +} +.ph-duotone.ph-octagon:after { + content: "\e38f"; + margin-left: -1em; +} +.ph-duotone.ph-office-chair:before { + content: "\ea46"; + opacity: 0.2; +} +.ph-duotone.ph-office-chair:after { + content: "\ea47"; + margin-left: -1em; +} +.ph-duotone.ph-onigiri:before { + content: "\ee2c"; + opacity: 0.2; +} +.ph-duotone.ph-onigiri:after { + content: "\ee2d"; + margin-left: -1em; +} +.ph-duotone.ph-open-ai-logo:before { + content: "\e7d2"; + opacity: 0.2; +} +.ph-duotone.ph-open-ai-logo:after { + content: "\e7d3"; + margin-left: -1em; +} +.ph-duotone.ph-option:before { + content: "\e8a8"; + opacity: 0.2; +} +.ph-duotone.ph-option:after { + content: "\e8a9"; + margin-left: -1em; +} +.ph-duotone.ph-orange:before { + content: "\ee40"; + opacity: 0.2; +} +.ph-duotone.ph-orange:after { + content: "\ee41"; + margin-left: -1em; +} +.ph-duotone.ph-orange-slice:before { + content: "\ed36"; + opacity: 0.2; +} +.ph-duotone.ph-orange-slice:after { + content: "\ed37"; + margin-left: -1em; +} +.ph-duotone.ph-oven:before { + content: "\ed8c"; + opacity: 0.2; +} +.ph-duotone.ph-oven:after { + content: "\ed8d"; + margin-left: -1em; +} +.ph-duotone.ph-package:before { + content: "\e390"; + opacity: 0.2; +} +.ph-duotone.ph-package:after { + content: "\e391"; + margin-left: -1em; +} +.ph-duotone.ph-paint-brush:before { + content: "\e6f0"; + opacity: 0.2; +} +.ph-duotone.ph-paint-brush:after { + content: "\e6f1"; + margin-left: -1em; +} +.ph-duotone.ph-paint-brush-broad:before { + content: "\e590"; + opacity: 0.2; +} +.ph-duotone.ph-paint-brush-broad:after { + content: "\e591"; + margin-left: -1em; +} +.ph-duotone.ph-paint-brush-household:before { + content: "\e6f2"; + opacity: 0.2; +} +.ph-duotone.ph-paint-brush-household:after { + content: "\e6f3"; + margin-left: -1em; +} +.ph-duotone.ph-paint-bucket:before { + content: "\e392"; + opacity: 0.2; +} +.ph-duotone.ph-paint-bucket:after { + content: "\e393"; + margin-left: -1em; +} +.ph-duotone.ph-paint-roller:before { + content: "\e6f4"; + opacity: 0.2; +} +.ph-duotone.ph-paint-roller:after { + content: "\e6f5"; + margin-left: -1em; +} +.ph-duotone.ph-palette:before { + content: "\e6c8"; + opacity: 0.2; +} +.ph-duotone.ph-palette:after { + content: "\e6c9"; + margin-left: -1em; +} +.ph-duotone.ph-panorama:before { + content: "\eaa2"; + opacity: 0.2; +} +.ph-duotone.ph-panorama:after { + content: "\eaa3"; + margin-left: -1em; +} +.ph-duotone.ph-pants:before { + content: "\ec88"; + opacity: 0.2; +} +.ph-duotone.ph-pants:after { + content: "\ec89"; + margin-left: -1em; +} +.ph-duotone.ph-paper-plane:before { + content: "\e394"; + opacity: 0.2; +} +.ph-duotone.ph-paper-plane:after { + content: "\e395"; + margin-left: -1em; +} +.ph-duotone.ph-paper-plane-right:before { + content: "\e396"; + opacity: 0.2; +} +.ph-duotone.ph-paper-plane-right:after { + content: "\e397"; + margin-left: -1em; +} +.ph-duotone.ph-paper-plane-tilt:before { + content: "\e398"; + opacity: 0.2; +} +.ph-duotone.ph-paper-plane-tilt:after { + content: "\e399"; + margin-left: -1em; +} +.ph-duotone.ph-paperclip:before { + content: "\e39a"; + opacity: 0.2; +} +.ph-duotone.ph-paperclip:after { + content: "\e39b"; + margin-left: -1em; +} +.ph-duotone.ph-paperclip-horizontal:before { + content: "\e592"; + opacity: 0.2; +} +.ph-duotone.ph-paperclip-horizontal:after { + content: "\e593"; + margin-left: -1em; +} +.ph-duotone.ph-parachute:before { + content: "\ea7c"; + opacity: 0.2; +} +.ph-duotone.ph-parachute:after { + content: "\ea7d"; + margin-left: -1em; +} +.ph-duotone.ph-paragraph:before { + content: "\e960"; + opacity: 0.2; +} +.ph-duotone.ph-paragraph:after { + content: "\e961"; + margin-left: -1em; +} +.ph-duotone.ph-parallelogram:before { + content: "\ecc6"; + opacity: 0.2; +} +.ph-duotone.ph-parallelogram:after { + content: "\ecc7"; + margin-left: -1em; +} +.ph-duotone.ph-park:before { + content: "\ecb2"; + opacity: 0.2; +} +.ph-duotone.ph-park:after { + content: "\ecb3"; + margin-left: -1em; +} +.ph-duotone.ph-password:before { + content: "\e752"; + opacity: 0.2; +} +.ph-duotone.ph-password:after { + content: "\e753"; + margin-left: -1em; +} +.ph-duotone.ph-path:before { + content: "\e39c"; + opacity: 0.2; +} +.ph-duotone.ph-path:after { + content: "\e39d"; + margin-left: -1em; +} +.ph-duotone.ph-patreon-logo:before { + content: "\e98a"; + opacity: 0.2; +} +.ph-duotone.ph-patreon-logo:after { + content: "\e98b"; + margin-left: -1em; +} +.ph-duotone.ph-pause:before { + content: "\e39e"; + opacity: 0.2; +} +.ph-duotone.ph-pause:after { + content: "\e39f"; + margin-left: -1em; +} +.ph-duotone.ph-pause-circle:before { + content: "\e3a0"; + opacity: 0.2; +} +.ph-duotone.ph-pause-circle:after { + content: "\e3a1"; + margin-left: -1em; +} +.ph-duotone.ph-paw-print:before { + content: "\e648"; + opacity: 0.2; +} +.ph-duotone.ph-paw-print:after { + content: "\e649"; + margin-left: -1em; +} +.ph-duotone.ph-paypal-logo:before { + content: "\e98c"; + opacity: 0.2; +} +.ph-duotone.ph-paypal-logo:after { + content: "\e98d"; + margin-left: -1em; +} +.ph-duotone.ph-peace:before { + content: "\e3a2"; + opacity: 0.2; +} +.ph-duotone.ph-peace:after { + content: "\e3a3"; + margin-left: -1em; +} +.ph-duotone.ph-pen:before { + content: "\e3aa"; + opacity: 0.2; +} +.ph-duotone.ph-pen:after { + content: "\e3ab"; + margin-left: -1em; +} +.ph-duotone.ph-pen-nib:before { + content: "\e3ac"; + opacity: 0.2; +} +.ph-duotone.ph-pen-nib:after { + content: "\e3ad"; + margin-left: -1em; +} +.ph-duotone.ph-pen-nib-straight:before { + content: "\e64a"; + opacity: 0.2; +} +.ph-duotone.ph-pen-nib-straight:after { + content: "\e64b"; + margin-left: -1em; +} +.ph-duotone.ph-pencil:before { + content: "\e3ae"; + opacity: 0.2; +} +.ph-duotone.ph-pencil:after { + content: "\e3af"; + margin-left: -1em; +} +.ph-duotone.ph-pencil-circle:before { + content: "\e3b0"; + opacity: 0.2; +} +.ph-duotone.ph-pencil-circle:after { + content: "\e3b1"; + margin-left: -1em; +} +.ph-duotone.ph-pencil-line:before { + content: "\e3b2"; + opacity: 0.2; +} +.ph-duotone.ph-pencil-line:after { + content: "\e3b3"; + margin-left: -1em; +} +.ph-duotone.ph-pencil-ruler:before { + content: "\e906"; + opacity: 0.2; +} +.ph-duotone.ph-pencil-ruler:after { + content: "\e907"; + margin-left: -1em; +} +.ph-duotone.ph-pencil-simple:before { + content: "\e3b4"; + opacity: 0.2; +} +.ph-duotone.ph-pencil-simple:after { + content: "\e3b5"; + margin-left: -1em; +} +.ph-duotone.ph-pencil-simple-line:before { + content: "\ebc6"; + opacity: 0.2; +} +.ph-duotone.ph-pencil-simple-line:after { + content: "\ebc7"; + margin-left: -1em; +} +.ph-duotone.ph-pencil-simple-slash:before { + content: "\ecf6"; + opacity: 0.2; +} +.ph-duotone.ph-pencil-simple-slash:after { + content: "\ecf7"; + margin-left: -1em; +} +.ph-duotone.ph-pencil-slash:before { + content: "\ecf8"; + opacity: 0.2; +} +.ph-duotone.ph-pencil-slash:after { + content: "\ecf9"; + margin-left: -1em; +} +.ph-duotone.ph-pentagon:before { + content: "\ec7e"; + opacity: 0.2; +} +.ph-duotone.ph-pentagon:after { + content: "\ec7f"; + margin-left: -1em; +} +.ph-duotone.ph-pentagram:before { + content: "\ec5c"; + opacity: 0.2; +} +.ph-duotone.ph-pentagram:after { + content: "\ec5d"; + margin-left: -1em; +} +.ph-duotone.ph-pepper:before { + content: "\e94a"; + opacity: 0.2; +} +.ph-duotone.ph-pepper:after { + content: "\e94b"; + margin-left: -1em; +} +.ph-duotone.ph-percent:before { + content: "\e3b6"; + opacity: 0.2; +} +.ph-duotone.ph-percent:after { + content: "\e3b7"; + margin-left: -1em; +} +.ph-duotone.ph-person:before { + content: "\e3a8"; + opacity: 0.2; +} +.ph-duotone.ph-person:after { + content: "\e3a9"; + margin-left: -1em; +} +.ph-duotone.ph-person-arms-spread:before { + content: "\ecfe"; + opacity: 0.2; +} +.ph-duotone.ph-person-arms-spread:after { + content: "\ecff"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple:before { + content: "\e72e"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple:after { + content: "\e72f"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-bike:before { + content: "\e734"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-bike:after { + content: "\e735"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-circle:before { + content: "\ee58"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-circle:after { + content: "\ee59"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-hike:before { + content: "\ed54"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-hike:after { + content: "\ed55"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-run:before { + content: "\e730"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-run:after { + content: "\e731"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-ski:before { + content: "\e71c"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-ski:after { + content: "\e71d"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-snowboard:before { + content: "\e71e"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-snowboard:after { + content: "\e71f"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-swim:before { + content: "\e736"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-swim:after { + content: "\e737"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-tai-chi:before { + content: "\ed5c"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-tai-chi:after { + content: "\ed5d"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-throw:before { + content: "\e732"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-throw:after { + content: "\e733"; + margin-left: -1em; +} +.ph-duotone.ph-person-simple-walk:before { + content: "\e73a"; + opacity: 0.2; +} +.ph-duotone.ph-person-simple-walk:after { + content: "\e73b"; + margin-left: -1em; +} +.ph-duotone.ph-perspective:before { + content: "\ebe6"; + opacity: 0.2; +} +.ph-duotone.ph-perspective:after { + content: "\ebe7"; + margin-left: -1em; +} +.ph-duotone.ph-phone:before { + content: "\e3b8"; + opacity: 0.2; +} +.ph-duotone.ph-phone:after { + content: "\e3b9"; + margin-left: -1em; +} +.ph-duotone.ph-phone-call:before { + content: "\e3ba"; + opacity: 0.2; +} +.ph-duotone.ph-phone-call:after { + content: "\e3bb"; + margin-left: -1em; +} +.ph-duotone.ph-phone-disconnect:before { + content: "\e3bc"; + opacity: 0.2; +} +.ph-duotone.ph-phone-disconnect:after { + content: "\e3bd"; + margin-left: -1em; +} +.ph-duotone.ph-phone-incoming:before { + content: "\e3be"; + opacity: 0.2; +} +.ph-duotone.ph-phone-incoming:after { + content: "\e3bf"; + margin-left: -1em; +} +.ph-duotone.ph-phone-list:before { + content: "\e3cc"; + opacity: 0.2; +} +.ph-duotone.ph-phone-list:after { + content: "\e3cd"; + margin-left: -1em; +} +.ph-duotone.ph-phone-outgoing:before { + content: "\e3c0"; + opacity: 0.2; +} +.ph-duotone.ph-phone-outgoing:after { + content: "\e3c1"; + margin-left: -1em; +} +.ph-duotone.ph-phone-pause:before { + content: "\e3ca"; + opacity: 0.2; +} +.ph-duotone.ph-phone-pause:after { + content: "\e3cb"; + margin-left: -1em; +} +.ph-duotone.ph-phone-plus:before { + content: "\ec56"; + opacity: 0.2; +} +.ph-duotone.ph-phone-plus:after { + content: "\ec57"; + margin-left: -1em; +} +.ph-duotone.ph-phone-slash:before { + content: "\e3c2"; + opacity: 0.2; +} +.ph-duotone.ph-phone-slash:after { + content: "\e3c3"; + margin-left: -1em; +} +.ph-duotone.ph-phone-transfer:before { + content: "\e3c6"; + opacity: 0.2; +} +.ph-duotone.ph-phone-transfer:after { + content: "\e3c7"; + margin-left: -1em; +} +.ph-duotone.ph-phone-x:before { + content: "\e3c4"; + opacity: 0.2; +} +.ph-duotone.ph-phone-x:after { + content: "\e3c5"; + margin-left: -1em; +} +.ph-duotone.ph-phosphor-logo:before { + content: "\e3ce"; + opacity: 0.2; +} +.ph-duotone.ph-phosphor-logo:after { + content: "\e3cf"; + margin-left: -1em; +} +.ph-duotone.ph-pi:before { + content: "\ec80"; + opacity: 0.2; +} +.ph-duotone.ph-pi:after { + content: "\ec81"; + margin-left: -1em; +} +.ph-duotone.ph-piano-keys:before { + content: "\e9c8"; + opacity: 0.2; +} +.ph-duotone.ph-piano-keys:after { + content: "\e9c9"; + margin-left: -1em; +} +.ph-duotone.ph-picnic-table:before { + content: "\ee26"; + opacity: 0.2; +} +.ph-duotone.ph-picnic-table:after { + content: "\ee27"; + margin-left: -1em; +} +.ph-duotone.ph-picture-in-picture:before { + content: "\e64c"; + opacity: 0.2; +} +.ph-duotone.ph-picture-in-picture:after { + content: "\e64d"; + margin-left: -1em; +} +.ph-duotone.ph-piggy-bank:before { + content: "\ea04"; + opacity: 0.2; +} +.ph-duotone.ph-piggy-bank:after { + content: "\ea05"; + margin-left: -1em; +} +.ph-duotone.ph-pill:before { + content: "\e700"; + opacity: 0.2; +} +.ph-duotone.ph-pill:after { + content: "\e701"; + margin-left: -1em; +} +.ph-duotone.ph-ping-pong:before { + content: "\ea42"; + opacity: 0.2; +} +.ph-duotone.ph-ping-pong:after { + content: "\ea43"; + margin-left: -1em; +} +.ph-duotone.ph-pint-glass:before { + content: "\edd0"; + opacity: 0.2; +} +.ph-duotone.ph-pint-glass:after { + content: "\edd1"; + margin-left: -1em; +} +.ph-duotone.ph-pinterest-logo:before { + content: "\e64e"; + opacity: 0.2; +} +.ph-duotone.ph-pinterest-logo:after { + content: "\e64f"; + margin-left: -1em; +} +.ph-duotone.ph-pinwheel:before { + content: "\eb9c"; + opacity: 0.2; +} +.ph-duotone.ph-pinwheel:after { + content: "\eb9d"; + margin-left: -1em; +} +.ph-duotone.ph-pipe:before { + content: "\ed86"; + opacity: 0.2; +} +.ph-duotone.ph-pipe:after { + content: "\ed87"; + margin-left: -1em; +} +.ph-duotone.ph-pipe-wrench:before { + content: "\ed88"; + opacity: 0.2; +} +.ph-duotone.ph-pipe-wrench:after { + content: "\ed89"; + margin-left: -1em; +} +.ph-duotone.ph-pix-logo:before { + content: "\ecc2"; + opacity: 0.2; +} +.ph-duotone.ph-pix-logo:after { + content: "\ecc3"; + margin-left: -1em; +} +.ph-duotone.ph-pizza:before { + content: "\e796"; + opacity: 0.2; +} +.ph-duotone.ph-pizza:after { + content: "\e797"; + margin-left: -1em; +} +.ph-duotone.ph-placeholder:before { + content: "\e650"; + opacity: 0.2; +} +.ph-duotone.ph-placeholder:after { + content: "\e651"; + margin-left: -1em; +} +.ph-duotone.ph-planet:before { + content: "\e652"; + opacity: 0.2; +} +.ph-duotone.ph-planet:after { + content: "\e653"; + margin-left: -1em; +} +.ph-duotone.ph-plant:before { + content: "\ebae"; + opacity: 0.2; +} +.ph-duotone.ph-plant:after { + content: "\ebaf"; + margin-left: -1em; +} +.ph-duotone.ph-play:before { + content: "\e3d0"; + opacity: 0.2; +} +.ph-duotone.ph-play:after { + content: "\e3d1"; + margin-left: -1em; +} +.ph-duotone.ph-play-circle:before { + content: "\e3d2"; + opacity: 0.2; +} +.ph-duotone.ph-play-circle:after { + content: "\e3d3"; + margin-left: -1em; +} +.ph-duotone.ph-play-pause:before { + content: "\e8be"; + opacity: 0.2; +} +.ph-duotone.ph-play-pause:after { + content: "\e8bf"; + margin-left: -1em; +} +.ph-duotone.ph-playlist:before { + content: "\e6aa"; + opacity: 0.2; +} +.ph-duotone.ph-playlist:after { + content: "\e6ab"; + margin-left: -1em; +} +.ph-duotone.ph-plug:before { + content: "\e946"; + opacity: 0.2; +} +.ph-duotone.ph-plug:after { + content: "\e947"; + margin-left: -1em; +} +.ph-duotone.ph-plug-charging:before { + content: "\eb5c"; + opacity: 0.2; +} +.ph-duotone.ph-plug-charging:after { + content: "\eb5d"; + margin-left: -1em; +} +.ph-duotone.ph-plugs:before { + content: "\eb56"; + opacity: 0.2; +} +.ph-duotone.ph-plugs:after { + content: "\eb57"; + margin-left: -1em; +} +.ph-duotone.ph-plugs-connected:before { + content: "\eb5a"; + opacity: 0.2; +} +.ph-duotone.ph-plugs-connected:after { + content: "\eb5b"; + margin-left: -1em; +} +.ph-duotone.ph-plus:before { + content: "\e3d4"; + opacity: 0.2; +} +.ph-duotone.ph-plus:after { + content: "\e3d5"; + margin-left: -1em; +} +.ph-duotone.ph-plus-circle:before { + content: "\e3d6"; + opacity: 0.2; +} +.ph-duotone.ph-plus-circle:after { + content: "\e3d7"; + margin-left: -1em; +} +.ph-duotone.ph-plus-minus:before { + content: "\e3d8"; + opacity: 0.2; +} +.ph-duotone.ph-plus-minus:after { + content: "\e3d9"; + margin-left: -1em; +} +.ph-duotone.ph-plus-square:before { + content: "\ed4a"; + opacity: 0.2; +} +.ph-duotone.ph-plus-square:after { + content: "\ed56"; + margin-left: -1em; +} +.ph-duotone.ph-poker-chip:before { + content: "\e594"; + opacity: 0.2; +} +.ph-duotone.ph-poker-chip:after { + content: "\e595"; + margin-left: -1em; +} +.ph-duotone.ph-police-car:before { + content: "\ec4a"; + opacity: 0.2; +} +.ph-duotone.ph-police-car:after { + content: "\ec4b"; + margin-left: -1em; +} +.ph-duotone.ph-polygon:before { + content: "\e6d0"; + opacity: 0.2; +} +.ph-duotone.ph-polygon:after { + content: "\e6d1"; + margin-left: -1em; +} +.ph-duotone.ph-popcorn:before { + content: "\eb4e"; + opacity: 0.2; +} +.ph-duotone.ph-popcorn:after { + content: "\eb4f"; + margin-left: -1em; +} +.ph-duotone.ph-popsicle:before { + content: "\ebbe"; + opacity: 0.2; +} +.ph-duotone.ph-popsicle:after { + content: "\ebbf"; + margin-left: -1em; +} +.ph-duotone.ph-potted-plant:before { + content: "\ec22"; + opacity: 0.2; +} +.ph-duotone.ph-potted-plant:after { + content: "\ec23"; + margin-left: -1em; +} +.ph-duotone.ph-power:before { + content: "\e3da"; + opacity: 0.2; +} +.ph-duotone.ph-power:after { + content: "\e3db"; + margin-left: -1em; +} +.ph-duotone.ph-prescription:before { + content: "\e7a2"; + opacity: 0.2; +} +.ph-duotone.ph-prescription:after { + content: "\e7a3"; + margin-left: -1em; +} +.ph-duotone.ph-presentation:before { + content: "\e654"; + opacity: 0.2; +} +.ph-duotone.ph-presentation:after { + content: "\e655"; + margin-left: -1em; +} +.ph-duotone.ph-presentation-chart:before { + content: "\e656"; + opacity: 0.2; +} +.ph-duotone.ph-presentation-chart:after { + content: "\e657"; + margin-left: -1em; +} +.ph-duotone.ph-printer:before { + content: "\e3dc"; + opacity: 0.2; +} +.ph-duotone.ph-printer:after { + content: "\e3dd"; + margin-left: -1em; +} +.ph-duotone.ph-prohibit:before { + content: "\e3de"; + opacity: 0.2; +} +.ph-duotone.ph-prohibit:after { + content: "\e3df"; + margin-left: -1em; +} +.ph-duotone.ph-prohibit-inset:before { + content: "\e3e0"; + opacity: 0.2; +} +.ph-duotone.ph-prohibit-inset:after { + content: "\e3e1"; + margin-left: -1em; +} +.ph-duotone.ph-projector-screen:before { + content: "\e658"; + opacity: 0.2; +} +.ph-duotone.ph-projector-screen:after { + content: "\e659"; + margin-left: -1em; +} +.ph-duotone.ph-projector-screen-chart:before { + content: "\e65a"; + opacity: 0.2; +} +.ph-duotone.ph-projector-screen-chart:after { + content: "\e65b"; + margin-left: -1em; +} +.ph-duotone.ph-pulse:before { + content: "\e000"; + opacity: 0.2; +} +.ph-duotone.ph-pulse:after { + content: "\e001"; + margin-left: -1em; +} +.ph-duotone.ph-push-pin:before { + content: "\e3e2"; + opacity: 0.2; +} +.ph-duotone.ph-push-pin:after { + content: "\e3e3"; + margin-left: -1em; +} +.ph-duotone.ph-push-pin-simple:before { + content: "\e65c"; + opacity: 0.2; +} +.ph-duotone.ph-push-pin-simple:after { + content: "\e65d"; + margin-left: -1em; +} +.ph-duotone.ph-push-pin-simple-slash:before { + content: "\e65e"; + opacity: 0.2; +} +.ph-duotone.ph-push-pin-simple-slash:after { + content: "\e65f"; + margin-left: -1em; +} +.ph-duotone.ph-push-pin-slash:before { + content: "\e3e4"; + opacity: 0.2; +} +.ph-duotone.ph-push-pin-slash:after { + content: "\e3e5"; + margin-left: -1em; +} +.ph-duotone.ph-puzzle-piece:before { + content: "\e596"; + opacity: 0.2; +} +.ph-duotone.ph-puzzle-piece:after { + content: "\e597"; + margin-left: -1em; +} +.ph-duotone.ph-qr-code:before { + content: "\e3e6"; + opacity: 0.2; +} +.ph-duotone.ph-qr-code:after { + content: "\e3e7"; + margin-left: -1em; +} +.ph-duotone.ph-question:before { + content: "\e3e8"; + opacity: 0.2; +} +.ph-duotone.ph-question:after { + content: "\e3eb"; + margin-left: -1em; +} +.ph-duotone.ph-question-mark:before { + content: "\e3e9"; + opacity: 0.2; +} +.ph-duotone.ph-question-mark:after { + content: "\e3ed"; + margin-left: -1em; +} +.ph-duotone.ph-queue:before { + content: "\e6ac"; + opacity: 0.2; +} +.ph-duotone.ph-queue:after { + content: "\e6ad"; + margin-left: -1em; +} +.ph-duotone.ph-quotes:before { + content: "\e660"; + opacity: 0.2; +} +.ph-duotone.ph-quotes:after { + content: "\e661"; + margin-left: -1em; +} +.ph-duotone.ph-rabbit:before { + content: "\eac2"; + opacity: 0.2; +} +.ph-duotone.ph-rabbit:after { + content: "\eac3"; + margin-left: -1em; +} +.ph-duotone.ph-racquet:before { + content: "\ee02"; + opacity: 0.2; +} +.ph-duotone.ph-racquet:after { + content: "\ee03"; + margin-left: -1em; +} +.ph-duotone.ph-radical:before { + content: "\e3ea"; + opacity: 0.2; +} +.ph-duotone.ph-radical:after { + content: "\e3ef"; + margin-left: -1em; +} +.ph-duotone.ph-radio:before { + content: "\e77e"; + opacity: 0.2; +} +.ph-duotone.ph-radio:after { + content: "\e77f"; + margin-left: -1em; +} +.ph-duotone.ph-radio-button:before { + content: "\eb08"; + opacity: 0.2; +} +.ph-duotone.ph-radio-button:after { + content: "\eb09"; + margin-left: -1em; +} +.ph-duotone.ph-radioactive:before { + content: "\e9dc"; + opacity: 0.2; +} +.ph-duotone.ph-radioactive:after { + content: "\e9dd"; + margin-left: -1em; +} +.ph-duotone.ph-rainbow:before { + content: "\e598"; + opacity: 0.2; +} +.ph-duotone.ph-rainbow:after { + content: "\e599"; + margin-left: -1em; +} +.ph-duotone.ph-rainbow-cloud:before { + content: "\e59a"; + opacity: 0.2; +} +.ph-duotone.ph-rainbow-cloud:after { + content: "\e59b"; + margin-left: -1em; +} +.ph-duotone.ph-ranking:before { + content: "\ed62"; + opacity: 0.2; +} +.ph-duotone.ph-ranking:after { + content: "\ed63"; + margin-left: -1em; +} +.ph-duotone.ph-read-cv-logo:before { + content: "\ed0c"; + opacity: 0.2; +} +.ph-duotone.ph-read-cv-logo:after { + content: "\ed0d"; + margin-left: -1em; +} +.ph-duotone.ph-receipt:before { + content: "\e3ec"; + opacity: 0.2; +} +.ph-duotone.ph-receipt:after { + content: "\e3f1"; + margin-left: -1em; +} +.ph-duotone.ph-receipt-x:before { + content: "\ed40"; + opacity: 0.2; +} +.ph-duotone.ph-receipt-x:after { + content: "\ed41"; + margin-left: -1em; +} +.ph-duotone.ph-record:before { + content: "\e3ee"; + opacity: 0.2; +} +.ph-duotone.ph-record:after { + content: "\e3f3"; + margin-left: -1em; +} +.ph-duotone.ph-rectangle:before { + content: "\e3f0"; + opacity: 0.2; +} +.ph-duotone.ph-rectangle:after { + content: "\e3f5"; + margin-left: -1em; +} +.ph-duotone.ph-rectangle-dashed:before { + content: "\e3f2"; + opacity: 0.2; +} +.ph-duotone.ph-rectangle-dashed:after { + content: "\e3f7"; + margin-left: -1em; +} +.ph-duotone.ph-recycle:before { + content: "\e75a"; + opacity: 0.2; +} +.ph-duotone.ph-recycle:after { + content: "\e75b"; + margin-left: -1em; +} +.ph-duotone.ph-reddit-logo:before { + content: "\e59c"; + opacity: 0.2; +} +.ph-duotone.ph-reddit-logo:after { + content: "\e59d"; + margin-left: -1em; +} +.ph-duotone.ph-repeat:before { + content: "\e3f6"; + opacity: 0.2; +} +.ph-duotone.ph-repeat:after { + content: "\e3f9"; + margin-left: -1em; +} +.ph-duotone.ph-repeat-once:before { + content: "\e3f8"; + opacity: 0.2; +} +.ph-duotone.ph-repeat-once:after { + content: "\e3fb"; + margin-left: -1em; +} +.ph-duotone.ph-replit-logo:before { + content: "\eb8a"; + opacity: 0.2; +} +.ph-duotone.ph-replit-logo:after { + content: "\eb8b"; + margin-left: -1em; +} +.ph-duotone.ph-resize:before { + content: "\ed6e"; + opacity: 0.2; +} +.ph-duotone.ph-resize:after { + content: "\ed6f"; + margin-left: -1em; +} +.ph-duotone.ph-rewind:before { + content: "\e6a8"; + opacity: 0.2; +} +.ph-duotone.ph-rewind:after { + content: "\e6a9"; + margin-left: -1em; +} +.ph-duotone.ph-rewind-circle:before { + content: "\e3fa"; + opacity: 0.2; +} +.ph-duotone.ph-rewind-circle:after { + content: "\e3fd"; + margin-left: -1em; +} +.ph-duotone.ph-road-horizon:before { + content: "\e838"; + opacity: 0.2; +} +.ph-duotone.ph-road-horizon:after { + content: "\e839"; + margin-left: -1em; +} +.ph-duotone.ph-robot:before { + content: "\e762"; + opacity: 0.2; +} +.ph-duotone.ph-robot:after { + content: "\e763"; + margin-left: -1em; +} +.ph-duotone.ph-rocket:before { + content: "\e3fc"; + opacity: 0.2; +} +.ph-duotone.ph-rocket:after { + content: "\e3ff"; + margin-left: -1em; +} +.ph-duotone.ph-rocket-launch:before { + content: "\e3fe"; + opacity: 0.2; +} +.ph-duotone.ph-rocket-launch:after { + content: "\e401"; + margin-left: -1em; +} +.ph-duotone.ph-rows:before { + content: "\e5a2"; + opacity: 0.2; +} +.ph-duotone.ph-rows:after { + content: "\e5a3"; + margin-left: -1em; +} +.ph-duotone.ph-rows-plus-bottom:before { + content: "\e59e"; + opacity: 0.2; +} +.ph-duotone.ph-rows-plus-bottom:after { + content: "\e59f"; + margin-left: -1em; +} +.ph-duotone.ph-rows-plus-top:before { + content: "\e5a0"; + opacity: 0.2; +} +.ph-duotone.ph-rows-plus-top:after { + content: "\e5a1"; + margin-left: -1em; +} +.ph-duotone.ph-rss:before { + content: "\e400"; + opacity: 0.2; +} +.ph-duotone.ph-rss:after { + content: "\e403"; + margin-left: -1em; +} +.ph-duotone.ph-rss-simple:before { + content: "\e402"; + opacity: 0.2; +} +.ph-duotone.ph-rss-simple:after { + content: "\e405"; + margin-left: -1em; +} +.ph-duotone.ph-rug:before { + content: "\ea1a"; + opacity: 0.2; +} +.ph-duotone.ph-rug:after { + content: "\ea1b"; + margin-left: -1em; +} +.ph-duotone.ph-ruler:before { + content: "\e6b8"; + opacity: 0.2; +} +.ph-duotone.ph-ruler:after { + content: "\e6b9"; + margin-left: -1em; +} +.ph-duotone.ph-sailboat:before { + content: "\e78a"; + opacity: 0.2; +} +.ph-duotone.ph-sailboat:after { + content: "\e78b"; + margin-left: -1em; +} +.ph-duotone.ph-scales:before { + content: "\e750"; + opacity: 0.2; +} +.ph-duotone.ph-scales:after { + content: "\e751"; + margin-left: -1em; +} +.ph-duotone.ph-scan:before { + content: "\ebb6"; + opacity: 0.2; +} +.ph-duotone.ph-scan:after { + content: "\ebb7"; + margin-left: -1em; +} +.ph-duotone.ph-scan-smiley:before { + content: "\ebb4"; + opacity: 0.2; +} +.ph-duotone.ph-scan-smiley:after { + content: "\ebb5"; + margin-left: -1em; +} +.ph-duotone.ph-scissors:before { + content: "\eae0"; + opacity: 0.2; +} +.ph-duotone.ph-scissors:after { + content: "\eae1"; + margin-left: -1em; +} +.ph-duotone.ph-scooter:before { + content: "\e820"; + opacity: 0.2; +} +.ph-duotone.ph-scooter:after { + content: "\e821"; + margin-left: -1em; +} +.ph-duotone.ph-screencast:before { + content: "\e404"; + opacity: 0.2; +} +.ph-duotone.ph-screencast:after { + content: "\e407"; + margin-left: -1em; +} +.ph-duotone.ph-screwdriver:before { + content: "\e86e"; + opacity: 0.2; +} +.ph-duotone.ph-screwdriver:after { + content: "\e86f"; + margin-left: -1em; +} +.ph-duotone.ph-scribble:before { + content: "\e806"; + opacity: 0.2; +} +.ph-duotone.ph-scribble:after { + content: "\e807"; + margin-left: -1em; +} +.ph-duotone.ph-scribble-loop:before { + content: "\e662"; + opacity: 0.2; +} +.ph-duotone.ph-scribble-loop:after { + content: "\e663"; + margin-left: -1em; +} +.ph-duotone.ph-scroll:before { + content: "\eb7a"; + opacity: 0.2; +} +.ph-duotone.ph-scroll:after { + content: "\eb7b"; + margin-left: -1em; +} +.ph-duotone.ph-seal:before { + content: "\e604"; + opacity: 0.2; +} +.ph-duotone.ph-seal:after { + content: "\e605"; + margin-left: -1em; +} +.ph-duotone.ph-seal-check:before { + content: "\e606"; + opacity: 0.2; +} +.ph-duotone.ph-seal-check:after { + content: "\e607"; + margin-left: -1em; +} +.ph-duotone.ph-seal-percent:before { + content: "\e60a"; + opacity: 0.2; +} +.ph-duotone.ph-seal-percent:after { + content: "\e60b"; + margin-left: -1em; +} +.ph-duotone.ph-seal-question:before { + content: "\e608"; + opacity: 0.2; +} +.ph-duotone.ph-seal-question:after { + content: "\e609"; + margin-left: -1em; +} +.ph-duotone.ph-seal-warning:before { + content: "\e60c"; + opacity: 0.2; +} +.ph-duotone.ph-seal-warning:after { + content: "\e60d"; + margin-left: -1em; +} +.ph-duotone.ph-seat:before { + content: "\eb8e"; + opacity: 0.2; +} +.ph-duotone.ph-seat:after { + content: "\eb8f"; + margin-left: -1em; +} +.ph-duotone.ph-seatbelt:before { + content: "\edfe"; + opacity: 0.2; +} +.ph-duotone.ph-seatbelt:after { + content: "\edff"; + margin-left: -1em; +} +.ph-duotone.ph-security-camera:before { + content: "\eca4"; + opacity: 0.2; +} +.ph-duotone.ph-security-camera:after { + content: "\eca5"; + margin-left: -1em; +} +.ph-duotone.ph-selection:before { + content: "\e69a"; + opacity: 0.2; +} +.ph-duotone.ph-selection:after { + content: "\e69b"; + margin-left: -1em; +} +.ph-duotone.ph-selection-all:before { + content: "\e746"; + opacity: 0.2; +} +.ph-duotone.ph-selection-all:after { + content: "\e747"; + margin-left: -1em; +} +.ph-duotone.ph-selection-background:before { + content: "\eaf8"; + opacity: 0.2; +} +.ph-duotone.ph-selection-background:after { + content: "\eaf9"; + margin-left: -1em; +} +.ph-duotone.ph-selection-foreground:before { + content: "\eaf6"; + opacity: 0.2; +} +.ph-duotone.ph-selection-foreground:after { + content: "\eaf7"; + margin-left: -1em; +} +.ph-duotone.ph-selection-inverse:before { + content: "\e744"; + opacity: 0.2; +} +.ph-duotone.ph-selection-inverse:after { + content: "\e745"; + margin-left: -1em; +} +.ph-duotone.ph-selection-plus:before { + content: "\e69c"; + opacity: 0.2; +} +.ph-duotone.ph-selection-plus:after { + content: "\e69d"; + margin-left: -1em; +} +.ph-duotone.ph-selection-slash:before { + content: "\e69e"; + opacity: 0.2; +} +.ph-duotone.ph-selection-slash:after { + content: "\e69f"; + margin-left: -1em; +} +.ph-duotone.ph-shapes:before { + content: "\ec5e"; + opacity: 0.2; +} +.ph-duotone.ph-shapes:after { + content: "\ec5f"; + margin-left: -1em; +} +.ph-duotone.ph-share:before { + content: "\e406"; + opacity: 0.2; +} +.ph-duotone.ph-share:after { + content: "\e409"; + margin-left: -1em; +} +.ph-duotone.ph-share-fat:before { + content: "\ed52"; + opacity: 0.2; +} +.ph-duotone.ph-share-fat:after { + content: "\ed57"; + margin-left: -1em; +} +.ph-duotone.ph-share-network:before { + content: "\e408"; + opacity: 0.2; +} +.ph-duotone.ph-share-network:after { + content: "\e40b"; + margin-left: -1em; +} +.ph-duotone.ph-shield:before { + content: "\e40a"; + opacity: 0.2; +} +.ph-duotone.ph-shield:after { + content: "\e40d"; + margin-left: -1em; +} +.ph-duotone.ph-shield-check:before { + content: "\e40c"; + opacity: 0.2; +} +.ph-duotone.ph-shield-check:after { + content: "\e40f"; + margin-left: -1em; +} +.ph-duotone.ph-shield-checkered:before { + content: "\e708"; + opacity: 0.2; +} +.ph-duotone.ph-shield-checkered:after { + content: "\e709"; + margin-left: -1em; +} +.ph-duotone.ph-shield-chevron:before { + content: "\e40e"; + opacity: 0.2; +} +.ph-duotone.ph-shield-chevron:after { + content: "\e411"; + margin-left: -1em; +} +.ph-duotone.ph-shield-plus:before { + content: "\e706"; + opacity: 0.2; +} +.ph-duotone.ph-shield-plus:after { + content: "\e707"; + margin-left: -1em; +} +.ph-duotone.ph-shield-slash:before { + content: "\e410"; + opacity: 0.2; +} +.ph-duotone.ph-shield-slash:after { + content: "\e413"; + margin-left: -1em; +} +.ph-duotone.ph-shield-star:before { + content: "\ec34"; + opacity: 0.2; +} +.ph-duotone.ph-shield-star:after { + content: "\ec35"; + margin-left: -1em; +} +.ph-duotone.ph-shield-warning:before { + content: "\e412"; + opacity: 0.2; +} +.ph-duotone.ph-shield-warning:after { + content: "\e414"; + margin-left: -1em; +} +.ph-duotone.ph-shipping-container:before { + content: "\e78c"; + opacity: 0.2; +} +.ph-duotone.ph-shipping-container:after { + content: "\e78d"; + margin-left: -1em; +} +.ph-duotone.ph-shirt-folded:before { + content: "\ea92"; + opacity: 0.2; +} +.ph-duotone.ph-shirt-folded:after { + content: "\ea93"; + margin-left: -1em; +} +.ph-duotone.ph-shooting-star:before { + content: "\ecfa"; + opacity: 0.2; +} +.ph-duotone.ph-shooting-star:after { + content: "\ecfb"; + margin-left: -1em; +} +.ph-duotone.ph-shopping-bag:before { + content: "\e416"; + opacity: 0.2; +} +.ph-duotone.ph-shopping-bag:after { + content: "\e417"; + margin-left: -1em; +} +.ph-duotone.ph-shopping-bag-open:before { + content: "\e418"; + opacity: 0.2; +} +.ph-duotone.ph-shopping-bag-open:after { + content: "\e419"; + margin-left: -1em; +} +.ph-duotone.ph-shopping-cart:before { + content: "\e41e"; + opacity: 0.2; +} +.ph-duotone.ph-shopping-cart:after { + content: "\e41f"; + margin-left: -1em; +} +.ph-duotone.ph-shopping-cart-simple:before { + content: "\e420"; + opacity: 0.2; +} +.ph-duotone.ph-shopping-cart-simple:after { + content: "\e421"; + margin-left: -1em; +} +.ph-duotone.ph-shovel:before { + content: "\e9e6"; + opacity: 0.2; +} +.ph-duotone.ph-shovel:after { + content: "\e9e7"; + margin-left: -1em; +} +.ph-duotone.ph-shower:before { + content: "\e776"; + opacity: 0.2; +} +.ph-duotone.ph-shower:after { + content: "\e777"; + margin-left: -1em; +} +.ph-duotone.ph-shrimp:before { + content: "\eab4"; + opacity: 0.2; +} +.ph-duotone.ph-shrimp:after { + content: "\eab5"; + margin-left: -1em; +} +.ph-duotone.ph-shuffle:before { + content: "\e422"; + opacity: 0.2; +} +.ph-duotone.ph-shuffle:after { + content: "\e423"; + margin-left: -1em; +} +.ph-duotone.ph-shuffle-angular:before { + content: "\e424"; + opacity: 0.2; +} +.ph-duotone.ph-shuffle-angular:after { + content: "\e425"; + margin-left: -1em; +} +.ph-duotone.ph-shuffle-simple:before { + content: "\e426"; + opacity: 0.2; +} +.ph-duotone.ph-shuffle-simple:after { + content: "\e427"; + margin-left: -1em; +} +.ph-duotone.ph-sidebar:before { + content: "\eab6"; + opacity: 0.2; +} +.ph-duotone.ph-sidebar:after { + content: "\eab7"; + margin-left: -1em; +} +.ph-duotone.ph-sidebar-simple:before { + content: "\ec24"; + opacity: 0.2; +} +.ph-duotone.ph-sidebar-simple:after { + content: "\ec25"; + margin-left: -1em; +} +.ph-duotone.ph-sigma:before { + content: "\eab8"; + opacity: 0.2; +} +.ph-duotone.ph-sigma:after { + content: "\eab9"; + margin-left: -1em; +} +.ph-duotone.ph-sign-in:before { + content: "\e428"; + opacity: 0.2; +} +.ph-duotone.ph-sign-in:after { + content: "\e429"; + margin-left: -1em; +} +.ph-duotone.ph-sign-out:before { + content: "\e42a"; + opacity: 0.2; +} +.ph-duotone.ph-sign-out:after { + content: "\e42b"; + margin-left: -1em; +} +.ph-duotone.ph-signature:before { + content: "\ebac"; + opacity: 0.2; +} +.ph-duotone.ph-signature:after { + content: "\ebad"; + margin-left: -1em; +} +.ph-duotone.ph-signpost:before { + content: "\e89c"; + opacity: 0.2; +} +.ph-duotone.ph-signpost:after { + content: "\e89d"; + margin-left: -1em; +} +.ph-duotone.ph-sim-card:before { + content: "\e664"; + opacity: 0.2; +} +.ph-duotone.ph-sim-card:after { + content: "\e665"; + margin-left: -1em; +} +.ph-duotone.ph-siren:before { + content: "\e9b8"; + opacity: 0.2; +} +.ph-duotone.ph-siren:after { + content: "\e9b9"; + margin-left: -1em; +} +.ph-duotone.ph-sketch-logo:before { + content: "\e42c"; + opacity: 0.2; +} +.ph-duotone.ph-sketch-logo:after { + content: "\e42d"; + margin-left: -1em; +} +.ph-duotone.ph-skip-back:before { + content: "\e5a4"; + opacity: 0.2; +} +.ph-duotone.ph-skip-back:after { + content: "\e5a5"; + margin-left: -1em; +} +.ph-duotone.ph-skip-back-circle:before { + content: "\e42e"; + opacity: 0.2; +} +.ph-duotone.ph-skip-back-circle:after { + content: "\e42f"; + margin-left: -1em; +} +.ph-duotone.ph-skip-forward:before { + content: "\e5a6"; + opacity: 0.2; +} +.ph-duotone.ph-skip-forward:after { + content: "\e5a7"; + margin-left: -1em; +} +.ph-duotone.ph-skip-forward-circle:before { + content: "\e430"; + opacity: 0.2; +} +.ph-duotone.ph-skip-forward-circle:after { + content: "\e431"; + margin-left: -1em; +} +.ph-duotone.ph-skull:before { + content: "\e916"; + opacity: 0.2; +} +.ph-duotone.ph-skull:after { + content: "\e917"; + margin-left: -1em; +} +.ph-duotone.ph-skype-logo:before { + content: "\e8dc"; + opacity: 0.2; +} +.ph-duotone.ph-skype-logo:after { + content: "\e8dd"; + margin-left: -1em; +} +.ph-duotone.ph-slack-logo:before { + content: "\e5a8"; + opacity: 0.2; +} +.ph-duotone.ph-slack-logo:after { + content: "\e5a9"; + margin-left: -1em; +} +.ph-duotone.ph-sliders:before { + content: "\e432"; + opacity: 0.2; +} +.ph-duotone.ph-sliders:after { + content: "\e433"; + margin-left: -1em; +} +.ph-duotone.ph-sliders-horizontal:before { + content: "\e434"; + opacity: 0.2; +} +.ph-duotone.ph-sliders-horizontal:after { + content: "\e435"; + margin-left: -1em; +} +.ph-duotone.ph-slideshow:before { + content: "\ed32"; + opacity: 0.2; +} +.ph-duotone.ph-slideshow:after { + content: "\ed33"; + margin-left: -1em; +} +.ph-duotone.ph-smiley:before { + content: "\e436"; + opacity: 0.2; +} +.ph-duotone.ph-smiley:after { + content: "\e437"; + margin-left: -1em; +} +.ph-duotone.ph-smiley-angry:before { + content: "\ec62"; + opacity: 0.2; +} +.ph-duotone.ph-smiley-angry:after { + content: "\ec63"; + margin-left: -1em; +} +.ph-duotone.ph-smiley-blank:before { + content: "\e438"; + opacity: 0.2; +} +.ph-duotone.ph-smiley-blank:after { + content: "\e439"; + margin-left: -1em; +} +.ph-duotone.ph-smiley-meh:before { + content: "\e43a"; + opacity: 0.2; +} +.ph-duotone.ph-smiley-meh:after { + content: "\e43b"; + margin-left: -1em; +} +.ph-duotone.ph-smiley-melting:before { + content: "\ee56"; + opacity: 0.2; +} +.ph-duotone.ph-smiley-melting:after { + content: "\ee57"; + margin-left: -1em; +} +.ph-duotone.ph-smiley-nervous:before { + content: "\e43c"; + opacity: 0.2; +} +.ph-duotone.ph-smiley-nervous:after { + content: "\e43d"; + margin-left: -1em; +} +.ph-duotone.ph-smiley-sad:before { + content: "\e43e"; + opacity: 0.2; +} +.ph-duotone.ph-smiley-sad:after { + content: "\e43f"; + margin-left: -1em; +} +.ph-duotone.ph-smiley-sticker:before { + content: "\e440"; + opacity: 0.2; +} +.ph-duotone.ph-smiley-sticker:after { + content: "\e441"; + margin-left: -1em; +} +.ph-duotone.ph-smiley-wink:before { + content: "\e666"; + opacity: 0.2; +} +.ph-duotone.ph-smiley-wink:after { + content: "\e667"; + margin-left: -1em; +} +.ph-duotone.ph-smiley-x-eyes:before { + content: "\e442"; + opacity: 0.2; +} +.ph-duotone.ph-smiley-x-eyes:after { + content: "\e443"; + margin-left: -1em; +} +.ph-duotone.ph-snapchat-logo:before { + content: "\e668"; + opacity: 0.2; +} +.ph-duotone.ph-snapchat-logo:after { + content: "\e669"; + margin-left: -1em; +} +.ph-duotone.ph-sneaker:before { + content: "\e80c"; + opacity: 0.2; +} +.ph-duotone.ph-sneaker:after { + content: "\e80d"; + margin-left: -1em; +} +.ph-duotone.ph-sneaker-move:before { + content: "\ed60"; + opacity: 0.2; +} +.ph-duotone.ph-sneaker-move:after { + content: "\ed61"; + margin-left: -1em; +} +.ph-duotone.ph-snowflake:before { + content: "\e5aa"; + opacity: 0.2; +} +.ph-duotone.ph-snowflake:after { + content: "\e5ab"; + margin-left: -1em; +} +.ph-duotone.ph-soccer-ball:before { + content: "\e716"; + opacity: 0.2; +} +.ph-duotone.ph-soccer-ball:after { + content: "\e717"; + margin-left: -1em; +} +.ph-duotone.ph-sock:before { + content: "\ecce"; + opacity: 0.2; +} +.ph-duotone.ph-sock:after { + content: "\eccf"; + margin-left: -1em; +} +.ph-duotone.ph-solar-panel:before { + content: "\ed7a"; + opacity: 0.2; +} +.ph-duotone.ph-solar-panel:after { + content: "\ed7e"; + margin-left: -1em; +} +.ph-duotone.ph-solar-roof:before { + content: "\ed7b"; + opacity: 0.2; +} +.ph-duotone.ph-solar-roof:after { + content: "\ed7f"; + margin-left: -1em; +} +.ph-duotone.ph-sort-ascending:before { + content: "\e444"; + opacity: 0.2; +} +.ph-duotone.ph-sort-ascending:after { + content: "\e445"; + margin-left: -1em; +} +.ph-duotone.ph-sort-descending:before { + content: "\e446"; + opacity: 0.2; +} +.ph-duotone.ph-sort-descending:after { + content: "\e447"; + margin-left: -1em; +} +.ph-duotone.ph-soundcloud-logo:before { + content: "\e8de"; + opacity: 0.2; +} +.ph-duotone.ph-soundcloud-logo:after { + content: "\e8df"; + margin-left: -1em; +} +.ph-duotone.ph-spade:before { + content: "\e448"; + opacity: 0.2; +} +.ph-duotone.ph-spade:after { + content: "\e449"; + margin-left: -1em; +} +.ph-duotone.ph-sparkle:before { + content: "\e6a2"; + opacity: 0.2; +} +.ph-duotone.ph-sparkle:after { + content: "\e6a3"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-hifi:before { + content: "\ea08"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-hifi:after { + content: "\ea09"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-high:before { + content: "\e44a"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-high:after { + content: "\e44b"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-low:before { + content: "\e44c"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-low:after { + content: "\e44d"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-none:before { + content: "\e44e"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-none:after { + content: "\e44f"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-simple-high:before { + content: "\e450"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-simple-high:after { + content: "\e451"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-simple-low:before { + content: "\e452"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-simple-low:after { + content: "\e453"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-simple-none:before { + content: "\e454"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-simple-none:after { + content: "\e455"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-simple-slash:before { + content: "\e456"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-simple-slash:after { + content: "\e457"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-simple-x:before { + content: "\e458"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-simple-x:after { + content: "\e459"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-slash:before { + content: "\e45a"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-slash:after { + content: "\e45b"; + margin-left: -1em; +} +.ph-duotone.ph-speaker-x:before { + content: "\e45c"; + opacity: 0.2; +} +.ph-duotone.ph-speaker-x:after { + content: "\e45d"; + margin-left: -1em; +} +.ph-duotone.ph-speedometer:before { + content: "\ee74"; + opacity: 0.2; +} +.ph-duotone.ph-speedometer:after { + content: "\ee75"; + margin-left: -1em; +} +.ph-duotone.ph-sphere:before { + content: "\ee66"; + opacity: 0.2; +} +.ph-duotone.ph-sphere:after { + content: "\ee67"; + margin-left: -1em; +} +.ph-duotone.ph-spinner:before { + content: "\e66a"; + opacity: 0.2; +} +.ph-duotone.ph-spinner:after { + content: "\e66b"; + margin-left: -1em; +} +.ph-duotone.ph-spinner-ball:before { + content: "\ee28"; + opacity: 0.2; +} +.ph-duotone.ph-spinner-ball:after { + content: "\ee29"; + margin-left: -1em; +} +.ph-duotone.ph-spinner-gap:before { + content: "\e66c"; + opacity: 0.2; +} +.ph-duotone.ph-spinner-gap:after { + content: "\e66d"; + margin-left: -1em; +} +.ph-duotone.ph-spiral:before { + content: "\e9fa"; + opacity: 0.2; +} +.ph-duotone.ph-spiral:after { + content: "\e9fb"; + margin-left: -1em; +} +.ph-duotone.ph-split-horizontal:before { + content: "\e872"; + opacity: 0.2; +} +.ph-duotone.ph-split-horizontal:after { + content: "\e873"; + margin-left: -1em; +} +.ph-duotone.ph-split-vertical:before { + content: "\e876"; + opacity: 0.2; +} +.ph-duotone.ph-split-vertical:after { + content: "\e877"; + margin-left: -1em; +} +.ph-duotone.ph-spotify-logo:before { + content: "\e66e"; + opacity: 0.2; +} +.ph-duotone.ph-spotify-logo:after { + content: "\e66f"; + margin-left: -1em; +} +.ph-duotone.ph-spray-bottle:before { + content: "\e7e4"; + opacity: 0.2; +} +.ph-duotone.ph-spray-bottle:after { + content: "\e7e8"; + margin-left: -1em; +} +.ph-duotone.ph-square:before { + content: "\e45e"; + opacity: 0.2; +} +.ph-duotone.ph-square:after { + content: "\e45f"; + margin-left: -1em; +} +.ph-duotone.ph-square-half:before { + content: "\e462"; + opacity: 0.2; +} +.ph-duotone.ph-square-half:after { + content: "\e463"; + margin-left: -1em; +} +.ph-duotone.ph-square-half-bottom:before { + content: "\eb16"; + opacity: 0.2; +} +.ph-duotone.ph-square-half-bottom:after { + content: "\eb17"; + margin-left: -1em; +} +.ph-duotone.ph-square-logo:before { + content: "\e690"; + opacity: 0.2; +} +.ph-duotone.ph-square-logo:after { + content: "\e691"; + margin-left: -1em; +} +.ph-duotone.ph-square-split-horizontal:before { + content: "\e870"; + opacity: 0.2; +} +.ph-duotone.ph-square-split-horizontal:after { + content: "\e871"; + margin-left: -1em; +} +.ph-duotone.ph-square-split-vertical:before { + content: "\e874"; + opacity: 0.2; +} +.ph-duotone.ph-square-split-vertical:after { + content: "\e875"; + margin-left: -1em; +} +.ph-duotone.ph-squares-four:before { + content: "\e464"; + opacity: 0.2; +} +.ph-duotone.ph-squares-four:after { + content: "\e465"; + margin-left: -1em; +} +.ph-duotone.ph-stack:before { + content: "\e466"; + opacity: 0.2; +} +.ph-duotone.ph-stack:after { + content: "\e467"; + margin-left: -1em; +} +.ph-duotone.ph-stack-minus:before { + content: "\edf4"; + opacity: 0.2; +} +.ph-duotone.ph-stack-minus:after { + content: "\edf5"; + margin-left: -1em; +} +.ph-duotone.ph-stack-overflow-logo:before { + content: "\eb78"; + opacity: 0.2; +} +.ph-duotone.ph-stack-overflow-logo:after { + content: "\eb79"; + margin-left: -1em; +} +.ph-duotone.ph-stack-plus:before { + content: "\edf6"; + opacity: 0.2; +} +.ph-duotone.ph-stack-plus:after { + content: "\edf7"; + margin-left: -1em; +} +.ph-duotone.ph-stack-simple:before { + content: "\e468"; + opacity: 0.2; +} +.ph-duotone.ph-stack-simple:after { + content: "\e469"; + margin-left: -1em; +} +.ph-duotone.ph-stairs:before { + content: "\e8ec"; + opacity: 0.2; +} +.ph-duotone.ph-stairs:after { + content: "\e8ed"; + margin-left: -1em; +} +.ph-duotone.ph-stamp:before { + content: "\ea48"; + opacity: 0.2; +} +.ph-duotone.ph-stamp:after { + content: "\ea49"; + margin-left: -1em; +} +.ph-duotone.ph-standard-definition:before { + content: "\ea90"; + opacity: 0.2; +} +.ph-duotone.ph-standard-definition:after { + content: "\ea91"; + margin-left: -1em; +} +.ph-duotone.ph-star:before { + content: "\e46a"; + opacity: 0.2; +} +.ph-duotone.ph-star:after { + content: "\e46b"; + margin-left: -1em; +} +.ph-duotone.ph-star-and-crescent:before { + content: "\ecf4"; + opacity: 0.2; +} +.ph-duotone.ph-star-and-crescent:after { + content: "\ecf5"; + margin-left: -1em; +} +.ph-duotone.ph-star-four:before { + content: "\e6a4"; + opacity: 0.2; +} +.ph-duotone.ph-star-four:after { + content: "\e6a5"; + margin-left: -1em; +} +.ph-duotone.ph-star-half:before { + content: "\e70a"; + opacity: 0.2; +} +.ph-duotone.ph-star-half:after { + content: "\e70b"; + margin-left: -1em; +} +.ph-duotone.ph-star-of-david:before { + content: "\e89e"; + opacity: 0.2; +} +.ph-duotone.ph-star-of-david:after { + content: "\e89f"; + margin-left: -1em; +} +.ph-duotone.ph-steam-logo:before { + content: "\ead4"; + opacity: 0.2; +} +.ph-duotone.ph-steam-logo:after { + content: "\ead5"; + margin-left: -1em; +} +.ph-duotone.ph-steering-wheel:before { + content: "\e9ac"; + opacity: 0.2; +} +.ph-duotone.ph-steering-wheel:after { + content: "\e9ad"; + margin-left: -1em; +} +.ph-duotone.ph-steps:before { + content: "\ecbe"; + opacity: 0.2; +} +.ph-duotone.ph-steps:after { + content: "\ecbf"; + margin-left: -1em; +} +.ph-duotone.ph-stethoscope:before { + content: "\e7ea"; + opacity: 0.2; +} +.ph-duotone.ph-stethoscope:after { + content: "\e7eb"; + margin-left: -1em; +} +.ph-duotone.ph-sticker:before { + content: "\e5ac"; + opacity: 0.2; +} +.ph-duotone.ph-sticker:after { + content: "\e5ad"; + margin-left: -1em; +} +.ph-duotone.ph-stool:before { + content: "\ea44"; + opacity: 0.2; +} +.ph-duotone.ph-stool:after { + content: "\ea45"; + margin-left: -1em; +} +.ph-duotone.ph-stop:before { + content: "\e46c"; + opacity: 0.2; +} +.ph-duotone.ph-stop:after { + content: "\e46d"; + margin-left: -1em; +} +.ph-duotone.ph-stop-circle:before { + content: "\e46e"; + opacity: 0.2; +} +.ph-duotone.ph-stop-circle:after { + content: "\e46f"; + margin-left: -1em; +} +.ph-duotone.ph-storefront:before { + content: "\e470"; + opacity: 0.2; +} +.ph-duotone.ph-storefront:after { + content: "\e471"; + margin-left: -1em; +} +.ph-duotone.ph-strategy:before { + content: "\ea3a"; + opacity: 0.2; +} +.ph-duotone.ph-strategy:after { + content: "\ea3b"; + margin-left: -1em; +} +.ph-duotone.ph-stripe-logo:before { + content: "\e698"; + opacity: 0.2; +} +.ph-duotone.ph-stripe-logo:after { + content: "\e699"; + margin-left: -1em; +} +.ph-duotone.ph-student:before { + content: "\e73e"; + opacity: 0.2; +} +.ph-duotone.ph-student:after { + content: "\e73f"; + margin-left: -1em; +} +.ph-duotone.ph-subset-of:before { + content: "\edc0"; + opacity: 0.2; +} +.ph-duotone.ph-subset-of:after { + content: "\edc1"; + margin-left: -1em; +} +.ph-duotone.ph-subset-proper-of:before { + content: "\edb6"; + opacity: 0.2; +} +.ph-duotone.ph-subset-proper-of:after { + content: "\edb7"; + margin-left: -1em; +} +.ph-duotone.ph-subtitles:before { + content: "\e1a8"; + opacity: 0.2; +} +.ph-duotone.ph-subtitles:after { + content: "\e1a9"; + margin-left: -1em; +} +.ph-duotone.ph-subtitles-slash:before { + content: "\e1a6"; + opacity: 0.2; +} +.ph-duotone.ph-subtitles-slash:after { + content: "\e1a7"; + margin-left: -1em; +} +.ph-duotone.ph-subtract:before { + content: "\ebd6"; + opacity: 0.2; +} +.ph-duotone.ph-subtract:after { + content: "\ebd7"; + margin-left: -1em; +} +.ph-duotone.ph-subtract-square:before { + content: "\ebd4"; + opacity: 0.2; +} +.ph-duotone.ph-subtract-square:after { + content: "\ebd5"; + margin-left: -1em; +} +.ph-duotone.ph-subway:before { + content: "\e498"; + opacity: 0.2; +} +.ph-duotone.ph-subway:after { + content: "\e499"; + margin-left: -1em; +} +.ph-duotone.ph-suitcase:before { + content: "\e5ae"; + opacity: 0.2; +} +.ph-duotone.ph-suitcase:after { + content: "\e5af"; + margin-left: -1em; +} +.ph-duotone.ph-suitcase-rolling:before { + content: "\e9b0"; + opacity: 0.2; +} +.ph-duotone.ph-suitcase-rolling:after { + content: "\e9b1"; + margin-left: -1em; +} +.ph-duotone.ph-suitcase-simple:before { + content: "\e5b0"; + opacity: 0.2; +} +.ph-duotone.ph-suitcase-simple:after { + content: "\e5b1"; + margin-left: -1em; +} +.ph-duotone.ph-sun:before { + content: "\e472"; + opacity: 0.2; +} +.ph-duotone.ph-sun:after { + content: "\e473"; + margin-left: -1em; +} +.ph-duotone.ph-sun-dim:before { + content: "\e474"; + opacity: 0.2; +} +.ph-duotone.ph-sun-dim:after { + content: "\e475"; + margin-left: -1em; +} +.ph-duotone.ph-sun-horizon:before { + content: "\e5b6"; + opacity: 0.2; +} +.ph-duotone.ph-sun-horizon:after { + content: "\e5b7"; + margin-left: -1em; +} +.ph-duotone.ph-sunglasses:before { + content: "\e816"; + opacity: 0.2; +} +.ph-duotone.ph-sunglasses:after { + content: "\e817"; + margin-left: -1em; +} +.ph-duotone.ph-superset-of:before { + content: "\edb8"; + opacity: 0.2; +} +.ph-duotone.ph-superset-of:after { + content: "\edb9"; + margin-left: -1em; +} +.ph-duotone.ph-superset-proper-of:before { + content: "\edb4"; + opacity: 0.2; +} +.ph-duotone.ph-superset-proper-of:after { + content: "\edb5"; + margin-left: -1em; +} +.ph-duotone.ph-swap:before { + content: "\e83c"; + opacity: 0.2; +} +.ph-duotone.ph-swap:after { + content: "\e83d"; + margin-left: -1em; +} +.ph-duotone.ph-swatches:before { + content: "\e5b8"; + opacity: 0.2; +} +.ph-duotone.ph-swatches:after { + content: "\e5b9"; + margin-left: -1em; +} +.ph-duotone.ph-swimming-pool:before { + content: "\ecb6"; + opacity: 0.2; +} +.ph-duotone.ph-swimming-pool:after { + content: "\ecb7"; + margin-left: -1em; +} +.ph-duotone.ph-sword:before { + content: "\e5ba"; + opacity: 0.2; +} +.ph-duotone.ph-sword:after { + content: "\e5bb"; + margin-left: -1em; +} +.ph-duotone.ph-synagogue:before { + content: "\ecec"; + opacity: 0.2; +} +.ph-duotone.ph-synagogue:after { + content: "\eced"; + margin-left: -1em; +} +.ph-duotone.ph-syringe:before { + content: "\e968"; + opacity: 0.2; +} +.ph-duotone.ph-syringe:after { + content: "\e969"; + margin-left: -1em; +} +.ph-duotone.ph-t-shirt:before { + content: "\e670"; + opacity: 0.2; +} +.ph-duotone.ph-t-shirt:after { + content: "\e671"; + margin-left: -1em; +} +.ph-duotone.ph-table:before { + content: "\e476"; + opacity: 0.2; +} +.ph-duotone.ph-table:after { + content: "\e477"; + margin-left: -1em; +} +.ph-duotone.ph-tabs:before { + content: "\e778"; + opacity: 0.2; +} +.ph-duotone.ph-tabs:after { + content: "\e779"; + margin-left: -1em; +} +.ph-duotone.ph-tag:before { + content: "\e478"; + opacity: 0.2; +} +.ph-duotone.ph-tag:after { + content: "\e479"; + margin-left: -1em; +} +.ph-duotone.ph-tag-chevron:before { + content: "\e672"; + opacity: 0.2; +} +.ph-duotone.ph-tag-chevron:after { + content: "\e673"; + margin-left: -1em; +} +.ph-duotone.ph-tag-simple:before { + content: "\e47a"; + opacity: 0.2; +} +.ph-duotone.ph-tag-simple:after { + content: "\e47b"; + margin-left: -1em; +} +.ph-duotone.ph-target:before { + content: "\e47c"; + opacity: 0.2; +} +.ph-duotone.ph-target:after { + content: "\e47d"; + margin-left: -1em; +} +.ph-duotone.ph-taxi:before { + content: "\e902"; + opacity: 0.2; +} +.ph-duotone.ph-taxi:after { + content: "\e903"; + margin-left: -1em; +} +.ph-duotone.ph-tea-bag:before { + content: "\e8e6"; + opacity: 0.2; +} +.ph-duotone.ph-tea-bag:after { + content: "\e8e7"; + margin-left: -1em; +} +.ph-duotone.ph-telegram-logo:before { + content: "\e5bc"; + opacity: 0.2; +} +.ph-duotone.ph-telegram-logo:after { + content: "\e5bd"; + margin-left: -1em; +} +.ph-duotone.ph-television:before { + content: "\e754"; + opacity: 0.2; +} +.ph-duotone.ph-television:after { + content: "\e755"; + margin-left: -1em; +} +.ph-duotone.ph-television-simple:before { + content: "\eae6"; + opacity: 0.2; +} +.ph-duotone.ph-television-simple:after { + content: "\eae7"; + margin-left: -1em; +} +.ph-duotone.ph-tennis-ball:before { + content: "\e720"; + opacity: 0.2; +} +.ph-duotone.ph-tennis-ball:after { + content: "\e721"; + margin-left: -1em; +} +.ph-duotone.ph-tent:before { + content: "\e8ba"; + opacity: 0.2; +} +.ph-duotone.ph-tent:after { + content: "\e8bb"; + margin-left: -1em; +} +.ph-duotone.ph-terminal:before { + content: "\e47e"; + opacity: 0.2; +} +.ph-duotone.ph-terminal:after { + content: "\e47f"; + margin-left: -1em; +} +.ph-duotone.ph-terminal-window:before { + content: "\eae8"; + opacity: 0.2; +} +.ph-duotone.ph-terminal-window:after { + content: "\eae9"; + margin-left: -1em; +} +.ph-duotone.ph-test-tube:before { + content: "\e7a0"; + opacity: 0.2; +} +.ph-duotone.ph-test-tube:after { + content: "\e7a1"; + margin-left: -1em; +} +.ph-duotone.ph-text-a-underline:before { + content: "\ed34"; + opacity: 0.2; +} +.ph-duotone.ph-text-a-underline:after { + content: "\ed35"; + margin-left: -1em; +} +.ph-duotone.ph-text-aa:before { + content: "\e6ee"; + opacity: 0.2; +} +.ph-duotone.ph-text-aa:after { + content: "\e6ef"; + margin-left: -1em; +} +.ph-duotone.ph-text-align-center:before { + content: "\e480"; + opacity: 0.2; +} +.ph-duotone.ph-text-align-center:after { + content: "\e481"; + margin-left: -1em; +} +.ph-duotone.ph-text-align-justify:before { + content: "\e482"; + opacity: 0.2; +} +.ph-duotone.ph-text-align-justify:after { + content: "\e483"; + margin-left: -1em; +} +.ph-duotone.ph-text-align-left:before { + content: "\e484"; + opacity: 0.2; +} +.ph-duotone.ph-text-align-left:after { + content: "\e485"; + margin-left: -1em; +} +.ph-duotone.ph-text-align-right:before { + content: "\e486"; + opacity: 0.2; +} +.ph-duotone.ph-text-align-right:after { + content: "\e487"; + margin-left: -1em; +} +.ph-duotone.ph-text-b:before { + content: "\e5be"; + opacity: 0.2; +} +.ph-duotone.ph-text-b:after { + content: "\e5bf"; + margin-left: -1em; +} +.ph-duotone.ph-text-columns:before { + content: "\ec96"; + opacity: 0.2; +} +.ph-duotone.ph-text-columns:after { + content: "\ec97"; + margin-left: -1em; +} +.ph-duotone.ph-text-h:before { + content: "\e6ba"; + opacity: 0.2; +} +.ph-duotone.ph-text-h:after { + content: "\e6bb"; + margin-left: -1em; +} +.ph-duotone.ph-text-h-five:before { + content: "\e6c4"; + opacity: 0.2; +} +.ph-duotone.ph-text-h-five:after { + content: "\e6c5"; + margin-left: -1em; +} +.ph-duotone.ph-text-h-four:before { + content: "\e6c2"; + opacity: 0.2; +} +.ph-duotone.ph-text-h-four:after { + content: "\e6c3"; + margin-left: -1em; +} +.ph-duotone.ph-text-h-one:before { + content: "\e6bc"; + opacity: 0.2; +} +.ph-duotone.ph-text-h-one:after { + content: "\e6bd"; + margin-left: -1em; +} +.ph-duotone.ph-text-h-six:before { + content: "\e6c6"; + opacity: 0.2; +} +.ph-duotone.ph-text-h-six:after { + content: "\e6c7"; + margin-left: -1em; +} +.ph-duotone.ph-text-h-three:before { + content: "\e6c0"; + opacity: 0.2; +} +.ph-duotone.ph-text-h-three:after { + content: "\e6c1"; + margin-left: -1em; +} +.ph-duotone.ph-text-h-two:before { + content: "\e6be"; + opacity: 0.2; +} +.ph-duotone.ph-text-h-two:after { + content: "\e6bf"; + margin-left: -1em; +} +.ph-duotone.ph-text-indent:before { + content: "\ea1e"; + opacity: 0.2; +} +.ph-duotone.ph-text-indent:after { + content: "\ea1f"; + margin-left: -1em; +} +.ph-duotone.ph-text-italic:before { + content: "\e5c0"; + opacity: 0.2; +} +.ph-duotone.ph-text-italic:after { + content: "\e5c1"; + margin-left: -1em; +} +.ph-duotone.ph-text-outdent:before { + content: "\ea1c"; + opacity: 0.2; +} +.ph-duotone.ph-text-outdent:after { + content: "\ea1d"; + margin-left: -1em; +} +.ph-duotone.ph-text-strikethrough:before { + content: "\e5c2"; + opacity: 0.2; +} +.ph-duotone.ph-text-strikethrough:after { + content: "\e5c3"; + margin-left: -1em; +} +.ph-duotone.ph-text-subscript:before { + content: "\ec98"; + opacity: 0.2; +} +.ph-duotone.ph-text-subscript:after { + content: "\ec99"; + margin-left: -1em; +} +.ph-duotone.ph-text-superscript:before { + content: "\ec9a"; + opacity: 0.2; +} +.ph-duotone.ph-text-superscript:after { + content: "\ec9b"; + margin-left: -1em; +} +.ph-duotone.ph-text-t:before { + content: "\e48a"; + opacity: 0.2; +} +.ph-duotone.ph-text-t:after { + content: "\e48b"; + margin-left: -1em; +} +.ph-duotone.ph-text-t-slash:before { + content: "\e488"; + opacity: 0.2; +} +.ph-duotone.ph-text-t-slash:after { + content: "\e489"; + margin-left: -1em; +} +.ph-duotone.ph-text-underline:before { + content: "\e5c4"; + opacity: 0.2; +} +.ph-duotone.ph-text-underline:after { + content: "\e5c5"; + margin-left: -1em; +} +.ph-duotone.ph-textbox:before { + content: "\eb0a"; + opacity: 0.2; +} +.ph-duotone.ph-textbox:after { + content: "\eb0b"; + margin-left: -1em; +} +.ph-duotone.ph-thermometer:before { + content: "\e5c6"; + opacity: 0.2; +} +.ph-duotone.ph-thermometer:after { + content: "\e5c7"; + margin-left: -1em; +} +.ph-duotone.ph-thermometer-cold:before { + content: "\e5c8"; + opacity: 0.2; +} +.ph-duotone.ph-thermometer-cold:after { + content: "\e5c9"; + margin-left: -1em; +} +.ph-duotone.ph-thermometer-hot:before { + content: "\e5ca"; + opacity: 0.2; +} +.ph-duotone.ph-thermometer-hot:after { + content: "\e5cb"; + margin-left: -1em; +} +.ph-duotone.ph-thermometer-simple:before { + content: "\e5cc"; + opacity: 0.2; +} +.ph-duotone.ph-thermometer-simple:after { + content: "\e5cd"; + margin-left: -1em; +} +.ph-duotone.ph-threads-logo:before { + content: "\ed9e"; + opacity: 0.2; +} +.ph-duotone.ph-threads-logo:after { + content: "\ed9f"; + margin-left: -1em; +} +.ph-duotone.ph-three-d:before { + content: "\ea5a"; + opacity: 0.2; +} +.ph-duotone.ph-three-d:after { + content: "\ea5b"; + margin-left: -1em; +} +.ph-duotone.ph-thumbs-down:before { + content: "\e48c"; + opacity: 0.2; +} +.ph-duotone.ph-thumbs-down:after { + content: "\e48d"; + margin-left: -1em; +} +.ph-duotone.ph-thumbs-up:before { + content: "\e48e"; + opacity: 0.2; +} +.ph-duotone.ph-thumbs-up:after { + content: "\e48f"; + margin-left: -1em; +} +.ph-duotone.ph-ticket:before { + content: "\e490"; + opacity: 0.2; +} +.ph-duotone.ph-ticket:after { + content: "\e491"; + margin-left: -1em; +} +.ph-duotone.ph-tidal-logo:before { + content: "\ed1c"; + opacity: 0.2; +} +.ph-duotone.ph-tidal-logo:after { + content: "\ed1d"; + margin-left: -1em; +} +.ph-duotone.ph-tiktok-logo:before { + content: "\eaf2"; + opacity: 0.2; +} +.ph-duotone.ph-tiktok-logo:after { + content: "\eaf3"; + margin-left: -1em; +} +.ph-duotone.ph-tilde:before { + content: "\eda8"; + opacity: 0.2; +} +.ph-duotone.ph-tilde:after { + content: "\eda9"; + margin-left: -1em; +} +.ph-duotone.ph-timer:before { + content: "\e492"; + opacity: 0.2; +} +.ph-duotone.ph-timer:after { + content: "\e493"; + margin-left: -1em; +} +.ph-duotone.ph-tip-jar:before { + content: "\e7e2"; + opacity: 0.2; +} +.ph-duotone.ph-tip-jar:after { + content: "\e7e9"; + margin-left: -1em; +} +.ph-duotone.ph-tipi:before { + content: "\ed30"; + opacity: 0.2; +} +.ph-duotone.ph-tipi:after { + content: "\ed31"; + margin-left: -1em; +} +.ph-duotone.ph-tire:before { + content: "\edd2"; + opacity: 0.2; +} +.ph-duotone.ph-tire:after { + content: "\edd3"; + margin-left: -1em; +} +.ph-duotone.ph-toggle-left:before { + content: "\e674"; + opacity: 0.2; +} +.ph-duotone.ph-toggle-left:after { + content: "\e675"; + margin-left: -1em; +} +.ph-duotone.ph-toggle-right:before { + content: "\e676"; + opacity: 0.2; +} +.ph-duotone.ph-toggle-right:after { + content: "\e677"; + margin-left: -1em; +} +.ph-duotone.ph-toilet:before { + content: "\e79a"; + opacity: 0.2; +} +.ph-duotone.ph-toilet:after { + content: "\e79b"; + margin-left: -1em; +} +.ph-duotone.ph-toilet-paper:before { + content: "\e79c"; + opacity: 0.2; +} +.ph-duotone.ph-toilet-paper:after { + content: "\e79d"; + margin-left: -1em; +} +.ph-duotone.ph-toolbox:before { + content: "\eca0"; + opacity: 0.2; +} +.ph-duotone.ph-toolbox:after { + content: "\eca1"; + margin-left: -1em; +} +.ph-duotone.ph-tooth:before { + content: "\e9cc"; + opacity: 0.2; +} +.ph-duotone.ph-tooth:after { + content: "\e9cd"; + margin-left: -1em; +} +.ph-duotone.ph-tornado:before { + content: "\e88c"; + opacity: 0.2; +} +.ph-duotone.ph-tornado:after { + content: "\e88d"; + margin-left: -1em; +} +.ph-duotone.ph-tote:before { + content: "\e494"; + opacity: 0.2; +} +.ph-duotone.ph-tote:after { + content: "\e495"; + margin-left: -1em; +} +.ph-duotone.ph-tote-simple:before { + content: "\e678"; + opacity: 0.2; +} +.ph-duotone.ph-tote-simple:after { + content: "\e679"; + margin-left: -1em; +} +.ph-duotone.ph-towel:before { + content: "\ede6"; + opacity: 0.2; +} +.ph-duotone.ph-towel:after { + content: "\ede7"; + margin-left: -1em; +} +.ph-duotone.ph-tractor:before { + content: "\ec6e"; + opacity: 0.2; +} +.ph-duotone.ph-tractor:after { + content: "\ec6f"; + margin-left: -1em; +} +.ph-duotone.ph-trademark:before { + content: "\e9f0"; + opacity: 0.2; +} +.ph-duotone.ph-trademark:after { + content: "\e9f1"; + margin-left: -1em; +} +.ph-duotone.ph-trademark-registered:before { + content: "\e3f4"; + opacity: 0.2; +} +.ph-duotone.ph-trademark-registered:after { + content: "\e415"; + margin-left: -1em; +} +.ph-duotone.ph-traffic-cone:before { + content: "\e9a8"; + opacity: 0.2; +} +.ph-duotone.ph-traffic-cone:after { + content: "\e9a9"; + margin-left: -1em; +} +.ph-duotone.ph-traffic-sign:before { + content: "\e67a"; + opacity: 0.2; +} +.ph-duotone.ph-traffic-sign:after { + content: "\e67b"; + margin-left: -1em; +} +.ph-duotone.ph-traffic-signal:before { + content: "\e9aa"; + opacity: 0.2; +} +.ph-duotone.ph-traffic-signal:after { + content: "\e9ab"; + margin-left: -1em; +} +.ph-duotone.ph-train:before { + content: "\e496"; + opacity: 0.2; +} +.ph-duotone.ph-train:after { + content: "\e497"; + margin-left: -1em; +} +.ph-duotone.ph-train-regional:before { + content: "\e49e"; + opacity: 0.2; +} +.ph-duotone.ph-train-regional:after { + content: "\e49f"; + margin-left: -1em; +} +.ph-duotone.ph-train-simple:before { + content: "\e4a0"; + opacity: 0.2; +} +.ph-duotone.ph-train-simple:after { + content: "\e4a1"; + margin-left: -1em; +} +.ph-duotone.ph-tram:before { + content: "\e9ec"; + opacity: 0.2; +} +.ph-duotone.ph-tram:after { + content: "\e9ed"; + margin-left: -1em; +} +.ph-duotone.ph-translate:before { + content: "\e4a2"; + opacity: 0.2; +} +.ph-duotone.ph-translate:after { + content: "\e4a3"; + margin-left: -1em; +} +.ph-duotone.ph-trash:before { + content: "\e4a6"; + opacity: 0.2; +} +.ph-duotone.ph-trash:after { + content: "\e4a7"; + margin-left: -1em; +} +.ph-duotone.ph-trash-simple:before { + content: "\e4a8"; + opacity: 0.2; +} +.ph-duotone.ph-trash-simple:after { + content: "\e4a9"; + margin-left: -1em; +} +.ph-duotone.ph-tray:before { + content: "\e4aa"; + opacity: 0.2; +} +.ph-duotone.ph-tray:after { + content: "\e4ab"; + margin-left: -1em; +} +.ph-duotone.ph-tray-arrow-down:before { + content: "\e010"; + opacity: 0.2; +} +.ph-duotone.ph-tray-arrow-down:after { + content: "\e011"; + margin-left: -1em; +} +.ph-duotone.ph-tray-arrow-up:before { + content: "\ee52"; + opacity: 0.2; +} +.ph-duotone.ph-tray-arrow-up:after { + content: "\ee53"; + margin-left: -1em; +} +.ph-duotone.ph-treasure-chest:before { + content: "\ede2"; + opacity: 0.2; +} +.ph-duotone.ph-treasure-chest:after { + content: "\ede3"; + margin-left: -1em; +} +.ph-duotone.ph-tree:before { + content: "\e6da"; + opacity: 0.2; +} +.ph-duotone.ph-tree:after { + content: "\e6db"; + margin-left: -1em; +} +.ph-duotone.ph-tree-evergreen:before { + content: "\e6dc"; + opacity: 0.2; +} +.ph-duotone.ph-tree-evergreen:after { + content: "\e6dd"; + margin-left: -1em; +} +.ph-duotone.ph-tree-palm:before { + content: "\e91a"; + opacity: 0.2; +} +.ph-duotone.ph-tree-palm:after { + content: "\e91b"; + margin-left: -1em; +} +.ph-duotone.ph-tree-structure:before { + content: "\e67c"; + opacity: 0.2; +} +.ph-duotone.ph-tree-structure:after { + content: "\e67d"; + margin-left: -1em; +} +.ph-duotone.ph-tree-view:before { + content: "\ee48"; + opacity: 0.2; +} +.ph-duotone.ph-tree-view:after { + content: "\ee49"; + margin-left: -1em; +} +.ph-duotone.ph-trend-down:before { + content: "\e4ac"; + opacity: 0.2; +} +.ph-duotone.ph-trend-down:after { + content: "\e4ad"; + margin-left: -1em; +} +.ph-duotone.ph-trend-up:before { + content: "\e4ae"; + opacity: 0.2; +} +.ph-duotone.ph-trend-up:after { + content: "\e4af"; + margin-left: -1em; +} +.ph-duotone.ph-triangle:before { + content: "\e4b0"; + opacity: 0.2; +} +.ph-duotone.ph-triangle:after { + content: "\e4b1"; + margin-left: -1em; +} +.ph-duotone.ph-triangle-dashed:before { + content: "\e4b2"; + opacity: 0.2; +} +.ph-duotone.ph-triangle-dashed:after { + content: "\e4b3"; + margin-left: -1em; +} +.ph-duotone.ph-trolley:before { + content: "\e5b2"; + opacity: 0.2; +} +.ph-duotone.ph-trolley:after { + content: "\e5b3"; + margin-left: -1em; +} +.ph-duotone.ph-trolley-suitcase:before { + content: "\e5b4"; + opacity: 0.2; +} +.ph-duotone.ph-trolley-suitcase:after { + content: "\e5b5"; + margin-left: -1em; +} +.ph-duotone.ph-trophy:before { + content: "\e67e"; + opacity: 0.2; +} +.ph-duotone.ph-trophy:after { + content: "\e67f"; + margin-left: -1em; +} +.ph-duotone.ph-truck:before { + content: "\e4b4"; + opacity: 0.2; +} +.ph-duotone.ph-truck:after { + content: "\e4b5"; + margin-left: -1em; +} +.ph-duotone.ph-truck-trailer:before { + content: "\e4b6"; + opacity: 0.2; +} +.ph-duotone.ph-truck-trailer:after { + content: "\e4b7"; + margin-left: -1em; +} +.ph-duotone.ph-tumblr-logo:before { + content: "\e8d4"; + opacity: 0.2; +} +.ph-duotone.ph-tumblr-logo:after { + content: "\e8d5"; + margin-left: -1em; +} +.ph-duotone.ph-twitch-logo:before { + content: "\e5ce"; + opacity: 0.2; +} +.ph-duotone.ph-twitch-logo:after { + content: "\e5cf"; + margin-left: -1em; +} +.ph-duotone.ph-twitter-logo:before { + content: "\e4ba"; + opacity: 0.2; +} +.ph-duotone.ph-twitter-logo:after { + content: "\e4bb"; + margin-left: -1em; +} +.ph-duotone.ph-umbrella:before { + content: "\e684"; + opacity: 0.2; +} +.ph-duotone.ph-umbrella:after { + content: "\e685"; + margin-left: -1em; +} +.ph-duotone.ph-umbrella-simple:before { + content: "\e686"; + opacity: 0.2; +} +.ph-duotone.ph-umbrella-simple:after { + content: "\e687"; + margin-left: -1em; +} +.ph-duotone.ph-union:before { + content: "\edbe"; + opacity: 0.2; +} +.ph-duotone.ph-union:after { + content: "\edbf"; + margin-left: -1em; +} +.ph-duotone.ph-unite:before { + content: "\e87e"; + opacity: 0.2; +} +.ph-duotone.ph-unite:after { + content: "\e87f"; + margin-left: -1em; +} +.ph-duotone.ph-unite-square:before { + content: "\e878"; + opacity: 0.2; +} +.ph-duotone.ph-unite-square:after { + content: "\e879"; + margin-left: -1em; +} +.ph-duotone.ph-upload:before { + content: "\e4be"; + opacity: 0.2; +} +.ph-duotone.ph-upload:after { + content: "\e4bf"; + margin-left: -1em; +} +.ph-duotone.ph-upload-simple:before { + content: "\e4c0"; + opacity: 0.2; +} +.ph-duotone.ph-upload-simple:after { + content: "\e4c1"; + margin-left: -1em; +} +.ph-duotone.ph-usb:before { + content: "\e956"; + opacity: 0.2; +} +.ph-duotone.ph-usb:after { + content: "\e957"; + margin-left: -1em; +} +.ph-duotone.ph-user:before { + content: "\e4c2"; + opacity: 0.2; +} +.ph-duotone.ph-user:after { + content: "\e4c3"; + margin-left: -1em; +} +.ph-duotone.ph-user-check:before { + content: "\eafa"; + opacity: 0.2; +} +.ph-duotone.ph-user-check:after { + content: "\eafb"; + margin-left: -1em; +} +.ph-duotone.ph-user-circle:before { + content: "\e4c4"; + opacity: 0.2; +} +.ph-duotone.ph-user-circle:after { + content: "\e4c5"; + margin-left: -1em; +} +.ph-duotone.ph-user-circle-check:before { + content: "\ec38"; + opacity: 0.2; +} +.ph-duotone.ph-user-circle-check:after { + content: "\ec39"; + margin-left: -1em; +} +.ph-duotone.ph-user-circle-dashed:before { + content: "\ec36"; + opacity: 0.2; +} +.ph-duotone.ph-user-circle-dashed:after { + content: "\ec37"; + margin-left: -1em; +} +.ph-duotone.ph-user-circle-gear:before { + content: "\e4c6"; + opacity: 0.2; +} +.ph-duotone.ph-user-circle-gear:after { + content: "\e4c7"; + margin-left: -1em; +} +.ph-duotone.ph-user-circle-minus:before { + content: "\e4c8"; + opacity: 0.2; +} +.ph-duotone.ph-user-circle-minus:after { + content: "\e4c9"; + margin-left: -1em; +} +.ph-duotone.ph-user-circle-plus:before { + content: "\e4ca"; + opacity: 0.2; +} +.ph-duotone.ph-user-circle-plus:after { + content: "\e4cb"; + margin-left: -1em; +} +.ph-duotone.ph-user-focus:before { + content: "\e6fc"; + opacity: 0.2; +} +.ph-duotone.ph-user-focus:after { + content: "\e6fd"; + margin-left: -1em; +} +.ph-duotone.ph-user-gear:before { + content: "\e4cc"; + opacity: 0.2; +} +.ph-duotone.ph-user-gear:after { + content: "\e4cd"; + margin-left: -1em; +} +.ph-duotone.ph-user-list:before { + content: "\e73c"; + opacity: 0.2; +} +.ph-duotone.ph-user-list:after { + content: "\e73d"; + margin-left: -1em; +} +.ph-duotone.ph-user-minus:before { + content: "\e4ce"; + opacity: 0.2; +} +.ph-duotone.ph-user-minus:after { + content: "\e4cf"; + margin-left: -1em; +} +.ph-duotone.ph-user-plus:before { + content: "\e4d0"; + opacity: 0.2; +} +.ph-duotone.ph-user-plus:after { + content: "\e4d1"; + margin-left: -1em; +} +.ph-duotone.ph-user-rectangle:before { + content: "\e4d2"; + opacity: 0.2; +} +.ph-duotone.ph-user-rectangle:after { + content: "\e4d3"; + margin-left: -1em; +} +.ph-duotone.ph-user-sound:before { + content: "\eca8"; + opacity: 0.2; +} +.ph-duotone.ph-user-sound:after { + content: "\eca9"; + margin-left: -1em; +} +.ph-duotone.ph-user-square:before { + content: "\e4d4"; + opacity: 0.2; +} +.ph-duotone.ph-user-square:after { + content: "\e4d5"; + margin-left: -1em; +} +.ph-duotone.ph-user-switch:before { + content: "\e756"; + opacity: 0.2; +} +.ph-duotone.ph-user-switch:after { + content: "\e757"; + margin-left: -1em; +} +.ph-duotone.ph-users:before { + content: "\e4d6"; + opacity: 0.2; +} +.ph-duotone.ph-users:after { + content: "\e4d7"; + margin-left: -1em; +} +.ph-duotone.ph-users-four:before { + content: "\e68c"; + opacity: 0.2; +} +.ph-duotone.ph-users-four:after { + content: "\e68d"; + margin-left: -1em; +} +.ph-duotone.ph-users-three:before { + content: "\e68e"; + opacity: 0.2; +} +.ph-duotone.ph-users-three:after { + content: "\e68f"; + margin-left: -1em; +} +.ph-duotone.ph-van:before { + content: "\e826"; + opacity: 0.2; +} +.ph-duotone.ph-van:after { + content: "\e827"; + margin-left: -1em; +} +.ph-duotone.ph-vault:before { + content: "\e76e"; + opacity: 0.2; +} +.ph-duotone.ph-vault:after { + content: "\e76f"; + margin-left: -1em; +} +.ph-duotone.ph-vector-three:before { + content: "\ee62"; + opacity: 0.2; +} +.ph-duotone.ph-vector-three:after { + content: "\ee63"; + margin-left: -1em; +} +.ph-duotone.ph-vector-two:before { + content: "\ee64"; + opacity: 0.2; +} +.ph-duotone.ph-vector-two:after { + content: "\ee65"; + margin-left: -1em; +} +.ph-duotone.ph-vibrate:before { + content: "\e4d8"; + opacity: 0.2; +} +.ph-duotone.ph-vibrate:after { + content: "\e4d9"; + margin-left: -1em; +} +.ph-duotone.ph-video:before { + content: "\e740"; + opacity: 0.2; +} +.ph-duotone.ph-video:after { + content: "\e741"; + margin-left: -1em; +} +.ph-duotone.ph-video-camera:before { + content: "\e4da"; + opacity: 0.2; +} +.ph-duotone.ph-video-camera:after { + content: "\e4db"; + margin-left: -1em; +} +.ph-duotone.ph-video-camera-slash:before { + content: "\e4dc"; + opacity: 0.2; +} +.ph-duotone.ph-video-camera-slash:after { + content: "\e4dd"; + margin-left: -1em; +} +.ph-duotone.ph-video-conference:before { + content: "\edce"; + opacity: 0.2; +} +.ph-duotone.ph-video-conference:after { + content: "\edcf"; + margin-left: -1em; +} +.ph-duotone.ph-vignette:before { + content: "\eba2"; + opacity: 0.2; +} +.ph-duotone.ph-vignette:after { + content: "\eba3"; + margin-left: -1em; +} +.ph-duotone.ph-vinyl-record:before { + content: "\ecac"; + opacity: 0.2; +} +.ph-duotone.ph-vinyl-record:after { + content: "\ecad"; + margin-left: -1em; +} +.ph-duotone.ph-virtual-reality:before { + content: "\e7b8"; + opacity: 0.2; +} +.ph-duotone.ph-virtual-reality:after { + content: "\e7b9"; + margin-left: -1em; +} +.ph-duotone.ph-virus:before { + content: "\e7d6"; + opacity: 0.2; +} +.ph-duotone.ph-virus:after { + content: "\e7d7"; + margin-left: -1em; +} +.ph-duotone.ph-visor:before { + content: "\ee2a"; + opacity: 0.2; +} +.ph-duotone.ph-visor:after { + content: "\ee2b"; + margin-left: -1em; +} +.ph-duotone.ph-voicemail:before { + content: "\e4de"; + opacity: 0.2; +} +.ph-duotone.ph-voicemail:after { + content: "\e4df"; + margin-left: -1em; +} +.ph-duotone.ph-volleyball:before { + content: "\e726"; + opacity: 0.2; +} +.ph-duotone.ph-volleyball:after { + content: "\e727"; + margin-left: -1em; +} +.ph-duotone.ph-wall:before { + content: "\e688"; + opacity: 0.2; +} +.ph-duotone.ph-wall:after { + content: "\e689"; + margin-left: -1em; +} +.ph-duotone.ph-wallet:before { + content: "\e68a"; + opacity: 0.2; +} +.ph-duotone.ph-wallet:after { + content: "\e68b"; + margin-left: -1em; +} +.ph-duotone.ph-warehouse:before { + content: "\ecd4"; + opacity: 0.2; +} +.ph-duotone.ph-warehouse:after { + content: "\ecd5"; + margin-left: -1em; +} +.ph-duotone.ph-warning:before { + content: "\e4e0"; + opacity: 0.2; +} +.ph-duotone.ph-warning:after { + content: "\e4e1"; + margin-left: -1em; +} +.ph-duotone.ph-warning-circle:before { + content: "\e4e2"; + opacity: 0.2; +} +.ph-duotone.ph-warning-circle:after { + content: "\e4e3"; + margin-left: -1em; +} +.ph-duotone.ph-warning-diamond:before { + content: "\e7fc"; + opacity: 0.2; +} +.ph-duotone.ph-warning-diamond:after { + content: "\e7fd"; + margin-left: -1em; +} +.ph-duotone.ph-warning-octagon:before { + content: "\e4e4"; + opacity: 0.2; +} +.ph-duotone.ph-warning-octagon:after { + content: "\e4e5"; + margin-left: -1em; +} +.ph-duotone.ph-washing-machine:before { + content: "\ede8"; + opacity: 0.2; +} +.ph-duotone.ph-washing-machine:after { + content: "\ede9"; + margin-left: -1em; +} +.ph-duotone.ph-watch:before { + content: "\e4e6"; + opacity: 0.2; +} +.ph-duotone.ph-watch:after { + content: "\e4e7"; + margin-left: -1em; +} +.ph-duotone.ph-wave-sawtooth:before { + content: "\ea9c"; + opacity: 0.2; +} +.ph-duotone.ph-wave-sawtooth:after { + content: "\ea9d"; + margin-left: -1em; +} +.ph-duotone.ph-wave-sine:before { + content: "\ea9a"; + opacity: 0.2; +} +.ph-duotone.ph-wave-sine:after { + content: "\ea9b"; + margin-left: -1em; +} +.ph-duotone.ph-wave-square:before { + content: "\ea9e"; + opacity: 0.2; +} +.ph-duotone.ph-wave-square:after { + content: "\ea9f"; + margin-left: -1em; +} +.ph-duotone.ph-wave-triangle:before { + content: "\eaa0"; + opacity: 0.2; +} +.ph-duotone.ph-wave-triangle:after { + content: "\eaa1"; + margin-left: -1em; +} +.ph-duotone.ph-waveform:before { + content: "\e802"; + opacity: 0.2; +} +.ph-duotone.ph-waveform:after { + content: "\e803"; + margin-left: -1em; +} +.ph-duotone.ph-waveform-slash:before { + content: "\e800"; + opacity: 0.2; +} +.ph-duotone.ph-waveform-slash:after { + content: "\e801"; + margin-left: -1em; +} +.ph-duotone.ph-waves:before { + content: "\e6de"; + opacity: 0.2; +} +.ph-duotone.ph-waves:after { + content: "\e6df"; + margin-left: -1em; +} +.ph-duotone.ph-webcam:before { + content: "\e9b2"; + opacity: 0.2; +} +.ph-duotone.ph-webcam:after { + content: "\e9b3"; + margin-left: -1em; +} +.ph-duotone.ph-webcam-slash:before { + content: "\ecdc"; + opacity: 0.2; +} +.ph-duotone.ph-webcam-slash:after { + content: "\ecdd"; + margin-left: -1em; +} +.ph-duotone.ph-webhooks-logo:before { + content: "\ecae"; + opacity: 0.2; +} +.ph-duotone.ph-webhooks-logo:after { + content: "\ecaf"; + margin-left: -1em; +} +.ph-duotone.ph-wechat-logo:before { + content: "\e8d2"; + opacity: 0.2; +} +.ph-duotone.ph-wechat-logo:after { + content: "\e8d3"; + margin-left: -1em; +} +.ph-duotone.ph-whatsapp-logo:before { + content: "\e5d0"; + opacity: 0.2; +} +.ph-duotone.ph-whatsapp-logo:after { + content: "\e5d1"; + margin-left: -1em; +} +.ph-duotone.ph-wheelchair:before { + content: "\e4e8"; + opacity: 0.2; +} +.ph-duotone.ph-wheelchair:after { + content: "\e4e9"; + margin-left: -1em; +} +.ph-duotone.ph-wheelchair-motion:before { + content: "\e89a"; + opacity: 0.2; +} +.ph-duotone.ph-wheelchair-motion:after { + content: "\e89b"; + margin-left: -1em; +} +.ph-duotone.ph-wifi-high:before { + content: "\e4ea"; + opacity: 0.2; +} +.ph-duotone.ph-wifi-high:after { + content: "\e4eb"; + margin-left: -1em; +} +.ph-duotone.ph-wifi-low:before { + content: "\e4ec"; + opacity: 0.2; +} +.ph-duotone.ph-wifi-low:after { + content: "\e4ed"; + margin-left: -1em; +} +.ph-duotone.ph-wifi-medium:before { + content: "\e4ee"; + opacity: 0.2; +} +.ph-duotone.ph-wifi-medium:after { + content: "\e4ef"; + margin-left: -1em; +} +.ph-duotone.ph-wifi-none:before { + content: "\e4f0"; + color: #444; +} +.ph-duotone.ph-wifi-slash:before { + content: "\e4f2"; + opacity: 0.2; +} +.ph-duotone.ph-wifi-slash:after { + content: "\e4f3"; + margin-left: -1em; +} +.ph-duotone.ph-wifi-x:before { + content: "\e4f4"; + opacity: 0.2; +} +.ph-duotone.ph-wifi-x:after { + content: "\e4f5"; + margin-left: -1em; +} +.ph-duotone.ph-wind:before { + content: "\e5d2"; + opacity: 0.2; +} +.ph-duotone.ph-wind:after { + content: "\e5d3"; + margin-left: -1em; +} +.ph-duotone.ph-windmill:before { + content: "\e9f8"; + opacity: 0.2; +} +.ph-duotone.ph-windmill:after { + content: "\e9f9"; + margin-left: -1em; +} +.ph-duotone.ph-windows-logo:before { + content: "\e692"; + opacity: 0.2; +} +.ph-duotone.ph-windows-logo:after { + content: "\e693"; + margin-left: -1em; +} +.ph-duotone.ph-wine:before { + content: "\e6b2"; + opacity: 0.2; +} +.ph-duotone.ph-wine:after { + content: "\e6b3"; + margin-left: -1em; +} +.ph-duotone.ph-wrench:before { + content: "\e5d4"; + opacity: 0.2; +} +.ph-duotone.ph-wrench:after { + content: "\e5d5"; + margin-left: -1em; +} +.ph-duotone.ph-x:before { + content: "\e4f6"; + opacity: 0.2; +} +.ph-duotone.ph-x:after { + content: "\e4f7"; + margin-left: -1em; +} +.ph-duotone.ph-x-circle:before { + content: "\e4f8"; + opacity: 0.2; +} +.ph-duotone.ph-x-circle:after { + content: "\e4f9"; + margin-left: -1em; +} +.ph-duotone.ph-x-logo:before { + content: "\e4bc"; + opacity: 0.2; +} +.ph-duotone.ph-x-logo:after { + content: "\e4bd"; + margin-left: -1em; +} +.ph-duotone.ph-x-square:before { + content: "\e4fa"; + opacity: 0.2; +} +.ph-duotone.ph-x-square:after { + content: "\e4fb"; + margin-left: -1em; +} +.ph-duotone.ph-yarn:before { + content: "\ed9a"; + opacity: 0.2; +} +.ph-duotone.ph-yarn:after { + content: "\ed9b"; + margin-left: -1em; +} +.ph-duotone.ph-yin-yang:before { + content: "\e92a"; + opacity: 0.2; +} +.ph-duotone.ph-yin-yang:after { + content: "\e92b"; + margin-left: -1em; +} +.ph-duotone.ph-youtube-logo:before { + content: "\e4fc"; + opacity: 0.2; +} +.ph-duotone.ph-youtube-logo:after { + content: "\e4fd"; + margin-left: -1em; +} diff --git a/website/res/img/aub_black.png b/website/res/img/aub_black.png new file mode 100644 index 0000000..a3619b4 --- /dev/null +++ b/website/res/img/aub_black.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f94491a606817d5ee98a9b01fbcea0e2b0ddadc6c724e78a35267c23392f7693 +size 316898 diff --git a/website/res/img/aub_red.png b/website/res/img/aub_red.png new file mode 100644 index 0000000..466f9ff --- /dev/null +++ b/website/res/img/aub_red.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:66cfad52eb159dfb92ad3e9604a8f7e9500cc760c9e516c239613ba257d67d3e +size 661137 diff --git a/website/res/img/aub_white.png b/website/res/img/aub_white.png new file mode 100644 index 0000000..771401c --- /dev/null +++ b/website/res/img/aub_white.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd772a786c217b34575c5822813cdf22aae0230f02608cb36bf21f78f6517d43 +size 390322 diff --git a/website/res/img/by-nc-sa.svg b/website/res/img/by-nc-sa.svg new file mode 100644 index 0000000..d38247c --- /dev/null +++ b/website/res/img/by-nc-sa.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae53a3cd58210ca72cf3243f983326d19183d774cfc030b2f76ee86a29fb3334 +size 11961 diff --git a/website/res/img/cedar.webp b/website/res/img/cedar.webp new file mode 100644 index 0000000..79f37ef --- /dev/null +++ b/website/res/img/cedar.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:180becff63c363dc8e28a4eb8c38a8f6a9b7833864891983d7844115c7725b1d +size 883630 diff --git a/website/res/img/favicon.png b/website/res/img/favicon.png new file mode 100644 index 0000000..e698f86 --- /dev/null +++ b/website/res/img/favicon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:905ee89747bf51c1d3c55169e75c3a65910c07fe9b3c56bde81bb82ea734f807 +size 158709 diff --git a/website/res/img/joy.webp b/website/res/img/joy.webp new file mode 100644 index 0000000..2defe92 --- /dev/null +++ b/website/res/img/joy.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4cf2c05e45e9b0fce0eaa131a37267656457aad20039d1706d58b86f6157ca98 +size 311342 diff --git a/website/res/img/og.jpg b/website/res/img/og.jpg new file mode 100644 index 0000000..644b48b --- /dev/null +++ b/website/res/img/og.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:603beeaf495175b06bee6d249fd47050e6931fcc69ae92b4e2848c03d61c1df8 +size 389666 diff --git a/website/res/img/try_again.gif b/website/res/img/try_again.gif new file mode 100644 index 0000000..998692f --- /dev/null +++ b/website/res/img/try_again.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a5dafaf888192de55f0a62132cb97196e15049c4b4c255f849de17569a914eb +size 528540 diff --git a/website/res/img/waiting.gif b/website/res/img/waiting.gif new file mode 100644 index 0000000..34be2af --- /dev/null +++ b/website/res/img/waiting.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65450b47249166f77d4e19c0b04fef77477793b980db4673cf8254bb1443e72c +size 4453 diff --git a/website/res/js/collapsible.js b/website/res/js/collapsible.js new file mode 100644 index 0000000..8aa62ab --- /dev/null +++ b/website/res/js/collapsible.js @@ -0,0 +1,8 @@ +const collapsibleInit = () => { + document.querySelectorAll(".collapsible-header").forEach((header) => { + header.addEventListener("click", () => { + header.classList.toggle("active"); + header.nextElementSibling.classList.toggle("active"); + }); + }); +}; \ No newline at end of file diff --git a/website/res/js/main.js b/website/res/js/main.js new file mode 100644 index 0000000..a2bad9d --- /dev/null +++ b/website/res/js/main.js @@ -0,0 +1,5 @@ +(() => { + menuInit(); + collapsibleInit(); + updatedInit(); +})(); \ No newline at end of file diff --git a/website/res/js/menu.js b/website/res/js/menu.js new file mode 100644 index 0000000..ecf54f1 --- /dev/null +++ b/website/res/js/menu.js @@ -0,0 +1,17 @@ +const menuInit = () => { + const mobileMenuToggle = document.querySelector(".mobile-menu-toggle"); + const navbarLinks = document.querySelector(".navbar-links"); + + mobileMenuToggle.addEventListener("click", () => { + mobileMenuToggle.classList.toggle("active"); + navbarLinks.classList.toggle("active"); + }); + + const navLinks = document.querySelectorAll(".navbar-links a"); + navLinks.forEach((link) => { + link.addEventListener("click", () => { + mobileMenuToggle.classList.remove("active"); + navbarLinks.classList.remove("active"); + }); + }); +}; \ No newline at end of file diff --git a/website/res/js/updated.js b/website/res/js/updated.js new file mode 100644 index 0000000..1a10c7a --- /dev/null +++ b/website/res/js/updated.js @@ -0,0 +1,39 @@ +const updatedInit = () => { + const lastUpdatedElement = document.getElementById("lastUpdated"); + const updatedLink = document.createElement("a"); + updatedLink.href = + "https://codeberg.org/nadimkobeissi/appliedcryptography/commits/branch/main"; + fetch( + "https://codeberg.org/api/v1/repos/nadimkobeissi/appliedcryptography/commits?limit=1&sha=main", + ) + .then((response) => response.json()) + .then((data) => { + if (Array.isArray(data) && data.length > 0) { + const latestCommitDate = new Date(data[0].commit.author.date); + const options = { + year: "numeric", + month: "long", + day: "numeric", + hour: "numeric", + minute: "numeric", + hour12: true, + }; + const formattedDate = latestCommitDate.toLocaleString( + undefined, + options, + ); + updatedLink.innerText = formattedDate; + lastUpdatedElement.innerHTML = ""; + lastUpdatedElement.appendChild(updatedLink); + const period = document.createElement("span"); + period.innerText = "."; + lastUpdatedElement.appendChild(period); + } + }) + .catch((error) => { + console.error("Error fetching commit data:", error); + updatedLink.innerText = "View history"; + lastUpdatedElement.innerHTML = ""; + lastUpdatedElement.appendChild(updatedLink); + }); +}; diff --git a/website/robots.txt b/website/robots.txt new file mode 100644 index 0000000..8f38b1e --- /dev/null +++ b/website/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Allow: / diff --git a/website/slides/.gitkeep b/website/slides/.gitkeep new file mode 100644 index 0000000..473a0f4