انتقل إلى المحتوى الرئيسي

توزيع المفاتيح الكمية

لهذه الوحدة من Qiskit in Classrooms، يحتاج الطلاب إلى بيئة Python تعمل بشكل صحيح مع تثبيت الحزم التالية:

  • qiskit الإصدار v2.1.0 أو أحدث
  • qiskit-ibm-runtime الإصدار v0.40.1 أو أحدث
  • qiskit-aer الإصدار v0.17.0 أو أحدث
  • qiskit.visualization
  • numpy
  • pylatexenc

لإعداد وتثبيت الحزم أعلاه، راجع دليل تثبيت Qiskit. لتشغيل المهام على حواسيب كمية حقيقية، يحتاج الطلاب إلى إنشاء حساب على IBM Quantum® باتباع الخطوات في دليل إعداد حساب IBM Cloud الخاص بك.

تم اختبار هذه الوحدة واستخدمت 5 ثوانٍ من وقت QPU. هذا تقدير فقط، وقد يختلف الاستخدام الفعلي.

# 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'

شاهد شرح الوحدة من الدكتورة Katie McCormick أدناه، أو اضغط هنا لمشاهدته على YouTube.


المقدمة والدافع

هناك طرق لا حصر لها لتشفير المعلومات وفك تشفيرها، وآلاف الطرق تمت دراستها بشكل جيد. هنا، سنقتصر على طريقة تشفير قديمة وبسيطة جداً تُسمى "الاستبدال البسيط"، وذلك للتركيز على الجزء الكمي من هذا البروتوكول. يمكن تكييف الجزء الكمي ليناسب بروتوكولات أخرى كثيرة مع تعديلات قليلة نسبياً.

الاستبدال البسيط

تشفير الاستبدال البسيط هو نوع يُستبدل فيه حرف أو رقم بآخر، بحيث يكون هناك تطابق 1:1 بين الحروف والأرقام في الرسالة والحروف والأرقام المستخدمة في التسلسل المشفر. من أبرز الأمثلة الشعبية على ذلك لغز cryptoquote أو cryptogram، حيث يُشفَّر اقتباس أو عبارة باستخدام الاستبدال البسيط، ومهمة اللاعب فك تشفيره. هذه الألغاز سهلة الحل إذا كانت طويلة بما يكفي. انظر المثال التالي:

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.

الناس الذين يحلون هذه الألغاز باليد يستخدمون في الغالب حيلاً تعتمد على معرفتهم ببنية لغة الرسالة الأصلية. مثلاً في الإنجليزية، الكلمات المكونة من حرف واحد مثل "R" المشفرة لا يمكن أن تكون سوى "a" أو "I". الحروف المزدوجة في مثل "KIVGGB" لا يمكن أن تأخذ سوى قيم معينة. وهناك أشياء أدق تعطي تلميحات، مثل أن أكثر كلمة شائعة تطابق نمط "GSZG" هي "that". من يستخدم الكود لحل هذه الألغاز لديه خيارات أكثر بكثير، منها المسح عبر الاحتمالات حتى يُسترجع كلمة إنجليزية، والتحديث مع الحفاظ على تلك الكلمة. طريقة بسيطة لكنها قوية هي استخدام تردد الحروف، خاصة حين تكون الرسالة طويلة بما يكفي لتكون عينة تمثيلية للإنجليزية.

سؤال تحقق

جرب فك تشفير هذا إذا أردت، وإن كان ذلك غير ضروري لبقية الوحدة. اضغط على السهم أدناه لرؤية الرسالة.

الإجابة:

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.

المثال أعلاه مرتبط بـ "مفتاح"، وهو تعيين من الحروف المشفرة إلى الحروف الأصلية. في هذه الحالة، المفتاح هو:

  • A (غير مستخدم، لنسمّه Z)
  • B->Y
  • C (غير مستخدم، لنسمّه X)
  • D->W
  • E->V
  • F->U
  • ...

وهكذا. بعبارة مخففة، هذا مفتاح سيء جداً. المفاتيح التي تكون فيها الحروف المشفرة والأصلية مجرد نسخة مزاحة من الأبجدية (مثل A->B و B->C) تُسمى تشفيرات "Caesar shift".

لاحظ أن هذه الأنواع صعبة جداً إذا كانت قصيرة. في الواقع، إذا كانت قصيرة جداً فهي غير محددة. انظر:

URYYP

هناك فك تشفيرات ممكنة كثيرة باستخدام مفاتيح مختلفة: HELLO، PETTY، HAPPY، JIGGY، STOOL. هل تستطيع التفكير في غيرها؟

لكن إذا أرسلت رسائل كثيرة كهذه، فسينكسر التشفير في نهاية المطاف. لذا ما ينفعك هو ألا تستخدم نفس "المفتاح" كثيراً. في الواقع، الأفضل أن تستخدم استبدالاً معيناً مرة واحدة فقط. ليس في رسالة واحدة فقط، بل لحرف واحد فقط! بهذا نعني أن يكون لديك مخطط تشفير أو مفتاح لكل حرف مستخدم في الرسالة، بالترتيب. إذا أردت إرسال رسالة لصديق بهذا الأسلوب، ستحتاج أنت وصديقك إلى ورقة (في الزمن القديم) مكتوب عليها هذا المفتاح المتغير باستمرار. وستستخدمونها مرة واحدة فقط. هذا يُسمى "الوسادة لمرة واحدة" (one-time pad).

الوسادة لمرة واحدة

لنرَ كيف يعمل هذا مع مثال. يمكن القيام بهذا بالحروف بالكامل، لكن من الشائع تحويل الحروف إلى أرقام، مثلاً بتعيين A=0، B=1، C=2…. لنفترض أننا أصدقاء منخرطون في أنشطة سرية وقد تشاركنا وسادة. مثالياً كنا سنتشارك وسادات كثيرة، لكن وسادة اليوم هي:

