노트북 02 — 하이브리드 X3DH 키 합의#

새로 생성한 두 신원(identity) 사이에서 하이브리드 핸드셰이크를 실행하고, 양쪽이 동일한 96바이트의 키 자료를 유도하는지 확인합니다.

from pqmsg.identity import generate_identity
from pqmsg.session import initiate_session, accept_session, Handshake

단계 1 — 신원 생성#

alice = generate_identity("alice")
bob   = generate_identity("bob")
print("alice X25519 pub (first 8B):", alice.x25519_public[:8].hex())
print("bob   X25519 pub (first 8B):", bob.x25519_public[:8].hex())
print("alice ML-KEM pub size      :", len(alice.ml_kem_public))
print("bob   ML-KEM pub size      :", len(bob.ml_kem_public))
alice X25519 pub (first 8B): 36f7fc3d734b1626
bob   X25519 pub (first 8B): 90a17827bd896256
alice ML-KEM pub size      : 1184
bob   ML-KEM pub size      : 1184

단계 2 — Alice가 세션 개시#

initiate_session은 X25519 DH, ML-KEM 캡슐화, 그리고 HKDF 유도를 수행합니다.

sess_a, handshake = initiate_session(
    ours=alice, peer_name=bob.name,
    peer_x25519_pub=bob.x25519_public,
    peer_ml_kem_pub=bob.ml_kem_public,
)
print("root_key (first 8B):        ", sess_a.root_key[:8].hex())
print("chain_key_send (first 8B):  ", sess_a.chain_key_send[:8].hex())
print("chain_key_recv (first 8B):  ", sess_a.chain_key_recv[:8].hex())
print("ephemeral_pk size:           ", len(handshake.ephemeral_pk))
print("kem_ciphertext size:         ", len(handshake.kem_ciphertext))
root_key (first 8B):         43d31a03c0a3d06a
chain_key_send (first 8B):   98f3dc07eb3f2e7a
chain_key_recv (first 8B):   b154502f31803a3a
ephemeral_pk size:            32
kem_ciphertext size:          1088

단계 3 — Bob이 세션 수락#

accept_session은 Bob의 개인키와 Alice가 보낸 핸드셰이크 필드를 사용합니다.

sess_b = accept_session(
    ours=bob, peer_name=alice.name,
    peer_x25519_pub=alice.x25519_public,
    handshake=handshake,
)
print("root_key match:        ", sess_a.root_key == sess_b.root_key)
print("chain_a2b mirrored:    ", sess_a.chain_key_send == sess_b.chain_key_recv)
print("chain_b2a mirrored:    ", sess_a.chain_key_recv == sess_b.chain_key_send)
root_key match:         True
chain_a2b mirrored:     True
chain_b2a mirrored:     True

두 줄 모두가 성공해야 하는 이유#

두 체인 키는 방향성을 가집니다: 하나는 Alice→Bob용, 다른 하나는 Bob→Alice용입니다. 이 핸드셰이크 이후, 양 당사자는 독립적으로 암호화하고 상대방은 복호화할 수 있습니다. 다음 노트북에서는 대칭 래칫을 10단계 굴려서 전방 비밀성을 보여주고 — 어디에서 멈추는지도 함께 살펴봅니다.