Przejdź do głównej treści

Kwantowa dystrybucja klucza

W tym module Qiskit in Classrooms uczniowie muszą mieć działające środowisko Python z zainstalowanymi następującymi pakietami:

  • qiskit w wersji 2.1.0 lub nowszej
  • qiskit-ibm-runtime w wersji 0.40.1 lub nowszej
  • qiskit-aer w wersji 0.17.0 lub nowszej
  • qiskit.visualization
  • numpy
  • pylatexenc

Aby skonfigurować i zainstalować powyższe pakiety, zapoznaj się z przewodnikiem Zainstaluj Qiskit. Aby uruchamiać zadania na prawdziwych komputerach kwantowych, uczniowie muszą założyć konto IBM Quantum®, wykonując kroki opisane w przewodniku Skonfiguruj swoje konto IBM Cloud.

Ten moduł był testowany i wykorzystał 5 sekund czasu QPU. To jedynie szacunek. Rzeczywiste użycie może się różnić.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer qiskit-ibm-runtime
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'

Obejrzyj prezentację modułu przygotowaną przez dr Katie McCormick poniżej lub kliknij tutaj, żeby obejrzeć ją na YouTube.


Wprowadzenie i motywacja

Istnieje nieskończenie wiele sposobów szyfrowania i deszyfrowania informacji, a dosłownie tysiące z nich zostały dokładnie zbadane. Tutaj ograniczymy się do bardzo wczesnej i bardzo prostej metody szyfrowania zwanej „prostym podstawieniem", aby skupić się na kwantowej części tego protokołu. Część kwantową można stosunkowo łatwo zaadaptować do wielu innych protokołów.

Proste podstawienie

Szyfrowanie przez proste podstawienie polega na zastępowaniu jednej litery lub cyfry inną, tak że istnieje odwzorowanie 1:1 liter i cyfr w wiadomości na litery i cyfry używane w zaszyfrowanej sekwencji. Popularnym przykładem są zagadki kryptogram lub cryptoquote, w których cytat lub fraza jest zaszyfrowana za pomocą prostego podstawienia, a gracz ma za zadanie ją odszyfrować. Są one łatwe do rozwiązania, jeśli są wystarczająco długie. Rozważ przykład:

R WVXRWVW GSZG R'W YVGGVI NZPV GSRH KIVGGB OLMT. GSZG DZB, KVLKOV DROO SZEV ZM VZHRVI GRNV HLOERMT RG. R SLKV R NZWV RG HRNKOV VMLFTS.

Osoby rozwiązujące takie zagadki ręcznie korzystają głównie ze znajomości struktury języka oryginalnej wiadomości. Na przykład w języku angielskim jedynymi jednoliiterowymi słowami, takimi jak zaszyfrowane „R", są „a" i „I". Podwojone litery zaszyfrowane np. w „KIVGGB" mogą przyjmować tylko określone wartości. Istnieją też subtelniejsze wskazówki, takie jak to, że najczęstszym słowem pasującym do wzorca „GSZG" jest „that". Osoby korzystające z kodu do rozwiązywania tego typu zagadek mają znacznie więcej możliwości, w tym po prostu przeglądanie możliwości, dopóki nie zostanie odzyskane angielskie słowo, i aktualizowanie wyników z zachowaniem tego słowa. Prostą, lecz skuteczną metodą jest częstotliwość liter, szczególnie gdy wiadomość jest wystarczająco długa, by stanowić reprezentatywną próbkę języka angielskiego.

Pytanie sprawdzające

Możesz spróbować samodzielnie odszyfrować ten tekst, choć nie jest to konieczne do zrozumienia pozostałej części modułu. Kliknij strzałkę poniżej, aby zobaczyć wiadomość.

Odpowiedź:

I decided that I'd better make this pretty long. That way, people will have an easier time solving it. I hope I made it simple enough.

Powyższy przykład jest powiązany z „kluczem" — odwzorowaniem zaszyfrowanych liter na odszyfrowane. W tym przypadku klucz wygląda następująco:

  • A (nieużywane, nazwijmy je Z)
  • B->Y
  • C (nieużywane, nazwijmy je X)
  • D->W
  • E->V
  • F->U
  • ...

I tak dalej. Mówiąc delikatnie, to nie jest dobry klucz. Klucze, w których zaszyfrowane i odszyfrowane litery są po prostu przesuniętymi wersjami alfabetu (np. A->B i B->C), nazywane są szyframi „Cezara".

Należy zauważyć, że takie szyfry są bardzo trudne do złamania, gdy są krótkie. Jeśli są bardzo krótkie, są wręcz nieokreślone. Rozważ:

URYYP

Istnieje wiele możliwych deszyfracji przy użyciu różnych kluczy: HELLO, PETTY, HAPPY, JIGGY, STOOL. Czy możesz wymyślić inne?

Jednak jeśli wyślesz wiele takich wiadomości, szyfrowanie w końcu zostanie złamane. Dlatego nie należy używać tego samego „klucza" zbyt często. Najlepiej używać danego podstawienia tylko raz — nie w jednej wiadomości, ale tylko dla jednego pojedynczego znaku! Oznacza to, że będziesz mieć oddzielny schemat szyfrowania lub klucz dla każdego znaku użytego w wiadomości, po kolei. Jeśli chcesz wysłać wiadomość do przyjaciela za pomocą tego systemu, ty i twój przyjaciel potrzebujecie kartki papieru (w dawnych czasach), na której zapisany jest ten ciągle zmieniający się klucz. Używacie jej tylko raz. To właśnie nazywamy „jednorazowym blokiem kluczowym" (one-time pad).

Jednorazowy blok kluczowy

Zobaczmy, jak to działa na przykładzie. Można to zrobić wyłącznie przy użyciu liter, ale zwyczajowo konwertuje się je na liczby, np. przypisując A=0, B=1, C=2…. Załóżmy, że jesteśmy przyjaciółmi zaangażowanymi w tajne działania i mamy wspólny blok kluczowy. W idealnym przypadku mielibyśmy wiele bloków, ale dzisiejszy wygląda tak:

EDGRPOJNCUWQZVMK…

Lub, przeliczone na liczby według pozycji w alfabecie:

4,3,6,17,15, 14, 9, 13, 2, 20, 22, 16, 25, 21, 12, 10…

Załóżmy, że chcę przekazać tobie wiadomość:

„I love quantum!"

Lub równoważnie:

8, 11, 14, 21, 4, 16, 20, 0, 13, 19, 20, 12

Nie chcemy wysyłać powyższego kodu wprost — to proste podstawienie, które jest zupełnie niezabezpieczone. Chcemy połączyć go z naszym kluczem w pewien sposób. Popularnym sposobem jest dodawanie modulo 26. Dodajemy wartość wiadomości do wartości klucza mod 26, aż osiągniemy koniec wiadomości. Wyślemy więc:

8+4 (mod 26) = 12, 11+3 (mod 26) = 14, 14+6 (mod 26) = 20, 21+17 (mod 26) = 12…

= 12, 14, 20, 12, 19, 4, 3, 13, 15, 13, 16, 2

Zauważ, że jeśli ktoś to przechwyci i NIE ma klucza, odszyfrowanie jest zupełnie beznadziejne! Nawet dwie litery „u" w słowie „quantum" nie są zakodowane tą samą liczbą! Pierwsza to 3, a druga to 16… w tym samym słowie!