EDGRPOJNCUWQZVMK…

أو، بالتحويل إلى أرقام حسب مواضعها في الأبجدية:

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

لنفترض أنني أريد مشاركتك الرسالة:

"I love quantum!"

أو بشكل مكافئ:

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

لا نريد إرسال الكود أعلاه؛ فذلك مجرد استبدال بسيط وغير آمن على الإطلاق. نريد دمجه مع مفتاحنا بطريقة ما. طريقة شائعة هي الجمع modulo 26. نجمع قيمة الرسالة مع قيمة المفتاح، mod 26، حتى نصل إلى نهاية الرسالة. إذن سنرسل:

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

لاحظ أنه لو اعترض أحدهم هذا وليس لديه المفتاح، فإن فك تشفيره مستحيل تماماً! حتى الحرفان "u" في "quantum" لم يُشفَّرا بنفس الرقم! الأول هو 3، والثاني هو 16… في نفس الكلمة!

إذن، أرسل هذا إليك، وأنت لديك نفس المفتاح الذي عندي. تتراجع عن الجمع modulo 26 الذي تعلم أنني قمت به:

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),…

بحيث تكون الرسالة x1, x2, x3, x4… يجب أن تكون

8, 11, 14, 21…

وأخيرًا، بتحويل هذا إلى نص، نحصل على

"I love quantum".

هذه هي لوحة الاستخدام الواحد (One-Time Pad).

لاحظ أنه إذا كان المفتاح أقصر من الرسالة، فسنبدأ بتكرار الترميز. هذا لا يزال مشكلة تشفير صعبة الحل، لكنها ليست مستحيلة إذا تكررت مرات كافية. لذا، أنت بحاجة إلى مفتاح طويل (أو "لوحة").

ملاحظة

في كثير من السياقات، سيكون الطلاب على دراية بهذا التشفير مسبقًا، بحيث يمكن تخطي هذا النشاط. لكنه مراجعة سريعة وبسيطة نسبيًا.

الخطوة 1: اختر شريكًا، وتشاركا تسلسلًا من 4 حروف لاستخدامه كمفتاح. أي تسلسل من 4 حروف مناسب للفصل الدراسي سيفي بالغرض.
الخطوة 2: اختر كلمة سرية من 4 حروف تريد إرسالها لشريكك (يفعل كلا الشريكين هذا كي يرسل كل منهما كلمة سرية مختلفة للآخر).
الخطوة 3: حوّل المفتاح/اللوحة من 4 حروف وكل كلمة سرية مكونة من 4 حروف إلى أرقام باستخدام A = 1، B = 2، وهكذا.
الخطوة 4: ادمج كلمتك المكونة من 4 حروف مع لوحة الاستخدام الواحد باستخدام الجمع بحساب نظام modulo 26.
الخطوة 5: سلّم شريكك تسلسل الأرقام الذي يرمّز كلمتك السرية، وسيسلّمك شريكك تسلسله.
الخطوة 6: فكّ تشفير كلمة كل منكما باستخدام الطرح بحساب نظام modulo 26.
الخطوة 7: تحقق. هل نجح الأمر؟

متابعة

تبادل الكلمات المشفرة مع مجموعة مختلفة لا تمتلك لوحة الاستخدام الواحد الخاصة بك. هل يمكنك فك تشفيرها؟ اشرح لماذا أم لماذا لا؟

نأمل أن النشاط أعلاه يوضح أن لوحة الاستخدام الواحد هي شكل من أشكال التشفير الذي لا يمكن كسره، بافتراض بعض الشروط، مثل:

  • المفتاح بنفس طول الرسالة المُرسَلة أو أطول
  • المفتاح عشوائي حقًا
  • يُستخدم المفتاح مرة واحدة فقط ثم يُتخلص منه

إذن هذا رائع. لدينا تشفير لا يمكن كسره... ما لم يحصل أحدهم على مفتاحنا. إذا حصل أحدهم على مفتاحنا، يتم فك تشفير كل شيء. هذا الفارق بين التشفير الذي لا يمكن كسره وانكشاف جميع أسرارنا يجعل مشاركة مفتاح آمن أمرًا بالغ الأهمية. الهدف من توزيع المفتاح الكمومي هو الاستفادة من القيود التي فرضتها الطبيعة على المعلومات الكمومية لتأمين مفتاح/لوحة استخدام واحد مشتركة.

استخدام الحالات الكمومية كمفتاح

لنفترض أننا نعمل مع كيوبتات (مع التأكيد على أن الكيوبتات لها حالتان ذاتيتان). يمكن للمرء استخدام أنظمة كمومية بأعداد أعلى من الحالات الكمومية، لكن أحدث أجهزة الكمبيوتر الكمومية لدى IBM® تستخدم الكيوبتات. لا توجد مشكلة في ترميز A، B، C لدينا في تسلسلات من 0 و1. لذا، يكفي أن نتشارك مفتاحًا من 0 و1 ونجري الجمع بحساب نظام modulo 2 على كل بت يخزن حرفًا.

تحقق من فهمك

اقرأ السؤال أدناه، فكّر في إجابتك، ثم انقر على المثلث للكشف عن الحل.

إذا كنا نهتم فعلًا بالحروف الإنجليزية فقط، فكم عدد البتات التي نحتاجها؟

الإجابة:

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

