양자 키 분배
이 Qiskit in Classrooms 모듈을 실행하려면 다음 패키지가 설치된 Python 환경이 필요합니다:
qiskitv2.1.0 이상qiskit-ibm-runtimev0.40.1 이상qiskit-aerv0.17.0 이상qiskit.visualizationnumpypylatexenc
위 패키지의 설정 및 설치 방법은 Qiskit 설치 가이드를 참고하세요. 실제 양자 컴퓨터에서 작업을 실행하려면, IBM Cloud 계정 설정 가이드의 단계를 따라 IBM Quantum® 계정을 만들어야 합니다.
이 모듈은 테스트되었으며 QPU 시간 5초를 사용했습니다. 이는 추정치일 뿐이며, 실제 사용량은 다를 수 있습니다.
# 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'
아래에서 Dr. 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)는 "시저 이동" 암호라고 합니다.
이런 암호들은 메시지가 짧으면 매우 어렵다는 점에 유의하세요. 사실, 매우 짧으면 불확정적입니다. 다음을 생각해 보세요:
URYYP
서로 다른 키를 사용한 많은 가능한 복호화가 있습니다: HELLO, PETTY, HAPPY, JIGGY, STOOL. 다른 것을 생각해낼 수 있나요?
하 지만 이런 메시지를 많이 보내면 결국 암호화가 해독됩니다. 따라서 같은 "키"를 너무 자주 사용해서는 안 됩니다. 사실 가장 좋은 방법은 특정 치환을 단 한 번만 사용하는 것입니다. 단 하나의 메시지에만 사용하는 것이 아니라, 단 하나의 문자에만! 즉, 메시지에서 사용된 각 문자마다 순서대로 암호화 방식 또는 키가 있다는 의미입니다. 이 방식으로 친구에게 메시지를 보내려면 당신과 친구 모두 이 끊임없이 변화하는 키가 적힌 메모지(옛날 방식으로는)가 필요합니다. 이것을 한 번만 사용합니다. 이것을 "일회용 패드"라고 합니다.
일회용 패드
예시를 통해 이것이 어떻게 작동하는지 살펴보겠습니다. 이것은 전적으로 문자로도 할 수 있지만, 예를 들어 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
위 코드를 그대로 보내고 싶지 않습니다. 그것은 단순 치환으로 전혀 안전하지 않습니다. 어떤 방식으로 이것을 키와 결합하고 싶습니다. 일반적인 방법은 26을 법으로 하는 덧셈(modulo 26)입니다. 메시 지 끝에 도달할 때까지 메시지 값에 키 값을 더하고 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
누군가 이것을 가로채고 키를 갖고 있지 않다면 복호화는 전혀 불가능합니다! "quantum"의 두 "u"조차도 같은 숫자로 인코딩되지 않습니다! 첫 번째는 3이고 두 번째는 16입니다… 같은 단어 안에서도요!
그래서 내가 이것을 당신에게 보내면, 당신은 내가 수행한 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".
이것이 일회용 패드입니다.
키가 메시지보다 짧으면 인코딩을 반복하기 시작합니다. 그것도 여전히 어려운 복호화 문제이지만, 충분히 반복되면 불가능하지는 않습니다. 따라서 긴 키(또는 "패드")가 필요합니다.
많은 경우 학생들이 이미 이 암호화에 익숙하여 이 활동을 건너뛸 수 있습니다. 하지만 비교적 빠르고 간단한 복습입니다.
1단계: 짝을 구해서 키로 사용할 4글자 시퀀스를 공유하세요. 수업에 적합한 4글자 시퀀스라면 무엇이든 됩니다.
2단계: 짝에게 보내고 싶은 4글자 비밀 단어를 선택하세요 (두 참여자가 모두 이렇게 해서 서로에게 다른 비밀 단어를 보냅니다)
3단계: 4글자 키/패드와 각 4글자 비밀 단어를 A = 1, B = 2 등을 사용하여 숫자로 변환하세요.
4단계: 4글자 단어를 일회용 패드와 모듈러 26 덧셈을 사용하여 결합하세요.
5단계: 비밀 단어를 인코딩한 숫자 시퀀스를 짝에게 건네주고, 짝도 자신의 것을 당신에게 건네줍니다.
6단계: 모듈러 26 뺄셈을 사용하여 서로의 단어를 복호화하세요.
7단계: 확인하세요. 성공했나요?
후속 활동
일회용 패드에 접근할 수 없는 다른 그룹과 암호화된 단어를 교환해 보세요. 복호화할 수 있나요? 그 이유 또는 이유를 설명하세요.
위 활동을 통해 일회용 패드가 다음과 같은 몇 가지 가정하에 해독 불가능한 암호화 형식임을 이해하셨을 것입니다:
- 키가 전송되는 메시지와 같은 길이이거나 그보다 길다
- 키가 진정으로 무작위이다
- 키가 한 번만 사용되고 폐기된다
정말 훌륭합니다. 우리는 해독 불가능한 암호화를 갖고 있습니다... 누군가 우리의 키를 얻지 않는다면요. 누군가 우리의 키를 얻으면 모든 것이 복호화됩니다. 해독 불가능한 암호화와 모든 비밀이 노출되는 것 사이의 이 차이가 안전한 키 공유를 극도로 중요하게 만듭니다. 양자 키 분배의 목표는 자연이 양자 정보에 부과한 제약을 활용하여 공유 키/일회용 패드를 보호하는 것입니다.
양자 상태를 키로 활용하기
큐비트(qubit에는 두 개의 고유 상태가 있음을 강조)를 사용한다고 가정해 보겠습니다. 더 많은 양자 상태를 가진 양자 시스템을 사용할 수도 있지만, IBM®의 최첨단 양자 컴퓨터는 Qubit을 사용합니다. A, B, C를 0과 1의 시퀀스로 인코딩하는 것은 전혀 문제가 없습니다. 따라서 0과 1로 이루어진 키를 공유하고, 각 비트에 대해 모듈로 2 덧셈을 수행하면 충분합니다.
이해도 확인
아래 질문을 읽고 답을 생각해 본 후, 삼각형을 클릭하여 정답을 확인하세요.
영어 알파벳만 다룬다면, 몇 비트가 필요할까요?
정답:
앨리스(Alice)와 밥(Bob)은 다른 누구도 가로챌 수 없는 방식으로 양자 키를 공유하고 싶어 합니다(적어도 가로채더라도 알 수 있도록). 두 사람은 서로에게 양자 상태를 전송할 방법이 필요합니다. 높은 정밀도와 잡음·오류 없이 이를 수행하는 것은 결코 간단하지 않습니다. 하지만 현 시점에서 이해할 수 있는 두 가지 접근 방식이 있습니다.
- 광섬유 케이블을 이용하면 빛을 전송할 수 있습니다… 빛은 매우 양자역학적입니다. 단일 광자는 수십 킬로미터에 달하는 광섬유 케이블을 통해 높은 정밀도로 검출될 수 있습니다. 이것은 완벽하고 오류 없는 양자 채널은 아니지만, 매우 우수할 수 있습니다.
- 이전 모듈에서 설명한 양자 텔레포테이션을 사용할 수 있습니다. 즉, 앨리스와 밥이 얽힌 Qubit을 공유하고, 텔레포테이션 프로토콜을 이용해 앨리스에서 밥으로 상태를 전송할 수 있습니다.
이 모듈에서는 광자를 공유하기 위한 고정밀 광학 장치를 갖추도록 요구하지 않으므로, 양자 상태를 공유하는 두 번째 방법을 사용합니다. 그렇다고 이 방법이 장거리 양자 키 공유에 가장 현실적이라는 의미는 아닙니다.
이제 1984년 Charles Bennett과 Gilles Brassard가 처음 제안한 프로토콜을 살펴보겠습니다. 이 프로토콜은 앨리스에서 밥으로 서로 다른 기저(basis)에서 측정된 상태를 공유하는 방법입니다. 영리한 측정 방식을 사용하여 나중에 암호화에 사용할 키를 구축합니다. 다시 말해, 통신을 원하는 두 당사자 사이에 양자 키를 분배하는 것이며, 이를 "양자 키 분배(QKD, Quantum Key Distribution)"라고 합니다.
QKD 1단계: 앨리스의 무작위 비트와 무작위 기저
앨리스는 먼저 0과 1의 무작위 시퀀스를 생성합니다. 그런 다음, 아래 표(밥도 공유하는 표)를 사용하여 각 무작위 비트에 따라 양자 상태를 준비할 기저를 무작위로 선택합니다.
| 기저 | 비트 = 0 | 비트 = 1 |
|---|---|---|
| Z | ||
| X |
예를 들어, 앨리스가 무작위로 0을 생성하고 X 기저를 무작위로 선택했다면, 양자 상태 을 준비합니다. 양자 무작위성을 활용하여 무작위 0과 1 집합 및 무작위 기저 선택을 생성할 수 있습니다. 지금은 다음과 같이 무작위 집합이 생성되었다고 가정합니다.
| 앨리스의 비트 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | ... |
|---|---|---|---|---|---|---|---|---|---|---|
| 앨리스의 기저 | X | X | Z | Z | Z | X | Z | Z | X | ... |
| 앨리스의 상태 | ... |
이 무작위 비트, 기저, 결과 상태의 집합은 충분한 길이의 키를 얻기 위해 긴 시퀀스로 계속됩니다.
QKD 2단계: 밥의 무작위 기저
밥도 무작위로 기저를 선택합니다. 하지만 앨리스가 기저 선택을 상태 준비에 사용한 반면, 밥은 이 기저로 실제 측정을 수행합니다. 밥이 앨리스가 상태를 준비한 것과 동일한 기저에서 측정하면, 밥의 측정 결과를 예측할 수 있습니다. 밥이 앨리스의 준비 기저와 다른 기저를 선택하면, 밥의 측정 결과를 알 수 없습니다.
| 앨리스의 비트 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | ... |
|---|---|---|---|---|---|---|---|---|---|---|
| 앨리스의 기저 | X | X | Z | Z | Z | X | Z | Z | X | ... |
| 앨리스의 상태 | ... | |||||||||
| 밥의 기저 | X | Z | X | Z | X | X | Z | X | X | ... |
| 밥의 상태 (사전 예측) | ? | ? | ? | ? | ... | |||||
| 밥의 상태 (측정 결과) | ... | |||||||||
| 아래 표에서 첫 번째 열을 살펴보겠습니다. 앨리스는 X의 고유 상태인 을 준비했습니다. 밥도 무작위로 X 기저에서 측정하기로 선택했으므로, 밥의 측정 상태로 가능한 결과는 단 하나입니다: . 그러나 두 번째 열에서는 서로 다른 기저를 선택했습니다. 앨리스가 보낸 상태는 입니다. 이 상태는 밥이 Z 기저에서 측정할 때 상태로 측정될 확률이 50%, 로 측정될 확률이 50%입니다. 따라서 밥의 측정에 대해 사전에 알 수 있는 내용을 보여주는 행은 2열을 채울 수 없습니다. 하지만 밥은 측정을 수행하여 (그 열에서) Z의 고유 상태를 얻게 됩니다. 마지막 행에는 이 측정에서 실제로 얻은 결과를 채워 넣습니다. |
QKD 3단계: 기저에 대한 공개 논의
앨리스와 밥은 이제 각 경우에 선택한 기저를 서로 공유할 수 있습니다. 두 사람이 같은 기저를 선택한 모든 열에서, 각자는 상대방이 어떤 상태를 가졌는지 확실히 알 수 있습니다. 밥은 두 당사자가 공유하는 규약에 따라 상태와 기저를 0 또는 1로 변환할 수 있습니다. 앨리스와 밥의 기저가 일치한 경우만 남도록 위 표를 다시 작성할 수 있습니다.
| 앨리스의 비트 | 0 | 0 | 1 | 0 | 0 | ... |
|---|---|---|---|---|---|---|
| 앨리스의 기저 | X | Z | X | Z | X | ... |
| 앨리스의 상태 | ... | |||||
| 밥의 기저 | X | Z | X | Z | X | X |
| 밥의 상태 (사전 예측) | ... | |||||
| 밥의 상태 (측정 결과) | ... | |||||
| 밥의 비트 | 0 | 0 | 1 | 0 | 0 | ... |
앨리스는 비트 문자열 00100...을 밥에게 성공적으로 전송했습니다. 만약 두 친구가 일회용 패드의 숫자에 5비트 문자열을 사용하기로 미리 합의했다면, 처음 다섯 비트는 이라는 숫자를 제공합니다.
QKD 4단계: 검증 및 비밀 전송
앨리스와 밥은 더 진행하기 전에, 고전적 비트 중 일부를 선택하여 비교해야 합니다. 두 사람은 같은 기저로 준비하고 측정된 Qubit의 측정값만 보존했으므로, 모든 측정값이 일치해야 합니다. 일치하지 않는 비율이 아주 작다면, 이는 양자 잡음이나 오류로 인한 것일 수 있습니다. 하지만 많은 수가 일치하지 않는다면, 무언가 잘못된 것입니다!
여기서는 키의 어느 비율을 검증에 사용해야 하는지는 다루지 않겠습니다. 지금은 이 검사가 잘 통과된다고 가정하겠으며, 아래의 도청 관련 절에서 다시 살펴보겠습니다.
그런 다음 두 친구는 고전적 채널을 통해 서로 암호화된 메시지를 전송합니다. 일회용 패드의 숫자를 사용하여 비밀 메시지를 암호화하거나 복호화하되, 일회용 패드 자체는 한 곳에서 다른 곳으로 전송하지 않습니다. 도청에 관한 다음 절을 위해, 이 키 공유 과정이 모두 고전적 채널을 통해 암호화된 비밀을 공개하기 이전에 이루어진다는 점을 기억해 두세요.
앨리스와 밥은 고전적 채널을 통해 선택한 기저를 전달했는데, 그것도 가로챌 수 있지 않을까요? 맞습니다! 하지만 그들이 측정에 사용한 기저를 알아도 그들이 보내거나 얻은 비트가 무엇인지는 알 수 없습니다. 그것은 앨리스의 초기 비트도 알아야만 가능한 일입니다. 그렇다면 앨리스의 컴퓨터에 이미 접근한 것이므로, 비밀의 안전한 통신 자체가 의미 없어집니다. 따라서 고전적 통신의 가로채기는 암호화를 깨지 못합니다. 그렇다면 양자 채널의 정보를 가로채는 경우는 어떨까요?
도청에 대한 QKD의 저항성
Alice와 Bob에게는 도청으로 악명 높은 친구 Eve가 있습니다. Eve는 Alice와 Bob의 양자 키를 가로채서 두 사람 사이에 전송되는 메시지를 해독하는 데 사용하려 합니다. 이 도청은 반드시 Alice가 상태를 준비한 후, Bob이 상태를 측정하기 전 사이에 이루어져야 합니다. 측정이 이루어지면 양자 상태가 붕괴되기 때문입니다. 특히, 이 도청은 기저(basis)가 공유 되거나 비교되기 전에 발생해야 합니다.
Eve는 각 비트를 인코딩하는 데 사용된 기저를 추측해야 합니다. Alice의 컴퓨터에 접근할 수 없다면, 추측의 근거가 없으므로 무작위로 선택할 수밖에 없습니다. Alice의 시작 상태가 이전과 동일하고, Bob의 무작위 측정 기저 선택도 이전과 동일하다고 가정합시다. Eve가 양자 채널을 측정하여 얻는 값을 표에 채워 봅시다. 이전과 마찬가지로, Eve가 Alice와 동일한 기저를 선택한 경우에는 결과를 알 수 있습니다. 그렇지 않은 경우에는 두 가지 결과 중 하나가 각각 50% 확률로 나올 수 있습니다.
| Alice의 비트 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | ... |
|---|---|---|---|---|---|---|---|---|---|---|
| Alice의 기저 | X | X | Z | Z | Z | X | Z | Z | X | ... |
| Alice의 상태 | ... | |||||||||
| Eve의 추측 기저 | Z | X | X | Z | X | Z | Z | X | X | ... |
| Eve의 상태 (사전 정보) | ? | ? | ? | ? | ? | ... | ||||
| Eve의 상태 (측정값) | ... | |||||||||
| Bob의 기저 | X | Z | X | Z | X | X | Z | X | X | ... |
이제 Eve는 자신이 Alice의 기저와 일치했는지 여부를 알 수 없으므로, Alice의 원래 상태와 일치하도록 Bob에게 무엇을 전달해야 할지 알 수 없습니다. 예를 들어 Eve가 을 측정한 경우, 확실히 알 수 있는 것은 Alice가 해당 Qubit에 대해 상태를 준비하지 않았다는 것뿐입니다. 하지만 Alice는 , , 중 하나를 준비했을 수 있으며, 모두 Eve의 측정 결과와 일치할 수 있습니다. 따라서 Eve는 선택을 해야 합니다. 자신이 측정한 상태를 그대로 전달하거나, 자신의 측정값이 Alice가 전송한 고유 상태(eigenstate)가 아닐 것으로 추측해 볼 수도 있습니다. 아래 표에는 두 경우가 혼합되어 있습니다:
| Alice의 비트 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | ... |
|---|---|---|---|---|---|---|---|---|---|---|
| Alice의 기저 | X | X | Z | Z | Z | X | Z | Z | X | ... |
| Alice의 상태 | ... | |||||||||
| Eve의 추측 기저 | Z | X | X | Z | X | Z | Z | X | X | ... |
| Eve의 상태 (사전 정보) | ? | ? | ? | ? | ? | ... | ||||
| Eve의 상태 (측정값) | ... | |||||||||
| Eve의 상태 (전달값) | ... | |||||||||
| Bob의 기저 | X | Z | X | Z | X | X | Z | X | X | ... |
| Bob의 상태 (사전 정보) | ? | ? | ... | |||||||
| Bob의 상태 (측정값) | ... | |||||||||
| Bob의 비트 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | ... |
이 시점에서 "Eve가 Alice의 양자 상태를 복사하여 하나는 자신이 측정하고, 다른 하나를 Bob에게 전달하면 되지 않을까?"라는 질문이 자연스럽게 생길 수 있습니다. 그 답은 "복제 불가 정리(no-cloning theorem)"에 있습니다. 비공식적으로 설명하면, 임의의 양자 상태를 원본을 보존하면서 두 번째 복사본으로 만들 수 있는 유니터리(양자역학적) 연산은 존재하지 않는다는 것입니다. 증명은 비교적 간단하며 안내된 연습 문제로 남겨 두겠습니다. 하지만 지금은 Eve가 양자 상태를 복사하는 것이 자연의 근본 법칙에 의해 금지되어 있다는 점을 이해하세요. 이것이 QKD의 핵심적인 강점입니다.
이전과 마찬가지로, Alice와 Bob은 서로 통화하여 기저를 비교합니다. 두 사람이 동일한 기저를 선택한 경우만 남기면 위의 표를 다음과 같이 줄일 수 있습니다:
| Alice의 비트 | 0 | 0 | 1 | 0 | 0 | ... |
|---|---|---|---|---|---|---|
| Alice의 기저 | X | Z | X | Z | X | ... |
| Alice의 상태 | ... | |||||
| Eve의 추측 기저 | Z | Z | Z | Z | X | ... |
| Eve의 상태 (사전 정보) | ? | ? | ... | |||
| Eve의 상태 (측정값) | ... | |||||
| Eve의 상태 (전달값) | ... | |||||
| Bob의 기저 | X | Z | X | Z | X | ... |
| Bob의 상태 (사전 정보) | ? | ... | ||||
| Bob의 상태 (측정값) | ... | |||||
| Bob의 비트 | 1 | 0 | 0 | 0 | 0 | ... |
Alice와 Bob은 다시 한번 비트 문자열을 주고받았지만... 문자열이 일치하지 않습니다. 맨 왼쪽 비트와 가운데 비트가 뒤바뀌어 있습니다. 앞의 표를 살펴보면 이 불일치가 Eve의 개입에서 비롯되었음을 추적할 수 있습니다. 중요한 점은, 암호화된 비밀을 공유하기 훨씬 전인 키 설정 단계에서 비트 문자열의 일치 여부에 대한 통계를 낼 수 있다는 것입니다. Alice와 Bob은 채널의 보안을 확인하기 위해 원하는 만큼 원타임 패드 비트를 사용할 수 있습니다. 단 하나의 비트 또는 아주 작은 비율의 비트가 일치하지 않는다면 잡음이나 오류 때문일 수 있습니다. 하지만 상당한 비율의 불일치는 도청이 있었음을 나타냅니다. 여기서 "상당한"의 의미는 사용하는 설정의 잡음 수준에 따라 달라집니다. IBM® 양자 컴퓨터의 경우에 어떤 의미인지는 이 프로토콜을 구현할 때 아래에서 설명합니다. 과도한 오류가 감지되면 Alice와 Bob은 비밀을 공유하지 않고 도청자를 찾아 나설 수 있습니다.
주의사항
보안을 증명하는 것은 매우 어렵습니다. 사실 여기서 느슨하게 설명한 프로토콜은 1984년에 제안되었지만, 16년이 지난 후에야 비로소 안전성이 증명되었습니다 Shor & Preskill, 2000. 이 입문 내용의 범위를 넘어서는 많은 미묘한 사항들이 있습니다. 하지만 주제가 여기서 설명된 것보다 훨씬 복잡하다는 것을 보여주기 위해 몇 가지를 간략히 나열하겠습니다.
- 안전한 채널: Alice가 어떤 양자 설정(채널)을 통해 Qubit을 전송하고, 특히 누군가로부터 고전적인 응답을 받을 때, 우리는 그 누군가가 실제로 Bob이라고 가정합니다. 만약 Eve가 이 설정에 침투하여 Alice의 모든 통신이 실제로는 Eve와 이루어지고, Bob의 모든 통신도 실제로는 Eve와 이루어진다면, Eve는 사실상 키를 획득하여 비밀을 알 수 있게 됩니다. 여기서 다루지 않은 별도의 프로토콜 집합인 "안전한 채널" 확보 과정을 먼저 진행해야 합니다.
- Eve에 대한 가정: 보안을 진정으로 증명하기 위해서는 Eve의 행동에 대해 어떠한 가정도 할 수 없습니다. Eve는 언제든지 우리의 예상을 뒤엎을 수 있습니다. 여기서는 구체적인 예를 들기 위해 가정을 두고 있습니다. 예를 들어, Eve가 Bob에게 전달하는 상태는 항상 자신이 측정하여 얻은 상태와 정확히 같다고 가정할 수 있습니다. 또는 자신의 측정과 실험적으로 일치하는 상태를 무작위로 선택한다고 가정할 수도 있습니다. 더 근본적으로, 여기서 사용하는 언어는 Eve가 실제로 측정을 수행한다고 가정하고 있으며, 상태를 다른 양자 시스템에 저장하고 Bob에게 임의의 Qubit을 전달하는 경우는 고려하지 않습니다. 이러한 가정들은 프로토콜을 이해하는 데는 적합하지만, 완전한 일반성에서 어떤 것도 증명하지 않는다는 의미이기도 합니다.
- 프라이버시 증폭: Alice와 Bob은 양자 키를 전송된 그대로 사용할 필요가 없습니다. 예를 들어, 공유된 키에 해시 함수를 적용할 수 있습니다. 이는 도청자가 키에 대한 불완전한 정보만 갖고 있다는 사실을 활용하여 더 짧지만 안전한 공유 키를 생성하는 방법입니다.
실험 1: 도청자가 없는 QKD
위의 프로토콜을 도청자가 없는 상황에서 구현해 보겠습니다. 먼저 시뮬레이터를 사용하여 전체 워크플로를 이해해 보겠습니다.
먼저 양자 시뮬레이터에 대해 한 가지 짚어두겠습니다. 큐비트 수가 ~30개를 초과하는 대부분의 양자 문제는 일반 컴퓨터로 시뮬레이션하기가 어렵습니다. 클래식 컴퓨터, 슈퍼컴퓨터, GPU 중 어느 것도 127큐비트 양자 컴퓨터의 전체 동작을 시뮬레이션할 수 없습니다. 보통 실제 양자 컴퓨터를 사용하는 이유는 얽힌 큐비트들이 시뮬레이션될 수 없기 때문입니다. 이 경우에는 큐비트 간 얽힘이 없습니다(텔레포테이션 방식으로 정보를 전달하지 않는 한). 실제 양자 컴퓨터를 사용하는 이유는 노-클로닝 정리(no-cloning theorem) 때문입니다. 큐비트를 시뮬레이션하는 클래식 컴퓨터는 양자 상태에 대한 정보를 앨리스에서 밥에게 전달할 수 있지만, 그 클래식 정보가 도중에 가로채이면 쉽게 복제될 수 있어 이브가 완전한 사본을 보관하면서 다른 사본을 밥에게 전달할 수 있습니다. 하지만 실제 양자 상태에서는 이것이 불가능합니다.
IBM Quantum에서는 "Qiskit 패턴(Qiskit patterns)"이라는 프레임워크를 통해 양자 컴퓨팅 문제를 다루길 권장합니다. 이 프레임워크는 다음과 같은 단계로 구성됩니다.
- 1단계: 문제를 양자 Circuit으로 매핑하기
- 2단계: 실제 양자 하드웨어에서 실행할 수 있도록 Circuit 최적화하기
- 3단계: Runtime 기본 요소(primitives)를 사용하여 IBM 양자 컴퓨터에서 작업 실행하기
- 4단계: 결과 후처리하기
Qiskit 패턴 1단계: 문제를 양자 Circuit으로 매핑하기
이 경우, 문제를 양자 Circuit으로 매핑하는 작업은 앨리스의 상태를 준비하고 밥의 측정을 포함하는 것으로 단순화됩니다. 먼저 무작위 비트와 무작위 기저를 선택합니다.
# 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)
비트, 기저, Circuit을 시각화해 보겠습니다. 기저가 일치하는 경우와 그렇지 않은 경우가 있음을 주목하세요.
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.]
Qiskit 패턴 2단계: 양자 실행을 위한 문제 최적화하기
이 단계에서는 수행하려는 연산을 특정 양자 컴퓨터의 기능에 맞게 표현하고, 문제를 양자 컴퓨터의 레이아웃에 매핑합니다.
먼저 IBM 양자 컴퓨터와 통신하는 데 필요한 여러 패키지를 불러옵니다. 또한 실행할 Backend를 선택해야 합니다. 가장 여유 있는 Backend를 선택하거나, 속성을 알고 있는 특정 Backend를 선택할 수 있습니다. 당장은 시뮬레이터를 사용하더라도, 합리적인 노이즈 모델을 사용하는 것이 중요하며, 나중에 실제 양자 컴퓨터에서 사용할 워크플로와 최대한 동일하게 유지하는 것이 좋습니다.
아래에는 처음 사용 시 자격 증명을 저장하는 코드가 있습니다. 자격 증명을 환경에 저장한 후에는 반드시 해당 정보를 노트북에서 삭제하여 노트북 공유 시 자격 증명이 실수로 노출되지 않도록 하세요. 자세한 내용은 IBM Cloud 계정 설정 및 신뢰할 수 없는 환경에서 서비스 초기화하기를 참고하세요.
# 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를 사용하여 Circuit을 인수로 전달하고 작업을 실행합니다.
# 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단계: 후처리하기
여기서는 결과를 해석하고 유용한 정보를 추출합니다. Sampler의 출력을 시각화해 볼 수도 있지만, 이번에는 Sampler를 일반적이지 않은 방식으로 사용했습니다. Circuit에 대한 여러 번의 측정으로 상태 통계를 구하는 대신, 한 번의 측정(밥의 측정)만 수행했습니다. 동일한 기저로 준비되고 측정된 큐비트는 결정론적 결과를 가지므로 한 번의 측정으로 충분합니다. 다른 기저로 준비되고 측정된 큐비트(확률적 결과를 가지며 해석을 위해 여러 번의 측정이 필요한)는 원타임 패드/키를 구성하는 데 사용되지 않습니다.
이 비트 문자열에서 측정 결과 목록을 추출해 보겠습니다. Circuit 생성에 사용한 앨리스의 비트 배열과 비교할 때 순서를 뒤집어야 합니다.
# 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]
앨리스와 밥이 무작위로 선택한 측정 기저를 비교해 보겠습니다. 이것이 QKD 프로토콜의 3단계(기저 공개 논의)입니다. 특정 큐비트에 대해 동일한 기저를 선택한 경우, 해당 큐비트와 연관된 비트를 원타임 패드의 숫자를 생성하기 위한 비트 목록에 추가합니다. 기저가 일치하지 않는 경우에는 결과를 버립니다. 또한 두 비트 목록이 일치하는지, 혹은 노이즈나 기타 요인으로 인한 손실이 있는지 확인해 보겠습니다.
# 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% 충실도로 일치합니다. 이 비트들을 원타임 패드의 숫자를 생성하는 데 활용할 수 있습니다. 그런 다음 QKD 4단계인 비밀 전송 및 복호화에 사용할 수 있습니다. 현재 비트 배열은 너무 짧아 실질적인 복호화에는 부족합니다. 도청 내용을 포함한 이후 내용에서 다시 다루겠습니다.
이해도 확인
아래 질문을 읽고 답을 생각해 본 다음, 삼각형을 클릭하여 정답을 확인하세요.
영어 알파벳 전체 길이만큼 문자를 이동시킬 수 있을 만큼 충분히 큰 숫자가 필요하다고 가정하세요. 물론 다른 인코딩 방식도 있을 수 있습니다.
(a) 위의 키에 있는 비트들을 이용하여 메시지는 최대 몇 글자까지 복호화할 수 있나요? (b) 여러분의 답이 동급 학우의 답과 반드시 일치해야 하나요? 왜 그런가요, 혹은 왜 그렇지 않나요?
정답:
(a) 답은 앨리스와 밥이 일치하도록 무작위 선택한 기저의 수에 따라 달라집니다. 임의의 큐비트에 대해 기저가 일치할 확률이 대략 50 대 50이므로, 유효한 비트의 수는 약 10개 정도일 것으로 예상됩니다. 9개나 11개도 충분히 가능하며, 4개나 15개도 불가능한 범위는 아닙니다. 영어 알파벳 길이보다 크거나 같은 이동값을 적용하려면 5비트가 필요하므로, 5비트마다 한 글자에 이동값을 적용할 수 있습니다. 앨리스와 밥이 최소 5비트를 공유하면 한 글자를 인코딩할 수 있고, 최소 10비트를 공유하면 두 글자를 인코딩할 수 있으며, 이후도 마찬가지입니다. (b) (a)에서 설명한 이유로 반드시 일치할 필요는 없습니다.
실험 2: 도청자가 있는 QKD
앞서와 완전히 동일한 프로토콜을 구현합니다. 이번에는 Alice와 Bob 사이에 Eve의 측정을 추가합니다.
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 patterns 4단계(후처리)는 간단합니다. 단 한 번의 측정만 수행했으므로 측정 분포를 시각화할 필요가 없습니다. Eve가 획득한 비트는 다음과 같습니다.
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]
이제 Eve는 Bob에게 전달할 양자 상태를 재구성해야 합니다. 앞서 소개에서 설명했듯이, Eve는 자신이 인코딩 기저를 올바르게 추측했는지 알 수 없으므로 Alice가 전송한 것과 정확히 동일한 상태를 준비할 수 없습니다. Eve는 모든 기저 선택이 정확했다고 가정하여 자신이 측정한 것을 그대로 인코딩하거나, 반대 기저의 고유 상태(eigenstate) 중 하나를 선택할 수도 있습니다. 여기서는 단순화를 위해 전자를 가정합니다. 이를 위해 새로운 양자 Circuit을 구성하고 앞서와 동일하게 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]
이제 Alice와 Bob의 비트를 비교해 보겠습니다.
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
이전에는 Alice와 Bob의 키 비트가 완벽하게 일치했습니다. 하지만 이번에는 Eve의 도청으로 인해, Alice와 Bob이 동일한 기저를 선택한 경우임에도 불구하고 비트가 14%의 경우에서 다르게 나타납니다. Alice와 Bob은 이를 쉽게 감지할 수 있습니다. 다만, 이와 같이 오류율에 의존한다는 것은 양자 채널에서 허용할 수 있는 노이즈의 한계가 있음을 의미합니다.
실험 3: 실제 양자 컴퓨터에서 도청 유무에 따른 QKD 비교
실제 양자 컴퓨터에서 실행해 보겠습니다. 이렇게 하면 복제 불가 정리(no-cloning theorem)를 실제로 활용할 수 있습니다. 동시에 실제 양자 컴퓨터는 노이즈가 존재하고 오류율이 고전 컴퓨터보다 높습니다. 따라서 도청 유무에 따른 키 비트 충실도(fidelity) 손실을 비교하여, 실제 양자 컴퓨터를 사용할 때 그 차이를 감지할 수 있는지 확인해 보겠습니다. 먼저 도청이 없는 경우부터 시작합니다.
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
도청이 없는 경우, 127개의 시험 비트에서 55개의 기저가 일치하여 사용 가능한 키 비트가 생성되었으며, 충실도는 100%를 기록했습니다. 이번에는 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
도청으로 인해 공유 비트의 충실도가 약 23% 손실된 것을 확인했습니다! 이는 매우 명확하게 감지할 수 있는 수준입니다. 물론 장거리에서 양자 정보를 전송할 경우 추가적인 노이즈와 오류가 발생할 수 있습니다. 노이즈가 존재하는 환경에서, 그리고 Eve가 모든 수단을 동원하더라도 도청을 감지할 수 있음을 보장하는 것은 이 입문 과정의 범위를 넘어서는 복잡한 분야입니다.
질문
강사는 이 노트북의 답안지 및 일반 교육과정 내 배치 가이드를 요청하려면 노트북 사용 방식에 관한 이 간단한 설문을 작성해 주세요.
핵심 개념
- 양자 정보는 복사하거나 "복제"할 수 없습니다.
- 동일한 준비 과정을 반복하여 모두 같 거나 거의 같은 양자 상태의 앙상블을 만들 수는 있습니다.
- 암호화/복호화 키(일회용 패드)는 양자 상태를 이용해 두 사람 사이에서 공유할 수 있습니다.
- 두 사람이 측정 기저를 무작위로 선택하면 절반 정도는 서로 다른 기저를 선택하게 되어 해당 Qubit의 정보는 버려야 합니다.
- 측정 기저를 무작위로 선택하면 도청자가 준비된 초기 상태를 알 수 없어 전송된 상태를 재현할 수 없습니다. 이로 인해 도청 행위가 반드시 탐지됩니다.
참/거짓(T/F) 문제
- T/F 양자 키 분배에서 통신하는 두 당사자는 각 Qubit을 같은 기저로 측정합니다.
- T/F QKD에서 양자 정보를 가로채는 도청자는 자연 법칙에 의해 가로챈 양자 상태를 복사할 수 없습니다.
- T/F 일회용 패드는 특정 암호화 방식을 알파벳 한 글자처럼 단 하나의 정보에만 한 번씩 사용하는 암호화/복호화 키입니다.
객관식(MC) 문제
- 다음 중 이 모듈에서 설명한 일회용 패드에 관한 설명을 가장 잘 완성하는 것을 고르세요. 일회용 패드는 암호화/복호화 키 집합으로서...
- a. 한 글자처럼 단 하나의 정보에 대해 한 번만 사용됩니다.
- b. 단 하나의 메시지에 대해 한 번만 사용됩니다.
- c. 하루와 같이 정해진 기간 동안 한 번만 사용됩니다.
- d. 도청의 증거가 발견될 때까지 사용됩니다.
- Alice와 Bob이 측정 기저를 무작위로 선택한다고 가정합니다. 측정 후 서로 기저를 공유하고, 같은 기저를 사용한 경우의 정보만 남깁니다. 무작위 변동을 감안할 때, Qubit 중 약 몇 퍼센트가 사용 가능한 비트를 산출할까요?
- a. 100%
- b. 50%
- c. 25%
- d. 12.5%
- e. 0%
- Alice와 Bob이 같은 측정 기저를 사용한 경우만 선별한 후, 양자 잡음과 오류가 무시할 수 있을 정도라면 해당 비트 정보 중 몇 퍼센트가 일치해야 할까요?
- a. 100%
- b. 50%
- c. 25%
- d. 12.5%
- e. 0%
- Alice가 측정 기저를 무작위로 선택했다고 가정합니다. Eve도 기저를 무작위로 선택하여 도청(측정)합니다. Eve는 자신의 측정 결과와 일치하는 상태를 Bob에게 전송합니다. Alice와 Bob이 기저를 비교하여 둘 다 같은 기저를 사용한 Qubit만 남길 때, 무작위 변동을 감안하면 남겨진 Qubit 측정값 중 Alice와 Bob이 일치하는 비율은 약 몇 퍼센트일까요?
- a. 100%
- b. 75%
- c. 50%
- d. 25%
- e. 12.5%
- f. 0%
토론 문제
-
Alice, Bob, Eve 모두 기저를 무작위로 선택한다고 가정합니다. Eve가 도청한 후, 자신이 측정한 기저로 준비한 상태 중 해당 측정 결과와 일치하는 상태를 Bob에게 전송한다고 가정합니다. Alice가 초기화한 전체 Qubit 중 12.5%가 Alice와 Bob 사이에서 측정 불일치를 일으켜 도청을 나타낸다는 것을 파트너들에게 설득해 보세요(양자 오류 및 잡음은 무시합니다). 힌트 1: 선호하는 기저가 없으므로, Alice의 초기 선택 하나를 고려했을 때의 비율이 모든 선택을 합산한 비율과 같아야 합니다. 힌트 2: 일부 결과는 서로 다른 확률로 발생할 수 있으므로, 단순히 경우의 수를 세는 것만으로는 충분하지 않을 수 있습니다.
-
다시 Alice, Bob, Eve 모두 기저를 무작위로 선택한다고 가정합니다. 이번에는 Eve가 측정 후 어떤 상태든 자유롭게 전송할 수 있다고 합니다. 자신의 측정 결과와 일치하지 않는 상태를 전송하는 것도 가능합니다. Eve가 어떤 기저를 선택하더라도 Alice와 Bob에게 도청을 나타내는 Qubit의 평균 비율을 줄일 수 있는지 파트너/이웃과 토론해 보세요.