Wysyłam ci więc ten ciąg, a ty masz ten sam klucz co ja. Cofasz dodawanie modulo 26, o którym wiesz, że je wykonałem:

12, 14, 20, 12, 19, 4, 3, 13, 15, 13, 16, 2

=(4+x1) (mod 26), (3+x2) (mod 26), (6+x3) (mod 26), (17+x4) (mod 26),…

Tak że wiadomość x1, x2, x3, x4… musi wynosić

8, 11, 14, 21…

Na koniec, po konwersji na tekst, otrzymujesz:

„I love quantum".

To jest właśnie jednorazowy blok kluczowy.

Zauważ, że jeśli klucz jest krótszy niż wiadomość, zaczynamy powtarzać nasze kodowanie. To nadal byłoby trudne do odszyfrowania, ale nie niemożliwe, jeśli powtarza się wystarczająco wiele razy. Potrzebujesz więc długiego klucza (lub „bloku").

uwaga

W wielu przypadkach uczniowie będą już zaznajomieni z tym szyfrowaniem, w związku z czym to ćwiczenie można pominąć. Jest to jednak stosunkowo szybkie i proste przypomnienie.

Krok 1: Dobierz się w pary i uzgodnijcie z partnerem sekwencję 4 liter jako klucz. Wystarczy dowolna, odpowiednia do zajęć sekwencja 4 liter.
Krok 2: Wybierz tajne 4-literowe słowo, które chcesz wysłać partnerowi (oboje to robicie, więc wysyłacie sobie nawzajem różne tajne słowa).
Krok 3: Zamień 4-literowy klucz/blok oraz każde z 4-literowych tajnych słów na liczby, używając A = 1, B = 2 itd.
Krok 4: Połącz swoje 4-literowe słowo z jednorazowym blokiem kluczowym za pomocą dodawania modulo 26.
Krok 5: Przekaż partnerowi sekwencję liczb kodujących twoje tajne słowo, a partner przekaże tobie swoją.
Krok 6: Odszyfrujcie nawzajem swoje słowa za pomocą odejmowania modulo 26.
Krok 7: Zweryfikuj. Czy zadziałało?

Pytanie uzupełniające

Wymień zaszyfrowane słowa z inną grupą, która nie ma dostępu do twojego jednorazowego bloku kluczowego. Czy możesz je odszyfrować? Wyjaśnij dlaczego lub dlaczego nie?

Mam nadzieję, że powyższe ćwiczenie jasno pokazuje, że jednorazowy blok kluczowy jest niezłamalną formą szyfrowania, przy kilku założeniach:

  • Klucz ma taką samą długość jak szyfrowana wiadomość lub jest dłuższy
  • Klucz jest naprawdę losowy
  • Klucz jest używany tylko raz, a następnie niszczony

To brzmi świetnie. Mamy niezłamalne szyfrowanie… chyba że ktoś zdobędzie nasz klucz. Jeśli ktoś zdobędzie nasz klucz, wszystko zostaje odszyfrowane. Ta różnica między niezłamalnym szyfrowaniem a ujawnieniem wszystkich naszych tajemnic sprawia, że udostępnianie bezpiecznego klucza jest niezwykle ważne. Celem kwantowej dystrybucji klucza jest wykorzystanie ograniczeń, jakie natura nakłada na informację kwantową, do zabezpieczenia współdzielonego klucza/jednorazowego bloku kluczowego.

Używanie stanów kwantowych jako klucza

Przyjmijmy, że pracujemy z qubitami (podkreślając, że qubity mają dwa stany własne). Można by użyć układów kwantowych z większą liczbą stanów, jednak najnowocześniejsze komputery kwantowe IBM® operują na qubitach. Kodowanie naszych liter A, B, C, … jako ciągów zer i jedynek nie stanowi żadnego problemu. Wystarczy więc, że wymienimy klucz złożony z zer i jedynek, a następnie będziemy wykonywać dodawanie modulo 2 na każdym bicie przechowującym literę.

Sprawdź swoje rozumienie

Przeczytaj poniższe pytanie, zastanów się nad odpowiedzią, a następnie kliknij trójkąt, aby zobaczyć rozwiązanie.

Jeśli zależy nam wyłącznie na literach angielskich, ile bitów potrzebujemy?

Odpowiedź:

24=1625=325 bits2^4=16\\ 2^5 = 32 \rightarrow 5 \text{ bits}

Nasi znajomi, Alicja i Bob, chcieliby wymienić klucz kwantowy w taki sposób, aby nikt inny nie mógł go przechwycić (a przynajmniej nie bez ich wiedzy). Muszą mieć możliwość przesyłania sobie nawzajem stanów kwantowych. Robienie tego z wysoką wiernością i bez szumów czy błędów NIE jest trywialne. Istnieją jednak dwa podejścia, które powinniśmy być w stanie zrozumieć na tym etapie:

  1. Kabel światłowodowy pozwala przesyłać światło… które jest bardzo kwantowomechaniczne. Pojedyncze fotony można wykrywać z dużą wiernością na odległości wielu kilometrów kabla światłowodowego. Nie jest to doskonały, bezbłędny kanał kwantowy, ale może być bardzo dobry.
  2. Można by skorzystać z teleportacji kwantowej opisanej w poprzednim module. Czyli Alicja i Bob mogliby współdzielić splątane qubity, a stan mógłby być przesłany od Alicji do Boba za pomocą protokołu teleportacji.

W tym module nie chcemy wymagać od ciebie zaawansowanych konfiguracji optycznych do przesyłania fotonów, dlatego skorzystamy z drugiej metody wymiany stanów kwantowych. Nie oznacza to jednak, że jest ona najbardziej realistyczna w przypadku wymiany kluczy kwantowych na duże odległości.

Zbadamy teraz protokół opracowany po raz pierwszy przez Charlesa Bennetta i Gillesa Brassarda w 1984 roku, służący do przesyłania stanów mierzonych w różnych bazach od Alicji do Boba. Użyjemy sprytnego schematu pomiarowego, aby zbudować klucz do późniejszego szyfrowania. Innymi słowy, dystrybuujemy klucz kwantowy między dwiema stronami, które chcą się komunikować — stąd nazwa „kwantowa dystrybucja klucza" (QKD, ang. quantum key distribution).

QKD krok 1: Losowe bity i losowe bazy Alicji

Alicja zaczyna od wygenerowania losowego ciągu zer i jedynek. Następnie losowo wybiera bazę, w której przygotuje stan kwantowy odpowiadający każdemu losowemu bitowi, korzystając z poniższej tabeli (którą posiada również Bob):

Bazabit = 0bit = 1
Z0\vert 0\rangle1\vert 1\rangle
X+\vert +\rangle\vert -\rangle

Na przykład, jeśli Alicja losowo wygenerowała 0 i losowo wybrała bazę X, przygotowałaby stan kwantowy ψ=+x=12(0+1)|\psi\rangle = |+\rangle_x = \frac{1}{\sqrt{2}}(|0\rangle+|1\rangle). Do wygenerowania losowego zestawu zer i jedynek oraz losowego wyboru bazy można oczywiście wykorzystać kwantową losowość. Na razie przyjmijmy po prostu, że taki losowy zestaw został wygenerowany w następujący sposób:

Bity Alicji010011010...
Bazy AlicjiXXZZZXZZX...
Stany Alicji+\vert +\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle1\vert 1\rangle\vert -\rangle0\vert 0\rangle1\vert 1\rangle+\vert +\rangle...

Ten zestaw losowych bitów, baz i wynikających z nich stanów byłby kontynuowany w długiej sekwencji, aby uzyskać klucz o odpowiedniej długości.

QKD krok 2: Losowe bazy Boba

Bob również losowo wybiera bazy. Jednak o ile Alicja używała wyboru bazy do przygotowania swojego stanu, Bob będzie faktycznie wykonywał pomiary w tych bazach. Jeśli Bob dokona pomiaru w tej samej bazie, w której Alicja przygotowała stan, możemy przewidzieć wynik pomiaru Boba. Gdy Bob przypadkowo wybierze inną bazę niż ta, której użyła Alicja przy przygotowaniu, nie możemy z góry znać wyniku pomiaru Boba.

Bity Alicji010011010...
Bazy AlicjiXXZZZXZZX...
Stany Alicji+\vert +\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle1\vert 1\rangle\vert -\rangle0\vert 0\rangle1\vert 1\rangle+\vert +\rangle...
Bazy BobaXZXZXXZXX...
Stany Boba (a priori)+\vert +\rangle??0\vert 0\rangle?\vert -\rangle0\vert 0\rangle?+\vert +\rangle...
Stany Boba (zmierzone)+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle\vert -\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...
Rozważmy pierwszą kolumnę poniższej tabeli. Alicja przygotowała stan +,\vert +\rangle, który jest stanem własnym bazy X. Ponieważ Bob również losowo wybrał pomiar w bazie X, istnieje tylko jeden możliwy wynik pomiaru Boba: +.\vert +\rangle. W drugiej kolumnie natomiast wybrali różne bazy. Stan wysłany przez Alicję to =12(01).\vert -\rangle = \frac{1}{\sqrt{2}}(\vert 0\rangle-\vert 1 \rangle). Ten stan zostanie zmierzony przez Boba jako 0\vert 0\rangle z prawdopodobieństwem 50% i jako 1\vert 1\rangle z prawdopodobieństwem 50%. Dlatego wiersza pokazującego to, co wiemy a priori o pomiarach Boba, nie można uzupełnić dla kolumny 2. Bob jednak dokona pomiaru i uzyska stan własny bazy Z (w tej kolumnie). W dolnym wierszu wpisujemy to, co te pomiary faktycznie dały.

QKD krok 3: Publiczna dyskusja o bazach

Alicja i Bob mogą teraz podzielić się ze sobą informacją o tym, jaką bazę wybrali w każdym przypadku. We wszystkich kolumnach, w których przypadkowo wybrali tę samą bazę, każde z nich wie z całą pewnością, w jakim stanie znajdował się drugi. Bob może przekształcić stan i bazę na 0 lub 1 zgodnie z konwencją uzgodnioną przez obie strony. Możemy przepisać powyższą tabelę, pokazując tylko przypadki, w których bazy Alicji i Boba były zgodne:

Bity Alicji00100...
Bazy AlicjiXZXZX...
Stany Alicji+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle...
Bazy BobaXZXZXX
Stany Boba (a priori)+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle...
Stany Boba (zmierzone)+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle...
Bity Boba00100...

Alicja z powodzeniem przesłała Bobowi ciąg bitów 00100…. Jeśli znajomi wcześniej uzgodnili, że używają 5-bitowych ciągów jako liczb w swoim jednorazowym szyfratorze, pierwsze pięć bitów da im liczbę 4=0×24+0×23+1×22+0×21+0×20.4 = 0\times2^4+0\times2^3+1\times2^2+0\times2^1+0\times2^0.

QKD krok 4: Weryfikacja i przesłanie sekretu

Zanim Alicja i Bob pójdą dalej, powinni wybrać podzbiór swoich klasycznych bitów do porównania. Ponieważ zachowali jedynie pomiary qubitów przygotowanych i zmierzonych w tej samej bazie, wszystkie zmierzone wartości powinny być zgodne. Jeśli bardzo mały odsetek nie byłby zgodny, można by to przypisać szumom kwantowym lub błędom. Lecz jeśli wiele wartości nie zgadza się — coś poszło nie tak!

W tym miejscu nie będziemy omawiać, jaka część klucza powinna zostać użyta do weryfikacji. Na razie założymy, że ta kontrola przebiega pomyślnie; wrócimy do tego w poniższej sekcji poświęconej podsłuchiwaniu.

Znajomi przesłaliby sobie następnie zaszyfrowaną wiadomość kanałami klasycznymi. Używaliby liczb ze swojego jednorazowego szyfratora do szyfrowania i odszyfrowywania tajnych wiadomości, nigdy nie przesyłając samego jednorazowego szyfratora z jednego miejsca do drugiego. W następnej sekcji dotyczącej podsłuchiwania pamiętaj, że cała ta wymiana klucza odbywa się przed ujawnieniem zaszyfrowanego sekretu kanałami klasycznymi.

Alicja i Bob przekazali sobie wybraną bazę pomiaru kanałami klasycznymi — czy więc ta informacja mogła zostać przechwycona? Tak! Jednak znajomość bazy użytej do pomiaru nie mówi ci, jaki bit został wysłany ani uzyskany. Jest to możliwe tylko wtedy, gdy znasz też początkowe bity Alicji. W takim razie byłbyś już w komputerze Alicji, gdzie przechowywane są sekrety, a bezpieczna komunikacja sekretów traci sens. Przechwycenie komunikacji klasycznej nie łamie więc szyfrowania. Ale co z przechwyceniem informacji w kanale kwantowym?

Odporność QKD na podsłuch

Alice i Bob mają przyjaciółkę Eve, która słynie z podsłuchiwania. Eve chce przechwycić klucz kwantowy Alice i Boba, aby móc wykorzystać go do odszyfrowania wiadomości przesyłanych między nimi. Musiałoby to nastąpić pomiędzy przygotowaniem stanów przez Alice a ich pomiarem przez Boba, ponieważ pomiar powoduje kolaps stanu kwantowego. W szczególności oznacza to, że podsłuch musiałby nastąpić przed jakimkolwiek udostępnieniem lub porównaniem baz.

Eve musi zgadywać, w jakiej bazie zakodowano każdy bit. Jeśli nie ma dostępu do komputera Alice, nie ma żadnej podstawy do tego zgadywania i będzie ono losowe. Przyjmijmy, że punkt startowy Alice jest taki sam jak poprzednio, a losowy wybór bazy pomiarowej przez Boba również pozostaje bez zmian. Wypełnijmy tabelę wynikami uzyskanymi przez Eve, gdy dokonuje pomiarów w kanale kwantowym. Podobnie jak poprzednio, jeśli Eve trafi na tę samą bazę co Alice, wiemy, co uzyska. Jeśli nie, może uzyskać jeden z dwóch wyników, każdy z prawdopodobieństwem 50%.

Bity Alice010011010...
Bazy AliceXXZZZXZZX...
Stany Alice+\vert +\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle1\vert 1\rangle\vert -\rangle0\vert 0\rangle1\vert 1\rangle+\vert +\rangle...
Zgadywane bazy EveZXXZXZZXX...
Stany Eve (a priori)?\vert -\rangle?0\vert 0\rangle??0\vert 0\rangle?+\vert +\rangle...
Stany Eve (zmierzone)1\vert 1\rangle\vert -\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...
Bazy BobaXZXZXXZXX...

Ponieważ Eve nie wie, czy dopasowała bazę Alice, nie wie, co przesłać dalej do Boba, aby odtworzyć oryginalne stany Alice. Gdy Eve zmierzy na przykład 0,|0\rangle, wie jedynie na pewno, że Alice nie przygotowała stanu 1|1\rangle dla tego Qubitu. Ale Alice mogła przygotować 0,|0\rangle, +|+\rangle lub .|-\rangle. Wszystkie te stany mogą być spójne z pomiarem Eve. Dlatego Eve musi dokonać wyboru. Może przesłać dalej dokładnie ten stan, który zmierzyła, albo może próbować odgadnąć przypadki, w których jej pomiar nie był stanem własnym wysłanym przez Alice. W tabeli uwzględnimy mieszankę obu podejść:

Bity Alice010011010...
Bazy AliceXXZZZXZZX...
Stany Alice+\vert +\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle1\vert 1\rangle\vert -\rangle0\vert 0\rangle1\vert 1\rangle+\vert +\rangle...
Zgadywane bazy EveZXXZXZZXX...
Stany Eve (a priori)?\vert -\rangle?0\vert 0\rangle??0\vert 0\rangle?+\vert +\rangle...
Stany Eve (zmierzone)1\vert 1\rangle\vert -\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...
Stany Eve (przesłane dalej)1\vert 1\rangle0\vert 0\rangle1\vert 1\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle...
Bazy BobaXZXZXXZXX...
Stany Boba (a priori)?0\vert 0\rangle?0\vert 0\rangle\vert -\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...
Stany Boba (zmierzone)\vert -\rangle0\vert 0\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...
Bity Boba100010010...

W tym miejscu warto zadać pytanie: „Dlaczego Eve nie zrobi po prostu kopii stanu kwantowego Alice, zatrzyma jedną dla siebie do pomiaru, a drugą prześle dalej do Boba?" Odpowiedź daje twierdzenie o zakazie klonowania. Mówiąc nieformalnie, stwierdza ono, że nie istnieje żadna unitarna (kwantowomechaniczna) operacja, która mogłaby stworzyć drugą kopię dowolnego stanu kwantowego, zachowując jednocześnie kopię pierwotną. Dowód jest stosunkowo prosty i pozostawiamy go jako ćwiczenie prowadzone krok po kroku. Na razie przyjmijmy, że kopiowanie stanu kwantowego przez Eve jest zabronione przez fundamentalne prawa przyrody i stanowi to jedną z głównych zalet QKD. Podobnie jak poprzednio, Alice i Bob zadzwonią do siebie i porównają bazy. Zredukują tę tabelę do przypadków, w których oboje wybrali te same bazy:

Bity Alice00100...
Bazy AliceXZXZX...
Stany Alice+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle...
Zgadywane bazy EveZZZZX...
Stany Eve (a priori)?0\vert 0\rangle?0\vert 0\rangle+\vert +\rangle...
Stany Eve (zmierzone)1\vert 1\rangle0\vert 0\rangle0\vert 0\rangle0\vert 0\rangle+\vert +\rangle...
Stany Eve (przesłane dalej)1\vert 1\rangle0\vert 0\rangle+\vert +\rangle0\vert 0\rangle0\vert 0\rangle...
Bazy BobaXZXZX...
Stany Boba (a priori)?0\vert 0\rangle+\vert +\rangle0\vert 0\rangle+\vert +\rangle...
Stany Boba (zmierzone)\vert -\rangle0\vert 0\rangle+\vert +\rangle0\vert 0\rangle+\vert +\rangle...
Bity Boba10000...

Alice i Bob ponownie przekazali sobie ciąg bitów... ale ciągi te nie są zgodne. Skrajnie lewy i środkowy bit są odwrócone. Patrząc na poprzednią tabelę, można prześledzić tę niezgodność i przypisać ją ingerencji Eve. Co istotne, możemy teraz przeprowadzić statystykę dopasowania między naszymi ciągami bitów na etapie tworzenia klucza, na długo przed ujawnieniem zaszyfrowanego sekretu. Alice i Bob mogą wykorzystać tyle bitów swojego jednorazowego bloku, ile chcą, do sprawdzenia bezpieczeństwa kanału. Jeśli tylko jeden bit lub bardzo mały odsetek bitów nie pasuje, można to przypisać szumowi lub błędom. Jednak znaczna frakcja niezgodności wskazuje na podsłuch. To, co uznaje się za „znaczną" frakcję, zależy nieco od szumów w używanej konfiguracji; co oznacza to dla komputerów kwantowych IBM®, omówiono poniżej przy implementacji tego protokołu. Jeśli wykryto nadmierne błędy, Alice i Bob nie ujawniają sekretu i mogą rozpocząć poszukiwania podsłuchującego.

Zastrzeżenia

Udowodnienie bezpieczeństwa jest niezwykle trudne. Protokół opisany tu ogólnie zaproponowano w 1984 roku, a jego bezpieczeństwo udowodniono dopiero 16 lat później Shor & Preskill, 2000. Istnieje wiele subtelności wykraczających poza zakres tego wprowadzenia. Wymienimy jednak kilka z nich, aby pokazać, że temat jest bardziej złożony, niż przedstawiono to tutaj.

  • Bezpieczne kanały: Gdy Alice wysyła swoje Qubity przez jakąś konfigurację kwantową (kanał), a w szczególności gdy otrzymuje klasyczne odpowiedzi od kogoś, zakładaliśmy, że tym kimś jest rzeczywiście Bob. Gdyby Eve zinfiltrował tę konfigurację w taki sposób, że cała komunikacja Alice odbywała się faktycznie z Eve, a cała komunikacja Boba była faktycznie prowadzona przez Eve, wówczas Eve skutecznie uzyskałaby klucz i mogłaby poznawać sekrety. Należy najpierw zapewnić „bezpieczne kanały" — proces oparty na odrębnym zestawie protokołów, których tutaj nie omawiamy.
  • Założenia dotyczące Eve: Aby naprawdę udowodnić bezpieczeństwo, nie możemy czynić założeń co do zachowania Eve; zawsze mogłaby ona pokrzyżować nasze oczekiwania. Tutaj, podając konkretne przykłady, czynimy założenia. Możemy na przykład zakładać, że stany przesyłane przez Eve do Boba są zawsze dokładnie tymi, które uzyskała przy pomiarze. Albo możemy zakładać, że losowo wybiera stan eksperymentalnie spójny z jej pomiarem. Mówiąc bardziej fundamentalnie, język stosowany tutaj zakłada, że Eve faktycznie dokonuje pomiaru, a nie przechowuje stan w innym układzie kwantowym i przesyła losowy Qubit do Boba. Założenia te są w porządku dla zrozumienia protokołu, ale oznaczają, że nie dowodzimy niczego w pełnej ogólności.
  • Wzmocnienie prywatności: Alice i Bob nie muszą używać klucza kwantowego dokładnie w takiej postaci, w jakiej został przesłany. Mogą na przykład zastosować funkcję skrótu do wspólnego klucza. Pozwoliłoby to wykorzystać fakt, że podsłuchujący ma niepełną wiedzę na temat klucza, w celu uzyskania krótszego, ale bezpiecznego, wspólnego klucza.

Eksperyment 1: QKD bez podsłuchującego

Zaimplementujmy powyższy protokół przy braku podsłuchującego. Zrobimy to najpierw przy użyciu symulatora, żeby po prostu zrozumieć cały przepływ pracy.

Najpierw kilka słów o symulatorach kwantowych: większości komputerów nie da się symulować problemów kwantowych obejmujących więcej niż ~30 qubitów. Żaden klasyczny komputer, superkomputer ani GPU nie jest w stanie zasymulować pełnego zakresu zachowań 127-qubitowego komputera kwantowego. Zazwyczaj motywacją do korzystania z prawdziwych komputerów kwantowych jest to, że wielu splątanych qubitów nie można zasymulować. W tym przypadku nie ma splątania qubitów, chyba że do przesyłania informacji użyjemy schematu teleportacji. Tutaj motywacja do korzystania z prawdziwych komputerów kwantowych jest inna: chodzi o twierdzenie o zakazie klonowania. Klasyczny komputer symulujący qubit mógłby wysyłać informacje o stanie kwantowym od Alicji do Boba, ale gdyby te klasyczne informacje zostały przechwycone, można by je łatwo powielić, a Ewa mogłaby zachować doskonałą kopię i wysłać drugą do Boba. Z prawdziwymi stanami kwantowymi nie jest to możliwe.

IBM Quantum zaleca podejście do problemów z obliczeniami kwantowymi przy użyciu struktury, którą nazywamy „wzorcami Qiskit" (Qiskit patterns). Składa się ona z następujących kroków:

  • Krok 1: Odwzoruj swój problem na obwód kwantowy
  • Krok 2: Zoptymalizuj swój obwód pod kątem uruchomienia na prawdziwym sprzęcie kwantowym
  • Krok 3: Wykonaj zadanie na komputerach kwantowych IBM przy użyciu prymitywów Runtime
  • Krok 4: Przetwórz wyniki końcowe

Wzorce Qiskit, krok 1: Odwzoruj swój problem na obwód kwantowy

W tym przypadku odwzorowanie naszego problemu na obwody kwantowe sprowadza się po prostu do przygotowania stanów Alicji, a następnie uwzględnienia pomiarów Boba. Zaczynamy od losowego wyboru bitu i losowego wyboru bazy.

# Qiskit patterns step 1: Map your problem to quantum circuit
# Import some generic packages

import numpy as np
from qiskit import QuantumCircuit

# Set up a random number generator and a quantum circuit. We choose to start with 20 bits, though any number <30 should be fine.

rng = np.random.default_rng()
bit_num = 20
qc = QuantumCircuit(bit_num, bit_num)

# QKD step 1: Random bits and bases for Alice
# generate Alice's random bits

abits = np.round(rng.random(bit_num))

# generate Alice's random measurement bases. Here we will associate a "0" with the Z basis, and a "1" with the X basis.

abase = np.round(rng.random(bit_num))

# Alice's state preparation. Check that this creates states according to table 1

for n in range(bit_num):
if abits[n] == 0:
if abase[n] == 1:
qc.h(n)
if abits[n] == 1:
if abase[n] == 0:
qc.x(n)
if abase[n] == 1:
qc.x(n)
qc.h(n)

qc.barrier()

# QKD step 2: Random bases for Bob
# generate Bob's random measurement bases.

bbase = np.round(rng.random(bit_num))

# Note that if Bob measures in Z no gates are necessary, since IBM Quantum computers measure in Z by default.
# If Bob measures in the X basis, we implement a hadamard gate qc.h to facilitate the measurement.

for m in range(bit_num):
if bbase[m] == 1:
qc.h(m)
qc.measure(m, m)

Zwizualizujmy bity, bazy i obwód. Zauważ, że czasem bazy się zgadzają, a czasem nie.

print("Alice's bits are ", abits)
print("Alice's bases are ", abase)
print("Bob's bases are ", bbase)
qc.draw("mpl")
Alice's bits are  [1. 1. 0. 1. 0. 1. 1. 0. 0. 1. 0. 0. 1. 0. 0. 0. 1. 0. 0. 0.]
Alice's bases are [0. 0. 0. 1. 1. 0. 0. 0. 0. 1. 1. 1. 1. 1. 0. 1. 1. 0. 1. 0.]
Bob's bases are [0. 1. 1. 0. 1. 0. 1. 1. 0. 0. 1. 1. 0. 0. 1. 0. 1. 1. 0. 0.]

Output of the previous code cell

Wzorce Qiskit, krok 2: Zoptymalizuj problem pod kątem wykonania kwantowego

Ten krok bierze operacje, które chcemy wykonać, i wyraża je w kategoriach funkcjonalności konkretnego komputera kwantowego. Odwzorowuje też nasz problem na układ komputera kwantowego.

Zaczniemy od załadowania kilku pakietów potrzebnych do komunikacji z komputerami kwantowymi IBM. Musimy też wybrać backend, na którym będziemy pracować. Możemy albo wybrać najmniej obciążony backend, albo wskazać konkretny backend, którego właściwości znamy. Choć za chwilę użyjemy symulatora, ważne jest, żeby korzystać z rozsądnego modelu szumu, i dobrze jest utrzymać przepływ pracy jak najbliżej tego, czego użyjemy później na prawdziwych komputerach kwantowych.

Poniżej znajdziesz kod do jednorazowego zapisania swoich danych uwierzytelniających. Pamiętaj, żeby po zapisaniu tych informacji do środowiska usunąć je z notatnika, by przypadkowo nie udostępnić danych uwierzytelniających razem z notatnikiem. Więcej wskazówek znajdziesz w przewodnikach Set up your IBM Cloud account i Initialize the service in an untrusted environment.

# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService

# Load the Qiskit Runtime service

# Syntax for first saving your token. Delete these lines after saving your credentials.
# QiskitRuntimeService.save_account(channel='ibm_quantum_platform', instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)
# service = QiskitRuntimeService(channel='ibm_quantum_platform')

# Load saved credentials
service = QiskitRuntimeService()

# Use the least busy backend, or uncomment the loading of a specific backend like "ibm_brisbane".
# backend = service.least_busy(operational=True, simulator=False, min_num_qubits = 127)
backend = service.backend("ibm_brisbane")
print(backend.name)
ibm_brisbane

Poniżej wybieramy symulator i model szumu.

# Load the backend sampler
from qiskit.primitives import BackendSamplerV2

# Load the Aer simulator and generate a noise model based on the currently-selected backend.
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel

# Load the qiskit runtime sampler
from qiskit_ibm_runtime import SamplerV2 as Sampler

noise_model = NoiseModel.from_backend(backend)

# Define a simulator using Aer, and use it in Sampler.
backend_sim = AerSimulator(noise_model=noise_model)
sampler_sim = BackendSamplerV2(backend=backend_sim)
# Qiskit patterns step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

Wzorce Qiskit, krok 3: Wykonanie

Użyj Samplera do uruchomienia zadania, podając obwód jako argument.

# This required 5 s to run on a Heron r2 processor on 10-28-24
sampler = Sampler(mode=backend)
job = sampler.run([qc_isa], shots=1)
# job = sampler_sim.run([qc], shots = 1)
counts = job.result()[0].data.c.get_counts()
countsint = job.result()[0].data.c.get_int_counts()

Wzorce Qiskit, krok 4: Przetwarzanie końcowe

Tutaj interpretujemy wyniki i wydobywamy przydatne informacje. Moglibyśmy spróbować zwizualizować dane wyjściowe naszego Samplera, ale użyliśmy go w niekonwencjonalny sposób. Zamiast wykonywać wiele pomiarów obwodu i budować statystyki stanów, wykonaliśmy tylko jeden pomiar (Boba). Każdy qubit ze stanem przygotowanym i zmierzonym w tej samej bazie powinien mieć deterministyczny wynik, więc wystarczy jeden pomiar. Te qubity, których stany zostały przygotowane i zmierzone w różnych bazach (co dawałoby probabilistyczne wyniki wymagające wielu pomiarów do interpretacji), nie zostaną użyte do zbudowania naszego jednorazowego klucza szyfrującego. Wyodrębnijmy listę wyników pomiarów z tego ciągu bitów. Pamiętaj, żeby odwrócić kolejność podczas porównywania z tablicą bitów Alicji użytą do wygenerowania obwodu.

# Get an array of bits

keys = counts.keys()
key = list(keys)[0]
bmeas = list(key)
bmeas_ints = []
for n in range(bit_num):
bmeas_ints.append(int(bmeas[n]))

# Reverse the order to match our input. See "little endian" notation.

bbits = bmeas_ints[::-1]

print(bbits)
[1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0]

Porównajmy losowo wybrane bazy pomiarowe Alicji i Boba. Był to krok 3 naszego protokołu QKD (publiczna dyskusja o bazach). Za każdym razem, gdy wybrali tę samą bazę dla danego qubitu, dodajemy bity powiązane z tym qubitem do listy bitów służących do generowania liczb w jednorazowym kluczu szyfrującym. Gdy bazy się nie zgadzają, wyniki są odrzucane. Sprawdźmy też, czy obie listy bitów się zgadzają, czy też wystąpiły jakieś straty spowodowane szumem lub innymi czynnikami.

# QKD step 3: Public discussion of bases

agoodbits = []
bgoodbits = []
match_count = 0
for n in range(bit_num):
# Check whether bases matched.
if abase[n] == bbase[n]:
agoodbits.append(int(abits[n]))
bgoodbits.append(bbits[n])
# If bits match when bases matched, increase count of matching bits
if int(abits[n]) == bbits[n]:
match_count += 1

print(agoodbits)
print(bgoodbits)
print("fidelity = ", match_count / len(agoodbits))
print("loss = ", 1 - match_count / len(agoodbits))
[1, 0, 1, 0, 0, 0, 1, 0]
[1, 0, 1, 0, 0, 0, 1, 0]
fidelity = 1.0
loss = 0.0

Alicja i Bob mają każde po liście bitów, które zgadzają się w 100%. Mogą ich użyć do generowania liczb w jednorazowym kluczu szyfrującym. Następnie mogą to zastosować w kroku 4 QKD: wysyłanie i odszyfrowywanie sekretu. Obecna tablica bitów jest zbyt krótka, żeby odszyfrować cokolwiek sensownego. Wrócimy do tego po uwzględnieniu podsłuchu.

Sprawdź swoje zrozumienie

Przeczytaj poniższe pytanie, zastanów się nad odpowiedzią, a następnie kliknij trójkąt, żeby poznać rozwiązanie.

Załóż, że potrzebujesz cyfr wystarczająco dużych, żeby umożliwić przesunięcie liter w angielskim alfabecie o pełną jego długość lub więcej, choć z pewnością istnieją inne schematy kodowania. (a) Jak długa (w literach) może być wiadomość, którą da się odszyfrować przy użyciu bitów z powyższego klucza? (b) Czy twoja odpowiedź musi być zgodna z odpowiedziami kolegów z klasy? Dlaczego tak lub dlaczego nie?

Odpowiedź:

(a) Odpowiedź zależy od tego, ile losowo wybranych baz Alicji i Boba się zgadza. Ponieważ dla każdego qubitu szansa na zgodność baz wynosi mniej więcej 50/50, spodziewamy się, że około 10 z naszych bitów będzie przydatnych. 9 lub 11 to zupełnie normalna wartość. Nawet 4 lub 15 nie wykracza poza granice możliwości. Do przesunięcia o liczbę większą lub równą długości angielskiego alfabetu potrzeba 5 bitów, co oznacza, że możesz zastosować przesunięcie do jednej litery na każde 5 posiadanych bitów. Jeśli Alicja i Bob mają co najmniej 5 wspólnych bitów, można zakodować jedną literę. Jeśli co najmniej 10 — dwie litery i tak dalej. (b) Nie musi się zgadzać, z powodów opisanych w (a).

Eksperyment 2: QKD z podsłuchującym

Zaimplementujemy dokładnie ten sam protokół co poprzednio. Tym razem wstawimy jednak dodatkowy zestaw pomiarów wykonywanych przez Eve — pomiędzy Alice a Bobem.

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister

# Qiskit patterns step 1: Mapping your problem to a quantum circuit
# QKD step 1: Random bits and bases for Alice

bit_num = 20
qr = QuantumRegister(bit_num, "q")
cr = ClassicalRegister(bit_num, "c")
qc = QuantumCircuit(qr, cr)

# Alice's random bits and bases, as before

abits = np.round(rng.random(bit_num))
abase = np.round(rng.random(bit_num))

# Alice's state preparation, as before

for n in range(bit_num):
if abits[n] == 0:
if abase[n] == 1:
qc.h(n)
if abits[n] == 1:
if abase[n] == 0:
qc.x(n)
if abase[n] == 1:
qc.x(n)
qc.h(n)

qc.barrier()

# Eavesdropping happens here!
# Generate Eve's random measurement bases

ebase = np.round(rng.random(bit_num))

for m in range(bit_num):
if ebase[m] == 1:
qc.h(m)
qc.measure(qr[m], cr[m])
# Qiskit patterns step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Qiskit patterns step 3: Execute
job = sampler_sim.run([qc_isa], shots=1)
counts = job.result()[0].data.c.get_counts()
countsint = job.result()[0].data.c.get_int_counts()

Krok 4 wzorca Qiskit patterns (przetwarzanie końcowe) jest w tym przypadku prosty. Nie ma potrzeby wizualizowania rozkładu pomiarów, bo wykonano tylko jeden pomiar. Eve ma następujące bity:

keys = counts.keys()
key = list(keys)[0]
emeas = list(key)
emeas_ints = []
for n in range(bit_num):
emeas_ints.append(int(emeas[n]))
ebits = emeas_ints[::-1]

print(ebits)
[0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1]

Teraz Eve musi odtworzyć stany, które prześle dalej do Boba. Jak opisano we wstępie, nie ma ona możliwości sprawdzenia, czy dobrze odgadła bazy kodowania, więc nie jest w stanie przygotować dokładnie takich samych stanów, jakie zostały wysłane. Mogłaby założyć, że za każdym razem wybrała właściwą bazę i zakodować to, co zmierzyła, albo też uznać, że wybrała bazę niepoprawnie i wybrać jeden z eigenstanów bazy przeciwnej. Dla uproszczenia przyjmujemy to pierwsze podejście. Realizujemy je, budując zupełnie nowy Circuit i ponownie przechodząc przez kolejne kroki wzorca Qiskit patterns.

from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

# Qiskit patterns step 1: Mapping your problem onto a quantum circuit
# QKD step 1: Eve uses her measurements to prepare best guess states to send on to Bob

qr = QuantumRegister(bit_num, "q")
cr = ClassicalRegister(bit_num, "c")
qc = QuantumCircuit(qr, cr)

# Eve's state preparation

for n in range(bit_num):
if ebits[n] == 0:
if ebase[n] == 1:
qc.h(n)
if ebits[n] == 1:
if ebase[n] == 0:
qc.x(n)
if ebase[n] == 1:
qc.x(n)
qc.h(n)

qc.barrier()

# QKD step 2: Random bases for Bob

bbase = np.round(rng.random(bit_num))

for m in range(bit_num):
if bbase[m] == 1:
qc.h(m)
qc.measure(qr[m], cr[m])

# Qiskit patterns step 2: Transpile

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

# Qiskit patterns step 3: Execute

job = sampler_sim.run([qc_isa], shots=1)
counts = job.result()[0].data.c.get_counts()
countsint = job.result()[0].data.c.get_int_counts()

# Qiskit patterns step 4: Post-processing

keys = counts.keys()
key = list(keys)[0]
bmeas = list(key)
bmeas_ints = []
for n in range(bit_num):
bmeas_ints.append(int(bmeas[n]))
bbits = bmeas_ints[::-1]

print(bbits)
[0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1]

Porównajmy teraz bity Alice i Boba:

agoodbits = []
bgoodbits = []
match_count = 0
for n in range(bit_num):
if abase[n] == bbase[n]:
agoodbits.append(int(abits[n]))
bgoodbits.append(bbits[n])
if int(abits[n]) == bbits[n]:
match_count += 1
print(agoodbits)
print(bgoodbits)
print("fidelity = ", match_count / len(agoodbits))
print("loss = ", 1 - match_count / len(agoodbits))
[1, 1, 0, 0, 0, 1, 1]
[1, 1, 0, 0, 0, 0, 1]
fidelity = 0.8571428571428571
loss = 0.1428571428571429

Poprzednio bity w kluczach Alice i Boba były ze sobą w pełni zgodne. Teraz, na skutek ingerencji Eve, widzimy, że bity Alice i Boba różnią się w 14% przypadków, w których powinny się zgadzać (bo Alice i Bob wybrali te same bazy). Alice i Bob powinni to z łatwością wykryć. Oparcie się jednak na takim odsetku błędów oznacza, że istnieje pewien próg szumu kwantowego, który można tolerować w kanale kwantowym.

Eksperyment 3: Porównanie QKD z podsłuchem i bez podsłuchu na prawdziwym komputerze kwantowym

Uruchommy teraz ten protokół na prawdziwym komputerze kwantowym. Dzięki temu możemy skorzystać z twierdzenia o nieklonowaniu. Jednocześnie prawdziwe komputery kwantowe są zaszumione i mają wyższe wskaźniki błędów niż komputery klasyczne. Porównajmy więc utratę wierności bitów klucza z podsłuchem i bez, aby upewnić się, że różnica jest wykrywalna przy użyciu prawdziwego komputera kwantowego. Zaczniemy od przypadku bez podsłuchu:

from qiskit_ibm_runtime import SamplerV2 as Sampler

# This calculation was run on an Eagle r3 processor on 11-7-24 and required 3 sec to run, with 127 qubits.
# Qiskit patterns step 1: Mapping your problem to a quantum circuit

bit_num = 127
qc = QuantumCircuit(bit_num, bit_num)

# QKD step 1: Generate Alice's random bits and bases

abits = np.round(rng.random(bit_num))
abase = np.round(rng.random(bit_num))

# Alice's state preparation

for n in range(bit_num):
if abits[n] == 0:
if abase[n] == 1:
qc.h(n)
if abits[n] == 1:
if abase[n] == 0:
qc.x(n)
if abase[n] == 1:
qc.x(n)
qc.h(n)

# QKD step 2: Random bases for Bob

bbase = np.round(rng.random(bit_num))

for m in range(bit_num):
if bbase[m] == 1:
qc.h(m)
qc.measure(m, m)

# Qiskit patterns step 2: Transpilation

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

# Load the Runtime primitive and session
sampler = Sampler(mode=backend)

# Qiskit patterns step 3: Execute

job = sampler.run([qc_isa], shots=1)
counts = job.result()[0].data.c.get_counts()
countsint = job.result()[0].data.c.get_int_counts()

# Qiskit patterns step 4: Post-processing
# Extract Bob's bits

keys = counts.keys()
key = list(keys)[0]
bmeas = list(key)
bmeas_ints = []
for n in range(bit_num):
bmeas_ints.append(int(bmeas[n]))
bbits = bmeas_ints[::-1]

# Compare Alice's and Bob's measurement bases and collect usable bits

agoodbits = []
bgoodbits = []
match_count = 0
for n in range(bit_num):
if abase[n] == bbase[n]:
agoodbits.append(int(abits[n]))
bgoodbits.append(bbits[n])
if int(abits[n]) == bbits[n]:
match_count += 1

# Print some results

print("Alice's bits = ", agoodbits)
print("Bob's bits = ", bgoodbits)
print("fidelity = ", match_count / len(agoodbits))
print("loss = ", 1 - match_count / len(agoodbits))
Alice's bits =  [0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1]
Bob's bits = [0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1]
fidelity = 0.9682539682539683
loss = 0.031746031746031744

Bez podsłuchu uzyskaliśmy 100% wierności na tym zbiorze 127 próbnych bitów, co dało 55 dopasowanych baz i użytecznych bitów klucza. Powtórzmy teraz ten eksperyment z podsłuchem Eve:

from qiskit_ibm_runtime import SamplerV2 as Sampler

# This calculation was run on an Eagle r3 processor on 11-7-24 and required 2 s to run, with 127 qubits.
# Qiskit patterns step 1: Mapping your problem to a quantum circuit

bit_num = 127
qr = QuantumRegister(bit_num, "q")
cr = ClassicalRegister(bit_num, "c")
qc = QuantumCircuit(qr, cr)

# QKD step 1: Generate Alice's random bits and bases

abits = np.round(rng.random(bit_num))
abase = np.round(rng.random(bit_num))

# Alice's state preparation

for n in range(bit_num):
if abits[n] == 0:
if abase[n] == 1:
qc.h(n)
if abits[n] == 1:
if abase[n] == 0:
qc.x(n)
if abase[n] == 1:
qc.x(n)
qc.h(n)

# Eavesdropping happens here!
# Generate Eve's random measurement bases

ebase = np.round(rng.random(bit_num))

for m in range(bit_num):
if ebase[m] == 1:
qc.h(m)
qc.measure(qr[m], cr[m])

# Qiskit patterns step 2: Transpile

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

sampler = Sampler(mode=backend)

# Qiskit patterns step 3: Execute

job = sampler.run([qc_isa], shots=1)
counts = job.result()[0].data.c.get_counts()
countsint = job.result()[0].data.c.get_int_counts()

# Qiskit patterns step 4: Post-processing
# Extract Eve's bits

keys = counts.keys()
key = list(keys)[0]
emeas = list(key)
emeas_ints = []
for n in range(bit_num):
emeas_ints.append(int(emeas[n]))
ebits = emeas_ints[::-1]

# print(ebits)

# Restart process
# Qiskit patterns step 1: Mapping your problem to a quantum circuit

# QKD step 1: Eve uses her measurements above to prepare best guess states to send on to Bob

qr = QuantumRegister(bit_num, "q")
cr = ClassicalRegister(bit_num, "c")
qc = QuantumCircuit(qr, cr)

# Eve's state preparation

for n in range(bit_num):
if ebits[n] == 0:
if ebase[n] == 1:
qc.h(n)
if ebits[n] == 1:
if ebase[n] == 0:
qc.x(n)
if ebase[n] == 1:
qc.x(n)
qc.h(n)

# QKD step 2: Random bases for Bob

bbase = np.round(rng.random(bit_num))

for m in range(bit_num):
if bbase[m] == 1:
qc.h(m)
qc.measure(qr[m], cr[m])

# Qiskit patterns step 2: Transpile

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

# Qiskit patterns step 3: Execute

job = sampler.run([qc_isa], shots=1)
counts = job.result()[0].data.c.get_counts()
countsint = job.result()[0].data.c.get_int_counts()

# Qiskit Patterns step 4: Post-processing
# Extract Bob's bits

keys = counts.keys()
key = list(keys)[0]
bmeas = list(key)
bmeas_ints = []
for n in range(bit_num):
bmeas_ints.append(int(bmeas[n]))
bbits = bmeas_ints[::-1]

# Compare Alice's and Bob's bases, when they are the same, keep the bits.

agoodbits = []
bgoodbits = []
match_count = 0
for n in range(bit_num):
if abase[n] == bbase[n]:
agoodbits.append(int(abits[n]))
bgoodbits.append(bbits[n])
if int(abits[n]) == bbits[n]:
match_count += 1

# Print some results

print("Alice's bits = ", agoodbits)
print("Bob's bits = ", bgoodbits)
print("fidelity = ", match_count / len(agoodbits))
print("loss = ", 1 - match_count / len(agoodbits))
Alice's bits =  [1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1]
Bob's bits = [1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1]
fidelity = 0.7619047619047619
loss = 0.23809523809523814

Tutaj zaobserwowaliśmy prawie 23% utratę wierności współdzielonych bitów spowodowaną podsłuchem! Jest to bardzo łatwe do wykrycia! Zauważ, że przesyłanie informacji kwantowej na duże odległości może wprowadzać dodatkowy szum i błędy. Zapewnienie wykrywalności podsłuchu nawet w obecności szumu i nawet wtedy, gdy Eve wykorzystuje wszystkie dostępne techniki, to złożona dziedzina wykraczająca poza zakres tego wprowadzenia.

Pytania

Instruktorzy mogą poprosić o wersje tych notebooków z kluczem odpowiedzi i wskazówkami dotyczącymi umiejscowienia w typowych programach nauczania, wypełniając tę krótką ankietę na temat sposobu korzystania z notebooków.

Kluczowe pojęcia

  • Informacji kwantowej nie można kopiować ani „klonować".
  • Można powtórzyć ten sam proces przygotowania, aby wytworzyć zbiór stanów kwantowych, które są takie same lub niemal takie same.
  • Klucz szyfrowania/deszyfrowania (jednorazowy blok) może być współdzielony między dwoma osobami za pomocą stanów kwantowych.
  • Jeśli dwoje przyjaciół losowo wybiera bazę pomiarową, to w połowie przypadków wybiorą różne bazy i będą musieli odrzucić informacje z tych qubitów.
  • Losowy wybór bazy pomiarowej gwarantuje również, że podsłuchujący nie może znać przygotowanego stanu początkowego, a tym samym nie może odtworzyć wysłanego stanu. To zapewnia, że podsłuchiwanie zostanie wykryte.

Pytania P/F (prawda/fałsz)

  1. P/F W kwantowej dystrybucji klucza obaj komunikujący się partnerzy mierzą każdy qubit w tej samej bazie.
  2. P/F Podsłuchujący przechwytujący informacje kwantowe w QKD jest przez prawa natury uniemożliwiony od skopiowania przechwyconego stanu kwantowego.
  3. P/F Jednorazowy blok to klucz do szyfrowania/deszyfrowania bezpiecznych wiadomości, w którym określony schemat kodowania jest używany tylko raz, dla jednej porcji informacji (np. jednej litery alfabetu).

Pytania wielokrotnego wyboru

  1. Wybierz opcję, która najlepiej uzupełnia zdanie. Zgodnie z opisem w tym module, jednorazowy blok to zestaw kluczy szyfrowania/deszyfrowania używany...
  • a. Tylko raz dla jednej porcji informacji, np. jednej litery.
  • b. Tylko raz dla jednej wiadomości.
  • c. Tylko raz przez określony czas, np. przez jeden dzień.
  • d. Do czasu wykrycia dowodów podsłuchiwania.
  1. Przyjmij, że Alice i Bob losowo wybierają swoje bazy pomiarowe. Dokonują pomiarów. Następnie dzielą się wyborami baz i zachowują tylko bity informacji z przypadków, w których użyli tej samej bazy. Z dokładnością do losowych fluktuacji, jaki mniej więcej procent ich qubitów powinien dawać użyteczne bity informacji?
  • a. 100%
  • b. 50%
  • c. 25%
  • d. 12,5%
  • e. 0%
  1. Po tym, jak Alice i Bob wybiorą przypadki, w których używali tych samych baz pomiarowych, jaki procent tych bitów informacji powinien być zgodny, jeśli szum kwantowy i błędy byłyby pomijalnie małe?
  • a. 100%
  • b. 50%
  • c. 25%
  • d. 12,5%
  • e. 0%
  1. Przyjmij, że Alice wybrała swoje bazy pomiarowe losowo. Eve również losowo wybiera swoje bazy i podsłuchuje (mierzy). Wysyła do Boba stany zgodne ze swoimi pomiarami. Alice i Bob porównują wybory baz i zachowują tylko qubity zmierzone/przygotowane przez nich w tych samych bazach. Z dokładnością do losowych fluktuacji, jaki mniej więcej procent tych zachowanych pomiarów qubitów będzie zgodny według Alice i Boba?
  • a. 100%
  • b. 75%
  • c. 50%
  • d. 25%
  • e. 12,5%
  • f. 0%

Pytania dyskusyjne

  1. Przyjmij, że wszystkie wybory baz są losowe dla wszystkich uczestników: Alice, Boba i Eve. Przyjmij, że po podsłuchaniu Eve wysyła do Boba stan przygotowany w tej samej bazie, w której dokonała pomiaru, i który jest zgodny z tym pomiarem. Przekonaj swoich partnerów, że 12,5% wszystkich qubitów zainicjalizowanych przez Alice będzie dawać niezgodności pomiarów między Alice a Bobem, wskazując na podsłuchiwanie (ignorując błędy kwantowe i szum). Wskazówka 1: Ponieważ nie ma uprzywilejowanej bazy, jeśli rozważysz tylko jeden początkowy wybór Alice, współczynnik dla tego jednego wyboru powinien być taki sam jak współczynnik dla sumy wszystkich wyborów. Wskazówka 2: Samo zliczenie liczby sposobów, na jakie coś może się wydarzyć, może być niewystarczające, ponieważ niektóre wyniki mogą zachodzić z różnymi prawdopodobieństwami.

  2. Przyjmij znowu, że wszystkie wybory baz są losowe dla wszystkich uczestników: Alice, Boba i Eve. Teraz jednak przyjmij, że Eve może wysłać dowolny stan po swoim pomiarze. Może nawet próbować wysyłać stany niezgodne z jej własnymi pomiarami. Przedyskutuj ze swoimi partnerami/sąsiadami, czy uważasz, że istnieje jakiś wybór baz, który mógłby zmniejszyć średni procent qubitów wskazujących na podsłuchiwanie według Alice i Boba.