صديقانا، أليس وبوب، يرغبان في مشاركة مفتاح كمومي بحيث لا يستطيع أي شخص آخر اعتراضه (على الأقل ليس دون علمهما). يحتاجان إلى طريقة لإرسال الحالات الكمومية لبعضهما. القيام بهذا بدقة عالية وبدون ضوضاء/أخطاء ليس أمرًا بسيطًا. لكن هناك نهجان يجب أن نكون قادرين على فهمهما في هذه المرحلة:

  1. الكابل الضوئي الليفي يتيح لك إرسال الضوء... وهو ميكانيكا كمومية للغاية. يمكن اكتشاف الفوتونات الفردية بدقة عالية عبر كيلومترات عديدة من الكابل الضوئي الليفي. هذه ليست قناة كمومية مثالية وخالية من الأخطاء، لكنها يمكن أن تكون جيدة جدًا.
  2. يمكننا استخدام الإنتقال الكمومي، كما هو موضح في وحدة سابقة. أي أن أليس وبوب يمكنهما مشاركة كيوبتات متشابكة ويمكن إرسال حالة من أليس إلى بوب باستخدام بروتوكول الإنتقال الكمومي.

في هذه الوحدة، لا نريد أن نطلب منك إعدادات بصرية عالية الدقة لمشاركة الفوتونات، لذا سنستخدم الطريقة الثانية لمشاركة الحالات الكمومية. لكن هذا لا يعني أنها الأكثر واقعية للمشاركة بعيدة المدى للمفاتيح الكمومية.

سنستكشف الآن بروتوكولًا وضعه أول مرة تشارلز بينيت وجيل براسار عام 1984 لمشاركة الحالات المقاسة في قواعد مختلفة من أليس إلى بوب. سنستخدم نظام قياس ذكي لبناء مفتاح للاستخدام في التشفير اللاحق. بعبارة أخرى، نحن نوزع مفتاحًا كموميًا بين طرفين يرغبان في التواصل، ومن هنا جاء مصطلح "توزيع المفتاح الكمومي" (QKD).

الخطوة 1 من QKD: البتات العشوائية والقواعد العشوائية لأليس

ستبدأ أليس بتوليد تسلسل عشوائي من 0 و1. ثم ستختار عشوائيًا قاعدة لتحضير حالة كمومية، بناءً على كل بت عشوائي، باستخدام الجدول أدناه (جدول يمتلكه بوب أيضًا):

القاعدةbit = 0bit = 1
Z0\vert 0\rangle1\vert 1\rangle
X+\vert +\rangle\vert -\rangle

على سبيل المثال، لنفترض أن أليس ولّدت عشوائيًا الرقم 0، واختارت عشوائيًا القاعدة X. عندها ستحضر حالة كمومية ψ=+x=12(0+1)|\psi\rangle = |+\rangle_x = \frac{1}{\sqrt{2}}(|0\rangle+|1\rangle). يمكن للمرء بالتأكيد الاستفادة من العشوائية الكمومية لتوليد مجموعة عشوائية من 0 و1، واختيار عشوائي للقاعدة. في الوقت الحالي، لنفترض ببساطة أنه تم توليد مجموعة عشوائية، على النحو التالي:

بتات أليس010011010...
قواعد أليسXXZZZXZZX...
حالات أليس+\vert +\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle1\vert 1\rangle\vert -\rangle0\vert 0\rangle1\vert 1\rangle+\vert +\rangle...

هذه المجموعة من البتات العشوائية والقواعد والحالات الناتجة ستستمر في تسلسل طويل، لإعطاء مفتاح بطول كافٍ.

الخطوة 2 من QKD: القواعد العشوائية لبوب

يختار بوب أيضًا قواعد عشوائية. لكن بينما كانت أليس تستخدم اختيار القاعدة لتحضير حالتها، سيقوم بوب فعليًا بإجراء قياسات في هذه القواعد. إذا أجرى بوب قياسًا في نفس القاعدة التي حضّرت فيها أليس الحالة، فيمكننا التنبؤ بنتيجة قياس بوب. عندما يختار بوب صدفةً قاعدة مختلفة عن القاعدة التي استخدمتها أليس في التحضير، لا يمكننا معرفة نتيجة قياس بوب.

بتات أليس010011010...
قواعد أليسXXZZZXZZX...
حالات أليس+\vert +\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle1\vert 1\rangle\vert -\rangle0\vert 0\rangle1\vert 1\rangle+\vert +\rangle...
قواعد بوبXZXZXXZXX...
حالات بوب (مسبقًا)+\vert +\rangle??0\vert 0\rangle?\vert -\rangle0\vert 0\rangle?+\vert +\rangle...
حالات بوب (مقاسة)+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle\vert -\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...

في الجدول أدناه، تأمل العمود الأول. لقد حضّرت أليس الحالة +,\vert +\rangle, وهي حالة ذاتية للقاعدة X. بما أن بوب اختار أيضًا عشوائيًا القياس في قاعدة X، فهناك نتيجة واحدة فقط ممكنة للحالة المقاسة لبوب: +.\vert +\rangle. في العمود الثاني، اختارا قواعد مختلفة. الحالة التي أرسلتها أليس هي =12(01).\vert -\rangle = \frac{1}{\sqrt{2}}(\vert 0\rangle-\vert 1 \rangle). هذه الحالة لديها احتمال 50% أن يقيسها بوب في الحالة 0\vert 0\rangle، واحتمال 50% أن يقيسها في 1.\vert 1\rangle. لذا لا يمكن ملء الصف الذي يُظهر ما نعرفه مسبقًا عن قياسات بوب للعمود الثاني. لكن بوب سيجري قياسًا ويحصل على حالة ذاتية للقاعدة Z (في ذلك العمود). في الصف السفلي، نملأ ما أسفرت عنه هذه القياسات.

الخطوة 3 من QKD: النقاش العلني حول القواعد

يمكن لأليس وبوب الآن مشاركة بعضهما ما هي القاعدة التي اختاراها في كل حالة. في جميع الأعمدة التي اتفقا فيها على نفس القاعدة، كل منهما يعرف بيقين ما الحالة التي كانت عند الآخر. يمكن لبوب تحويل الحالة والقاعدة إلى 0 أو 1 وفقًا للاتفاقية المشتركة بين الطرفين. يمكننا إعادة كتابة الجدول أعلاه لإظهار الحالات التي تطابقت فيها قواعد أليس وبوب فقط:

بتات أليس00100...
قواعد أليسXZXZX...
حالات أليس+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle...
قواعد بوبXZXZXX
حالات بوب (مسبقًا)+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle...
حالات بوب (مقاسة)+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle...
بتات بوب00100...

نجحت أليس في نقل سلسلة البتات 00100... إلى بوب. إذا اتفق الصديقان مسبقًا على استخدام سلاسل من 5 بتات كأرقام في لوحة الاستخدام الواحد، فإن هذه البتات الخمس الأولى ستعطيهما الرقم 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.

الخطوة 4 من QKD: التحقق وإرسال السر

قبل أن يتابع أليس وبوب أي شيء آخر، يجب عليهما اختيار مجموعة فرعية من بتاتهما الكلاسيكية للمقارنة. بما أنهما احتفظا فقط بقياسات الكيوبتات التي تم تحضيرها وقياسها باستخدام نفس القاعدة، يجب أن تتطابق جميع القيم المقاسة. إذا كانت نسبة صغيرة جدًا لا تتوافق، يمكن أن يُعزى ذلك إلى الضوضاء الكمومية أو الأخطاء. لكن إذا كان الكثير منها لا يتوافق، فهذا يعني أن شيئًا ما قد حدث خطأ!

هنا لن نتطرق إلى الجزء الذي يجب استخدامه من المفتاح للتحقق. في الوقت الحالي، سنفترض أن هذا الفحص يسير بشكل جيد؛ سنعود إليه في القسم أدناه المتعلق بالتنصت.

سيرسل الصديقان بعد ذلك رسالة مشفرة لبعضهما عبر القنوات الكلاسيكية. سيستخدمان الأرقام الموجودة في لوحة الاستخدام الواحد لتشفير/فك تشفير الرسائل السرية، دون نقل لوحة الاستخدام الواحد أبدًا من موقع إلى آخر. في القسم التالي حول التنصت، يرجى مراعاة أن كل هذه المشاركة للمفتاح تحدث قبل الكشف عن السر المشفر عبر القنوات الكلاسيكية.

تواصل أليس وبوب بشأن أساس الاختيار عبر القنوات الكلاسيكية، أفلا يمكن اعتراض ذلك؟ نعم! لكن معرفة القاعدة التي استخدماها للقياس لا تخبرك بالبت الذي أرسله أو حصل عليه أي منهما. هذا ممكن فقط إذا كنت تعرف أيضًا بتات أليس الأولية. لكن عندها ستكون داخل جهاز كمبيوتر أليس حيث تُخزّن الأسرار، وستصبح الاتصالات السرية للأسرار بلا معنى. لذا فإن اعتراض الاتصال الكلاسيكي لا يكسر التشفير. لكن ماذا عن اعتراض المعلومات في القناة الكمومية؟

مقاومة QKD للتنصت

لأليس وبوب صديقة تُدعى إيف، مشهورة بالتنصت. تريد إيف اعتراض المفتاح الكمومي لأليس وبوب كي تتمكن من استخدامه لفك تشفير الرسائل المتبادلة بينهما. سيحدث هذا بالضرورة بين تحضير أليس للحالات وقياس بوب لها، نظرًا لأن القياس يهدم الحالة الكمومية. وبشكل خاص، هذا يعني أن التنصت يجب أن يحدث قبل أي مشاركة أو مقارنة للقواعد.

يجب على إيف تخمين القاعدة المستخدمة في ترميز كل بت. مرة أخرى، إذا لم تستطع الوصول إلى جهاز كمبيوتر أليس، فليس لديها أي أساس لهذا التخمين وسيكون عشوائيًا. لنفترض أن بداية أليس هي نفسها كما في السابق، ولنفترض كذلك أن اختيار بوب العشوائي لقاعدة القياس هو نفسه كما في السابق. لنملأ ما تحصل عليه إيف إذا أجرت قياسات للقناة الكمومية. كما في السابق، إذا صادف أن اختارت إيف نفس القاعدة التي اختارتها أليس، نعرف ما ستحصل عليه. إن لم تفعل، يمكنها الحصول على أي من نتيجتين، كل منهما باحتمال 50%.

بتات أليس010011010...
قواعد أليسXXZZZXZZX...
حالات أليس+\vert +\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle1\vert 1\rangle\vert -\rangle0\vert 0\rangle1\vert 1\rangle+\vert +\rangle...
قواعد إيف المخمّنةZXXZXZZXX...
حالات إيف (مسبقًا)?\vert -\rangle?0\vert 0\rangle??0\vert 0\rangle?+\vert +\rangle...
حالات إيف (مقاسة)1\vert 1\rangle\vert -\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...
قواعد بوبXZXZXXZXX...

الآن بما أن إيف لا تعرف إن كانت قد طابقت قاعدة أليس أم لا، فهي لا تعلم ما الذي تُرسله إلى بوب ليطابق الحالات الأصلية لأليس. عندما تقيس إيف، مثلًا، 0,|0\rangle, كل ما تعرفه بيقين هو أن أليس لم تحضّر الحالة 1|1\rangle لتلك الكيوبت. لكن أليس كان يمكنها تحضير 0,|0\rangle, أو +,|+\rangle, أو .|-\rangle. كل هذه الحالات تتوافق مع قياس إيف. إذن يجب على إيف أن تختار. قد ترسل الحالة التي قاستها بالضبط، أو قد تحاول تخمين الحالات التي لم يكن قياسها هو الحالة الذاتية التي أرسلتها أليس. سندرج مزيجًا في جدولنا:

بتات أليس010011010...
قواعد أليسXXZZZXZZX...
حالات أليس+\vert +\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle1\vert 1\rangle\vert -\rangle0\vert 0\rangle1\vert 1\rangle+\vert +\rangle...
قواعد إيف المخمّنةZXXZXZZXX...
حالات إيف (مسبقًا)?\vert -\rangle?0\vert 0\rangle??0\vert 0\rangle?+\vert +\rangle...
حالات إيف (مقاسة)1\vert 1\rangle\vert -\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...
حالات إيف (المرسلة)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...
قواعد بوبXZXZXXZXX...
حالات بوب (مسبقًا)?0\vert 0\rangle?0\vert 0\rangle\vert -\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...
حالات بوب (مقاسة)\vert -\rangle0\vert 0\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle0\vert 0\rangle\vert -\rangle+\vert +\rangle...
بتات بوب100010010...

في هذه النقطة، من المنطقي أن تسأل: "لماذا لا تصنع إيف نسخة من حالة أليس الكمومية، وتحتفظ بواحدة للقياس، وترسل الأخرى إلى بوب؟" الجواب هو نظرية "عدم الاستنساخ". بشكل غير رسمي، تقول إنه لا توجد عملية وحدوية (ميكانيكية كمومية) يمكنها صنع نسخة ثانية من حالة كمومية عشوائية مع الحفاظ على النسخة الأولى. الإثبات بسيط نسبيًا، وهو متروك كتمرين موجّه. لكن في الوقت الحالي، افهم أن قيام إيف بعمل نسخ من الحالة الكمومية محظور بموجب القوانين الأساسية للطبيعة، وهذا يُعدّ قوة جوهرية للـ QKD.

كما في السابق، سيتصل أليس وبوب ببعضهما ويقارنان القواعد. سيقلصان هذا الجدول إلى الحالات التي اختار فيها الصديقان نفس القواعد:

بتات أليس00100...
قواعد أليسXZXZX...
حالات أليس+\vert +\rangle0\vert 0\rangle\vert -\rangle0\vert 0\rangle+\vert +\rangle...
قواعد إيف المخمّنةZZZZX...
حالات إيف (مسبقًا)?0\vert 0\rangle?0\vert 0\rangle+\vert +\rangle...
حالات إيف (مقاسة)1\vert 1\rangle0\vert 0\rangle0\vert 0\rangle0\vert 0\rangle+\vert +\rangle...
حالات إيف (المرسلة)1\vert 1\rangle0\vert 0\rangle+\vert +\rangle0\vert 0\rangle0\vert 0\rangle...
قواعد بوبXZXZX...
حالات بوب (مسبقًا)?0\vert 0\rangle+\vert +\rangle0\vert 0\rangle+\vert +\rangle...
حالات بوب (مقاسة)\vert -\rangle0\vert 0\rangle+\vert +\rangle0\vert 0\rangle+\vert +\rangle...
بتات بوب10000...

نجح أليس وبوب مجددًا في توصيل سلسلة بتات... لكن السلاسل لا تتطابق. البت الأيسر والبت الأوسط مقلوبان. بالنظر إلى الجدول السابق، يمكنك تتبع هذا التعارض إلى تدخل إيف. والأهم، لاحظ أننا نستطيع الآن إجراء إحصاءات على التطابق بين سلاسل البتات لدينا، أثناء إعداد المفتاح، قبل وقت طويل من الكشف عن سرنا المشفر. أليس وبوب أحرار في استخدام أي عدد من بتات لوحة الاستخدام الواحد يريدانه للتحقق من أمان قناتهما. إذا لم يتطابق بت واحد أو نسبة صغيرة جدًا من البتات، فقد يُعزى ذلك إلى الضوضاء أو الأخطاء. لكن نسبة كبيرة من التعارضات تشير إلى التنصت. معنى "كبيرة" هنا يعتمد نوعًا ما على مستوى الضوضاء في الإعداد المستخدم؛ ما تعنيه لأجهزة الكمبيوتر الكمومية من IBM® يُناقش أدناه عند تنفيذ هذا البروتوكول. إذا اكتُشفت أخطاء زائدة، لا يتشاركان السر، ويمكنهما البدء في البحث عن المتنصت.

تحفظات

إثبات الأمان أمر بالغ الصعوبة. في الواقع، البروتوكول الموضح هنا بشكل عام اقتُرح في عام 1984، ولم يُثبت أمانه إلا بعد 16 عامًا Shor & Preskill, 2000. هناك الكثير من الدقائق التي تتجاوز نطاق هذه المقدمة. لكننا سنذكر بعضها باختصار لإظهار أن الموضوع أكثر تعقيدًا مما هو موضح هنا.

  • القنوات الآمنة: عندما ترسل أليس كيوبتاتها عبر إعداد كمومي ما (قناة)، وخاصةً عندما تسمع ردودًا كلاسيكية من شخص ما، افترضنا أن ذلك الشخص هو بوب فعلًا. إذا تسللت إيف إلى هذا الإعداد بحيث أن جميع تواصل أليس كان يجري فعليًا مع إيف، و__جميع__ تواصل بوب كان يجري فعليًا مع إيف، فقد حصلت إيف فعليًا على مفتاح، ويمكنها الاطلاع على الأسرار. يجب على المرء أولًا ضمان "القنوات الآمنة"، وهي عملية ذات مجموعة مختلفة من البروتوكولات لم نتطرق إليها هنا.
  • افتراضات حول إيف: لإثبات الأمان بشكل حقيقي، لا يمكننا وضع افتراضات حول سلوك إيف؛ فهي قد تخيب توقعاتنا دائمًا. هنا، لتقديم أمثلة ملموسة، نضع افتراضات. على سبيل المثال، قد نفترض أن الحالات التي ترسلها إيف إلى بوب هي دائمًا بالضبط تلك التي حصلت عليها عند القياس. أو قد نفترض أنها تختار عشوائيًا حالة متوافقة تجريبيًا مع قياسها. والأهم من ذلك، اللغة المستخدمة هنا تفترض أن إيف تجري قياسًا فعليًا، على عكس تخزين الحالة على نظام كمومي آخر وإرسال كيوبت عشوائي إلى بوب. هذه الافتراضات مقبولة لفهم البروتوكول، لكنها تعني أننا لا نثبت أي شيء بشكل عام كامل.
  • تضخيم الخصوصية: لا يُلزم أليس وبوب باستخدام المفتاح الكمومي بالضبط كما تم إرساله. يمكنهما، مثلًا، تطبيق دالة تجزئة (hash function) على المفتاح المشترك. هذا يستغل حقيقة أن المتنصت لديه معرفة غير مكتملة بالمفتاح لإنتاج مفتاح مشترك أقصر لكنه آمن.

التجربة 1: QKD بدون متنصت

لنطبق البروتوكول أعلاه في غياب متنصت. سنفعل ذلك أولًا باستخدام محاكٍ، لفهم سير العمل.

أولًا، ملاحظة حول المحاكيات الكمومية: معظم المسائل الكمومية التي تتضمن أكثر من ~30 كيوبت لا يمكن محاكاتها بمعظم الحواسيب. لا يستطيع أي حاسوب كلاسيكي أو حاسوب عملاق أو معالج رسوميات GPU محاكاة النطاق الكامل لسلوك حاسوب كمومي بـ 127 كيوبت. عادةً، الدافع لاستخدام أجهزة الكمبيوتر الكمومية الحقيقية هو أن الكيوبتات المتشابكة الكثيرة لا يمكن محاكاتها. في هذه الحالة، لا يوجد تشابك بين الكيوبتات، ما لم نستخدم نظام الإنتقال الكمومي لنقل المعلومات. في هذه الحالة، الدافع لاستخدام أجهزة الكمبيوتر الكمومية الحقيقية مختلف: إنه نظرية عدم الاستنساخ. يمكن لحاسوب كلاسيكي يحاكي كيوبتًا أن يرسل معلومات عن حالة كمومية من أليس إلى بوب، لكن إذا تم اعتراض هذه المعلومات الكلاسيكية، يمكن تضاعفها بسهولة، وتحتفظ إيف بنسخة مثالية بينما ترسل أخرى إلى بوب. هذا غير ممكن مع الحالات الكمومية الحقيقية.

توصي IBM Quantum بمعالجة مسائل الحوسبة الكمومية باستخدام إطار عمل نسميه "أنماط Qiskit". ويتضمن الخطوات التالية:

  • الخطوة 1: عيّن مشكلتك على دائرة كمومية
  • الخطوة 2: حسّن دائرتك للتشغيل على أجهزة كمومية حقيقية
  • الخطوة 3: نفّذ وظيفتك على أجهزة الكمبيوتر الكمومية من IBM باستخدام أوليّات Runtime
  • الخطوة 4: أجرِ المعالجة اللاحقة للنتائج

أنماط Qiskit الخطوة 1: تعيين المشكلة على دائرة كمومية

في هذه الحالة، يتلخص تعيين مشكلتنا على الدوائر الكمومية في تحضير حالات أليس فحسب، ثم تضمين قياسات بوب. نبدأ باختيار البت العشوائي والقاعدة العشوائية.

# 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)

لنرسم البتات والقواعد والدائرة بيانيًا. لاحظ أن القواعد تتطابق أحيانًا وأحيانًا لا تتطابق.

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

أنماط Qiskit الخطوة 2: تحسين المشكلة للتنفيذ الكمومي

تأخذ هذه الخطوة العمليات التي نريد تنفيذها وتعبّر عنها من حيث وظائف حاسوب كمومي بعينه. كما تعيّن مشكلتنا على تخطيط الحاسوب الكمومي.

سنبدأ بتحميل عدة حزم مطلوبة للتواصل مع أجهزة الكمبيوتر الكمومية من IBM. يجب علينا أيضًا اختيار واجهة خلفية (backend) للتشغيل عليها. يمكننا إما اختيار الواجهة الخلفية الأقل انشغالًا، أو تحديد واجهة خلفية بعينها نعرف خصائصها. رغم أننا سنستخدم محاكيًا في الوقت الحالي، من المهم استخدام نموذج ضوضاء معقول في المحاكاة، ومن الجيد إبقاء سير العمل قريبًا قدر الإمكان مما سنستخدمه لاحقًا مع أجهزة الكمبيوتر الكمومية الحقيقية.

يوجد كود أدناه لحفظ بيانات اعتمادك عند الاستخدام الأول. احرص على حذف هذه المعلومات من الدفتر بعد حفظها في بيئتك، حتى لا تُشارَك بيانات اعتمادك عن طريق الخطأ عند مشاركة الدفتر. راجع Set up your IBM Cloud account و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

أدناه نختار محاكيًا ونموذج ضوضاء.

# 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)

أنماط Qiskit الخطوة 3: التنفيذ

استخدم أداة الأخذ بالعينات (sampler) لتشغيل وظيفتك، مع الدائرة كوسيط.

# 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()

أنماط Qiskit الخطوة 4: المعالجة اللاحقة

هنا نفسّر نتائجنا ونستخرج المعلومات المفيدة. قد نحاول رسم مخرجات أداة الأخذ بالعينات بيانيًا، لكننا استخدمناها بطريقة غير تقليدية. بدلًا من إجراء قياسات كثيرة لدائرتنا وتطوير إحصاءات حول الحالات، أجرينا قياسًا واحدًا فقط (قياس بوب). أي كيوبت ذات حالة تم تحضيرها وقياسها في نفس القاعدة يجب أن تكون لها نتيجة حتمية، بحيث يكفي قياس واحد. تلك الكيوبتات ذات الحالات التي تم تحضيرها وقياسها في قواعد مختلفة (والتي سيكون لها نتائج احتمالية وتتطلب قياسات كثيرة لتفسيرها) لن تُستخدم لبناء لوحة الاستخدام الواحد/المفتاح.

لنستخرج قائمة بنتائج القياسات من سلسلة البتات هذه. انتبه لعكس الترتيب إذا كنت تقارن بمصفوفة بتات أليس التي استخدمناها لتوليد الدائرة.

# 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]

لنقارن قواعد القياس التي اختارها أليس وبوب عشوائيًا. كانت هذه الخطوة 3 في بروتوكول QKD الخاص بنا (النقاش العلني حول القواعد). في كل مرة يختاران فيها نفس القاعدة لكيوبت ما، نضيف البتات المرتبطة بتلك الكيوبت إلى قائمة البتات لتوليد أرقام في لوحة الاستخدام الواحد. عندما لا تتطابق القواعد، تُستبعد النتائج. لنتحقق أيضًا إذا كانت القائمتان من البتات تتفقان، أو إذا كان هناك أي خسائر بسبب الضوضاء أو عوامل أخرى.

# 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

لدى أليس وبوب كل منهما قائمة من البتات، وتتطابقان بدقة 100%. يمكنهما استخدامها لتوليد أرقام في لوحة الاستخدام الواحد. يمكنهما بعد ذلك استخدام هذا في الخطوة 4 من QKD: إرسال وفك تشفير سر. المصفوفة الحالية من البتات قصيرة جدًا لفك تشفير أي شيء يُذكر. سنعود إلى هذا بعد تضمين التنصت.

تحقق من فهمك

اقرأ السؤال أدناه، فكّر في إجابتك، ثم انقر على المثلث للكشف عن الحل.

افترض أنك تحتاج أرقامًا كبيرة بما يكفي لتيسير إزاحة الحروف في الأبجدية الإنجليزية بطول تلك الأبجدية كاملًا أو أكثر، رغم أن هناك بالتأكيد مخططات ترميز أخرى. (أ) كم حرفًا يمكن أن تكون الرسالة كي يمكن فك تشفيرها باستخدام البتات الموجودة في المفتاح أعلاه؟ (ب) هل يجب أن تتفق إجابتك مع إجابات زملائك؟ لماذا أم لماذا لا؟

الإجابة:

(a) The answer depends on how many randomly-chosen bases matched between Alice and Bob. Since there is roughly a 50-50 chance of the bases matching for any given qubit, we expect close to 10 of our bits to be useful. 9 or 11 will be perfectly common. Even 4 or 15 are not outside the realm of possibility. 5 bits are required to shift by a number greater than or equal to the length of the English alphabet, meaning you can apply the shift to one letter for every 5 bits you have. If you have at least 5 bits shared by Alice and Bob, you can encode a single letter. If you have at least 10, you can encode 2 letters, and so on. (b) It need not agree, for the reasons outlined in (a).

التجربة 2: توزيع المفاتيح الكمية مع وجود متنصّت

سنطبّق نفس البروتوكول السابق بالضبط، لكن هذه المرة سنضيف مجموعة قياسات إضافية تجريها إيف بين أليس وبوب.

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()

الخطوة الرابعة من أنماط Qiskit (المعالجة اللاحقة) بسيطة في هذه الحالة، إذ لا حاجة لتصوير توزيع القياسات لأننا أجرينا قياساً واحداً فقط. إيف لديها البِتّات التالية:

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]

الآن يجب على إيف إعادة بناء الحالات الكمية لإرسالها إلى بوب. كما أشرنا في المقدمة، ليس لديها أي طريقة لمعرفة إذا كانت قد خمّنت قواعد التشفير بشكل صحيح، لذا لا تستطيع إعداد نفس الحالات التي أُرسلت بالضبط. يمكنها افتراض أن كل اختيار للقاعدة كان صحيحاً وتشفير ما قاسته تماماً، أو يمكنها افتراض أنها اختارت القاعدة بشكل خاطئ والاختيار من أي حالة ذاتية للقاعدة المقابلة. هنا نفترض الأول للتبسيط. نحقق ذلك ببناء دائرة كمية جديدة كلياً وتكرار خطوات أنماط Qiskit كما من قبل.

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]

الآن لنقارن بِتّات أليس وبوب:

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

في السابق، كان هناك تطابق تام بين بِتّات مفتاح أليس وبوب. أما الآن، فبسبب تدخّل إيف نرى أن بِتّات أليس وبوب تختلف في 14% من الحالات التي كان يجب أن تتطابق فيها لأن أليس وبوب اختارا نفس القواعد. يجب أن يكون هذا سهل الاكتشاف لأليس وبوب. غير أن الاعتماد على نسبة الأخطاء هذه يعني أن هناك حداً لمقدار الضوضاء الذي يمكننا تحمّله في القناة الكمية.

التجربة 3: مقارنة توزيع المفاتيح الكمية مع وبدون تنصّت على حاسوب كمي حقيقي

لنشغّل هذا على حاسوب كمي حقيقي. بهذه الطريقة نستطيع الاستفادة من نظرية عدم الاستنساخ. في نفس الوقت، تحتوي الحواسيب الكمية الحقيقية على ضوضاء ومعدلات أخطاء أعلى من الحواسيب الكلاسيكية. لذا دعنا نقارن الفقدان في دقة بِتّات المفتاح مع وبدون تنصّت، للتأكد من أن الفرق قابل للاكتشاف عند استخدام حاسوب كمي حقيقي. سنبدأ في غياب التنصّت:

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

بدون تنصّت، حصلنا على دقة 100% على هذه المجموعة من 127 بِتّة تجريبية، ما أسفر عن 55 قاعدة متطابقة وبِتّات مفتاح قابلة للاستخدام. الآن لنكرّر هذه التجربة مع استماع إيف:

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

وجدنا هنا ما يقارب 23% فقدان في دقة البِتّات المشتركة بسبب التنصّت! وهذا قابل للاكتشاف بسهولة! لاحظ أن نقل المعلومات الكمية عبر مسافات طويلة قد يُدخل ضوضاء وأخطاء إضافية. ضمان إمكانية اكتشاف التنصّت حتى في وجود الضوضاء وحتى عندما تستخدم إيف كل الحيل المتاحة لها هو مجال متخصص يتجاوز نطاق هذه المقدمة.

الأسئلة

يمكن للمدرّسين طلب نسخ من هذه الدفاتر مع مفاتيح الإجابات والتوجيهات حول موضعها في المناهج الشائعة عن طريق ملء هذا الاستبيان السريع حول كيفية استخدام الدفاتر.

المفاهيم الأساسية

  • لا يمكن نسخ المعلومات الكمية أو "استنساخها".
  • يمكنك تكرار نفس عملية التحضير لإنشاء مجموعة من الحالات الكمية المتشابهة أو شبه المتشابهة.
  • يمكن مشاركة مفتاح التشفير/فك التشفير (الرقعة ذات الاستخدام الواحد) بين صديقين باستخدام الحالات الكمية.
  • عندما يختار الصديقان قاعدة قياس بشكل عشوائي، فنصف الوقت سيختاران بشكل مختلف وسيضطران لاستبعاد المعلومات المتعلقة بتلك الكيوبتات.
  • الاختيار العشوائي لقاعدة القياس يضمن أيضاً أن المتنصّت لا يستطيع معرفة الحالة الابتدائية المُحضَّرة، وبالتالي لا يستطيع إعادة إنشاء الحالة المُرسَلة. هذا يضمن اكتشاف عملية التنصّت.

أسئلة صح/خطأ

  1. ص/خ في توزيع المفاتيح الكمية، يقيس الشريكان المتواصلان كل كيوبت في نفس القاعدة.
  2. ص/خ المتنصّت الذي يعترض المعلومات الكمية في توزيع المفاتيح الكمية تمنعه قوانين الطبيعة من نسخ الحالة الكمية التي يعترضها.
  3. ص/خ الرقعة ذات الاستخدام الواحد هي مفتاح لتشفير/فك تشفير الرسائل الآمنة يُستخدم فيه نظام ترميز معين مرة واحدة فقط، لقطعة معلومات واحدة (مثل حرف واحد من الأبجدية).

أسئلة الاختيار المتعدد

  1. اختر الخيار الأكثر اكتمالاً للجملة. كما هو موضح في هذه الوحدة، الرقعة ذات الاستخدام الواحد هي مجموعة من مفاتيح التشفير/فك التشفير تُستخدم...
  • أ. مرة واحدة فقط لقطعة معلومات واحدة، مثل حرف واحد.
  • ب. مرة واحدة فقط لرسالة واحدة.
  • ج. مرة واحدة فقط لفترة زمنية محددة، مثل يوم واحد.
  • د. حتى يظهر دليل على وجود تنصّت.
  1. افترض أن أليس وبوب يختاران قواعد القياس بشكل عشوائي. يقيسان. ثم يتشاركان قواعد قياسيهما ويحتفظان فقط بالبِتّات المعلوماتية من الحالات التي استخدما فيها نفس القاعدة. مع مراعاة بعض التذبذب العشوائي، ما النسبة التقريبية من كيوباتهم التي ينبغي أن تُنتج بِتّات معلومات قابلة للاستخدام؟
  • أ. 100%
  • ب. 50%
  • ج. 25%
  • د. 12.5%
  • هـ. 0%
  1. بعد أن يختار أليس وبوب الحالات التي استخدما فيها نفس قواعد القياس، ما النسبة التي ينبغي أن تتطابق فيها تلك البِتّات، إذا كانت الضوضاء الكمية والأخطاء لا يُعتدّ بها؟
  • أ. 100%
  • ب. 50%
  • ج. 25%
  • د. 12.5%
  • هـ. 0%
  1. افترض أن أليس اختارت قواعد قياسها بشكل عشوائي. تختار إيف أيضاً قواعدها بشكل عشوائي وتتنصّت (تقيس). ترسل إيف حالات إلى بوب تتوافق مع قياساتها. يقارن أليس وبوب اختياراتهما للقواعد ويحتفظان فقط بالكيوبتات التي قاسا/حضّراها في نفس القواعد. مع مراعاة بعض التذبذب العشوائي، ما النسبة التقريبية من تلك القياسات المحفوظة التي ستتطابق وفق أليس وبوب؟
  • أ. 100%
  • ب. 75%
  • ج. 50%
  • د. 25%
  • هـ. 12.5%
  • و. 0%

أسئلة النقاش

  1. افترض أن جميع اختيارات القواعد عشوائية لجميع المشاركين: أليس وبوب وإيف. افترض أنه بعد أن تتنصّت إيف، ترسل إلى بوب حالة محضّرة في نفس القاعدة التي قاست بها وتتوافق مع ذلك القياس. أقنع شركاءك بأن 12.5% من جميع الكيوبتات التي هيّأتها أليس ستُعطي حالات عدم تطابق في القياس بين أليس وبوب، مما يدل على وجود تنصّت (متجاهلاً أخطاء الكم والضوضاء). تلميح 1: نظراً لعدم وجود قاعدة مفضّلة، إذا نظرت إلى اختيار واحد فقط لأليس، فيجب أن تكون النسبة لذلك الاختيار الواحد مساوية للنسبة الإجمالية لجميع الاختيارات. تلميح 2: قد لا يكفي حساب عدد الطرق التي يمكن أن يحدث بها شيء ما، إذ إن بعض النتائج قد تحدث باحتمالات مختلفة.