<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>ECC on kenji.blog</title><link>http://kenji.blog/ko/tags/ecc/</link><description>Recent content in ECC on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ko</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 10:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ko/tags/ecc/index.xml" rel="self" type="application/rss+xml"/><item><title>타원곡선 암호(ECC)의 수학적 기초와 C++에서의 구현</title><link>http://kenji.blog/ko/p/elliptic-curve-cryptography-math-cpp/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/ko/p/elliptic-curve-cryptography-math-cpp/</guid><description>&lt;img src="http://kenji.blog/p/elliptic-curve-cryptography-math-cpp/img/eyecatch.jpg" alt="Featured image of post 타원곡선 암호(ECC)의 수학적 기초와 C++에서의 구현" />&lt;h1 id="타원곡선-암호ecc의-수학적-기초와-c에서의-구현">타원곡선 암호(ECC)의 수학적 기초와 C++에서의 구현
&lt;/h1>&lt;p>현대 암호 기술에서 **타원곡선 암호(Elliptic Curve Cryptography: ECC)**는 매우 중요한 역할을 담당하고 있습니다. 우리의 일상적인 인터넷 통신(HTTPS/TLS)부터 스마트폰의 보안 엔클레이브(Secure Enclave), SSH를 통한 서버 인증, FIDO와 같은 패스워드리스 인증, 심지어 비트코인이나 이더리움과 같은 암호화폐에 이르기까지 현대 디지털 사회의 신뢰 기반은 ECC에 의해 지탱되고 있다고 해도 과언이 아닙니다.&lt;/p>
&lt;p>본 기사에서는 이 타원곡선 암호가 어떻게 기능하는지, 그 이면에 있는 아름답고도 난해한 수학적 이론(유한체 상의 대수기하학)에서 출발하여 실제 C++를 이용한 구현 방법, 나아가 부채널 공격(타이밍 공격)을 방지하기 위한 안전한 코딩 기법까지 압도적인 분량으로 철저하게 해설합니다.&lt;/p>
&lt;hr>
&lt;h2 id="1-왜-타원곡선-암호인가-rsa와의-비교">1. 왜 타원곡선 암호인가? (RSA와의 비교)
&lt;/h2>&lt;p>공개키 암호 방식의 대명사라고 하면 오랫동안 &lt;strong>RSA 암호&lt;/strong>를 떠올렸습니다. RSA 암호는 &amp;lsquo;거대한 합성수의 소인수분해의 어려움&amp;rsquo;을 안전성의 근거로 삼고 있습니다. 하지만 컴퓨터의 계산 능력이 향상됨에 따라 안전성을 유지하기 위해서는 RSA의 키 길이(모듈러스의 비트 수)를 지속적으로 늘려야 할 필요성이 생겼습니다. 현재는 최소 2048비트, 더 안전을 기한다면 3072비트나 4096비트의 키 길이가 권장되고 있습니다.&lt;/p>
&lt;p>이에 반해, 타원곡선 암호(ECC)는 **&amp;lsquo;타원곡선 상의 이산대수 문제(ECDLP)&amp;rsquo;**라는 또 다른 수학적 어려움을 안전성의 근거로 삼고 있습니다. ECDLP를 풀기 위한 효율적인 알고리즘(준지수 시간 알고리즘 등)은 현재까지 발견되지 않았으며, 알려진 가장 효율적인 공격 기법조차도 지수 함수적인 시간을 필요로 합니다.&lt;/p>
&lt;p>이러한 성질로 인해 ECC는 &lt;strong>매우 짧은 키 길이로 RSA와 동등한 보안 강도를 구현할 수 있다&lt;/strong>는 결정적인 장점을 가집니다.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">보안 강도(비트)&lt;/th>
&lt;th style="text-align:center">RSA 암호의 키 길이(비트)&lt;/th>
&lt;th style="text-align:center">타원곡선 암호의 키 길이(비트)&lt;/th>
&lt;th style="text-align:center">키 길이 비율&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">80&lt;/td>
&lt;td style="text-align:center">1024&lt;/td>
&lt;td style="text-align:center">160&lt;/td>
&lt;td style="text-align:center">1:6&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">112&lt;/td>
&lt;td style="text-align:center">2048&lt;/td>
&lt;td style="text-align:center">224&lt;/td>
&lt;td style="text-align:center">1:9&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">128&lt;/td>
&lt;td style="text-align:center">3072&lt;/td>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">1:12&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">192&lt;/td>
&lt;td style="text-align:center">7680&lt;/td>
&lt;td style="text-align:center">384&lt;/td>
&lt;td style="text-align:center">1:20&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">256&lt;/td>
&lt;td style="text-align:center">15360&lt;/td>
&lt;td style="text-align:center">512&lt;/td>
&lt;td style="text-align:center">1:30&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>위의 표에서 알 수 있듯이, 128비트의 보안 강도(현재 표준적인 강도)를 얻기 위해 RSA에서는 3072비트의 키가 필요하지만, ECC라면 단 256비트면 충분합니다. 이를 통해 계산량 감소, 메모리 사용량 절감, 네트워크 대역폭 절약이 가능해지며, 특히 리소스가 제한된 IoT 기기나 스마트카드 환경에서 압도적인 우위를 자랑합니다.&lt;/p>
&lt;hr>
&lt;h2 id="2-수학적-준비-군론과-유한체의-세계">2. 수학적 준비: 군론과 유한체의 세계
&lt;/h2>&lt;p>타원곡선 암호를 진정으로 이해하기 위해서는 추상대수학(군론 및 체론)의 기본 개념을 파악해 둘 필요가 있습니다. 여기서는 ECC를 구성하기 위한 사전 지식을 간결하게 정리합니다.&lt;/p>
&lt;h3 id="21-군group과-아벨-군">2.1. 군(Group)과 아벨 군
&lt;/h3>&lt;p>**군(Group)**이란 어떤 집합 $G$와 그 집합 상의 이항 연산(여기서는 덧셈 $+$로 합니다)의 쌍 $(G, +)$이며, 다음의 4가지 공리를 만족하는 것을 말합니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>닫힘(Closure)&lt;/strong>: 임의의 $a, b \in G$에 대해 $a + b \in G$이다.&lt;/li>
&lt;li>&lt;strong>결합 법칙(Associativity)&lt;/strong>: 임의의 $a, b, c \in G$에 대해 $(a + b) + c = a + (b + c)$가 성립한다.&lt;/li>
&lt;li>&lt;strong>항등원의 존재(Identity element)&lt;/strong>: 임의의 $a \in G$에 대해 $a + e = e + a = a$가 되는 원소 $e \in G$가 존재한다. 덧셈군의 경우, 이 항등원을 보통 $0$ 또는 $\mathcal{O}$로 표기합니다.&lt;/li>
&lt;li>&lt;strong>역원의 존재(Inverse element)&lt;/strong>: 임의의 $a \in G$에 대해 $a + b = b + a = e$가 되는 원소 $b \in G$가 존재한다. 이 $b$를 $-a$로 표기합니다.&lt;/li>
&lt;/ol>
&lt;p>더 나아가 연산의 순서를 바꾸어도 결과가 변하지 않는, 즉 다음 조건을 만족하는 군을 **아벨 군(가환군)**이라고 부릅니다.&lt;/p>
&lt;ol start="5">
&lt;li>&lt;strong>교환 법칙(Commutativity)&lt;/strong>: 임의의 $a, b \in G$에 대해 $a + b = b + a$가 성립한다.&lt;/li>
&lt;/ol>
&lt;p>타원곡선 상의 점들의 집합은 특정한 덧셈 규칙을 정의함으로써 이 &lt;strong>아벨 군&lt;/strong>을 구성합니다.&lt;/p>
&lt;h3 id="22-유한체finite-field">2.2. 유한체(Finite Field)
&lt;/h3>&lt;p>암호 이론에서는 실수나 복소수처럼 연속적이고 무한한 요소를 가진 체가 아니라, 원소의 개수가 유한한 &lt;strong>유한체(Finite Field)&lt;/strong> 또는 갈루아 체(Galois Field)를 사용합니다.&lt;/p>
&lt;p>가장 기본적인 유한체는 소수 $p$를 사용한 **소체 $\mathbb{F}_p$**입니다. 이는 $\{0, 1, 2, \dots, p-1\}$의 정수 집합에 모듈로 $p$($p$로 나눈 나머지)에서의 사칙연산(덧셈, 뺄셈, 곱셈, 나눗셈)을 정의한 것입니다.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>덧셈&lt;/strong>: $(a + b) \pmod p$&lt;/li>
&lt;li>&lt;strong>뺄셈&lt;/strong>: $(a - b) \pmod p$&lt;/li>
&lt;li>&lt;strong>곱셈&lt;/strong>: $(a \times b) \pmod p$&lt;/li>
&lt;li>&lt;strong>나눗셈&lt;/strong>: $a \times b^{-1} \pmod p$ (여기서 $b^{-1}$은 모듈로 $p$에서의 $b$의 곱셈 역원)&lt;/li>
&lt;/ul>
&lt;p>**곱셈 역원(Modular Multiplicative Inverse)**의 계산은 암호 구현에서 매우 중요합니다. $b \times b^{-1} \equiv 1 \pmod p$를 만족하는 $b^{-1}$을 구하기 위해서는 주로 다음 두 가지 알고리즘이 사용됩니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>확장 유클리드 호제법(Extended Euclidean Algorithm)&lt;/strong>: 빠르지만, 구현에 따라 처리 시간이 입력값에 의존하기 때문에 타이밍 공격의 위험이 있습니다.&lt;/li>
&lt;li>&lt;strong>페르마의 소정리(Fermat&amp;rsquo;s Little Theorem)&lt;/strong>: $p$가 소수이고 $b \neq 0$일 때, $b^{p-1} \equiv 1 \pmod p$가 성립합니다. 양변을 $b$로 나누면 $b^{p-2} \equiv b^{-1} \pmod p$가 됩니다. 즉, $b$의 $p-2$ 제곱을 계산함으로써 역원을 구할 수 있습니다. 거듭제곱 연산은 상수 시간(Constant-Time)으로 구현하기 쉽기 때문에, 암호 구현에서는 이 방법을 선호합니다.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="3-타원곡선의-방정식과-기하학">3. 타원곡선의 방정식과 기하학
&lt;/h2>&lt;h3 id="31-바이어슈트라스의-표준형">3.1. 바이어슈트라스의 표준형
&lt;/h3>&lt;p>**타원곡선(Elliptic Curve)**은 일반적으로 다음의 **바이어슈트라스 표준형(Weierstrass normal form)**이라고 불리는 방정식으로 정의되는 평면 곡선입니다.&lt;/p>
$$ y^2 = x^3 + ax + b $$
&lt;p>여기서 $a$와 $b$는 상수이며, 곡선이 특이점(자기 교차점이나 뾰족점)을 가지지 않기(매끄러운 곡선이기) 위한 조건으로 다음의 **판별식(Discriminant) $\Delta$**가 0이 아니어야 합니다.&lt;/p>
$$ \Delta = -16(4a^3 + 27b^2) \neq 0 $$
&lt;p>특이점을 가진 곡선은 암호학적 안전성을 손상시키기 때문에, 반드시 이 조건을 만족하는 계수 $a, b$가 선택됩니다.&lt;/p>
&lt;h3 id="32-무한원점point-at-infinity">3.2. 무한원점(Point at Infinity)
&lt;/h3>&lt;p>타원곡선을 수학적으로 완전한 군으로 만들기 위해, 평면 상의 점에 더해 **&amp;lsquo;무한원점(Point at Infinity)&amp;rsquo;**이라고 불리는 가상의 점을 도입합니다. 이를 $\mathcal{O}$(오)라고 표기합니다.&lt;/p>
&lt;p>무한원점 $\mathcal{O}$는 모든 수직선이 무한히 먼 곳에서 만나는 점으로 정의됩니다. 군론에서 이 무한원점 $\mathcal{O}$는 &lt;strong>덧셈에 대한 항등원&lt;/strong>(0)으로 기능합니다.&lt;/p>
&lt;p>즉, 곡선 상의 임의의 점 $P$에 대해 다음이 성립합니다.
&lt;/p>
$$ P + \mathcal{O} = \mathcal{O} + P = P $$
&lt;p>또한, 점 $P = (x, y)$의 역원 $-P$는 x축에 대해 대칭인 점 $(x, -y)$로 정의됩니다. 따라서:
&lt;/p>
$$ P + (-P) = \mathcal{O} $$
&lt;p>
가 됩니다.&lt;/p>
&lt;hr>
&lt;h2 id="4-타원곡선-상의-군-연산점의-덧셈과-2배-연산">4. 타원곡선 상의 군 연산(점의 덧셈과 2배 연산)
&lt;/h2>&lt;p>타원곡선 암호의 근간을 이루는 것이 바로 곡선 상의 점들 간의 **&amp;lsquo;덧셈(Addition)&amp;rsquo;**이라는 연산입니다. 이는 일반적인 정수의 덧셈과는 다르며 기하학적인 조작을 바탕으로 정의되어 있습니다.&lt;/p>
&lt;h3 id="41-기하학적-덧셈tangent-and-chord-method">4.1. 기하학적 덧셈(Tangent and Chord Method)
&lt;/h3>&lt;p>곡선 상의 서로 다른 두 점 $P$와 $Q$를 더하여 새로운 점 $R$ ($R = P + Q$)을 구하는 절차는 다음과 같습니다.&lt;/p>
&lt;ol>
&lt;li>점 $P$와 점 $Q$를 지나는 직선(현)을 긋습니다.&lt;/li>
&lt;li>이 직선은 타원곡선과 반드시 또 다른 한 점(이를 $-R$이라 합니다)에서 만납니다. (※ 대수기하학의 정리에 따름)&lt;/li>
&lt;li>교점 $-R$을 x축에 대해 대칭으로 뒤집은 점(y좌표의 부호를 반전시킨 점)이 구하고자 하는 점 $R$이 됩니다.&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
Step1["P(x1, y1) 와 Q(x2, y2) 를 잇는 직선을 긋는다"] --> Step2["곡선과의 제3의 교점 -R 을 찾는다"]
Step2 --> Step3["-R 을 x축으로 뒤집어, R(x3, y3) 을 얻는다"]
Step3 -.-> Result["이것이 R = P + Q"]&lt;/div>
&lt;h3 id="42-점의-2배-연산point-doubling">4.2. 점의 2배 연산(Point Doubling)
&lt;/h3>&lt;p>점 $P$에 같은 점 $P$를 더하는 경우($P + P = 2P$), 두 점을 지나는 직선을 그을 수 없습니다. 이 경우에는 **점 $P$에서의 곡선의 접선(Tangent)**을 긋습니다.&lt;/p>
&lt;ol>
&lt;li>점 $P$에서의 곡선의 접선을 긋습니다.&lt;/li>
&lt;li>이 접선은 곡선과 또 다른 한 점 $-R$에서 만납니다.&lt;/li>
&lt;li>교점을 x축에 대해 대칭으로 뒤집은 점이 구하고자 하는 점 $R = 2P$가 됩니다.&lt;/li>
&lt;/ol>
&lt;h3 id="43-대수적인-계산-공식">4.3. 대수적인 계산 공식
&lt;/h3>&lt;p>기하학적인 조작을 컴퓨터로 계산할 수 있도록 대수적인 공식으로 옮겨냅니다.
연산은 모두 **유한체 $\mathbb{F}_p$ 상(모듈로 $p$)**에서 이루어집니다.&lt;/p>
&lt;p>점 $P = (x_1, y_1)$, 점 $Q = (x_2, y_2)$라고 합시다.
또한 계산 결과인 점을 $R = P + Q = (x_3, y_3)$이라 합시다.&lt;/p>
&lt;p>직선의 기울기를 $\lambda$(람다)라고 합니다.&lt;/p>
&lt;p>&lt;strong>【케이스 1: $P \neq Q$ 인 경우 (점의 덧셈)】&lt;/strong>
기울기 $\lambda$는 두 점 사이의 변화율입니다.
&lt;/p>
$$ \lambda \equiv \frac{y_2 - y_1}{x_2 - x_1} \pmod p $$
$$ \lambda \equiv (y_2 - y_1) \cdot (x_2 - x_1)^{-1} \pmod p $$
&lt;p>이 $\lambda$를 사용하여 $x_3, y_3$은 다음과 같이 구합니다.
&lt;/p>
$$ x_3 \equiv \lambda^2 - x_1 - x_2 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;p>&lt;strong>【케이스 2: $P = Q$ 인 경우 (점의 2배 연산)】&lt;/strong>
기울기 $\lambda$는 미분을 통해 구한 접선의 기울기가 됩니다. ($y^2 = x^3 + ax + b$를 암묵적으로 미분합니다)
&lt;/p>
$$ 2y \cdot y' = 3x^2 + a \implies y' = \frac{3x^2 + a}{2y} $$
&lt;p>
따라서,
&lt;/p>
$$ \lambda \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod p $$
&lt;p>$x_3, y_3$의 식은 덧셈과 같은 형태이지만, $x_2 = x_1$이므로 다음과 같이 됩니다.
&lt;/p>
$$ x_3 \equiv \lambda^2 - 2x_1 \pmod p $$
$$ y_3 \equiv \lambda(x_1 - x_3) - y_1 \pmod p $$
&lt;blockquote>
&lt;p>[!IMPORTANT]
이러한 공식에는 $(x_2 - x_1)^{-1}$이나 $(2y_1)^{-1}$과 같은 **나눗셈(모듈로 역원의 계산)**이 포함되어 있습니다. 모듈로 역원의 계산은 계산 비용이 매우 높기 때문에, 실제 구현에서는 나눗셈을 지연시키는 &lt;strong>&amp;lsquo;야코비 좌표계(Jacobian Coordinates)&amp;rsquo;&lt;/strong> 등의 사영 좌표계가 일반적으로 사용됩니다.&lt;/p>
&lt;/blockquote>
&lt;hr>
&lt;h2 id="5-스칼라-곱셈과-타원곡선-이산대수-문제ecdlp">5. 스칼라 곱셈과 타원곡선 이산대수 문제(ECDLP)
&lt;/h2>&lt;p>타원곡선 암호에서 가장 계산량이 많고, 동시에 보안의 핵심을 이루는 연산이 바로 **스칼라 곱셈(Scalar Multiplication)**입니다.&lt;/p>
&lt;h3 id="51-스칼라-곱셈이란">5.1. 스칼라 곱셈이란
&lt;/h3>&lt;p>어떤 점 $P$를 $k$번 더하는 조작을 스칼라 곱셈이라 부르며, $kP$라고 표기합니다.
&lt;/p>
$$ kP = \underbrace{P + P + \dots + P}_{k\text{번}} $$
&lt;p>여기서 $k$는 매우 큰 정수(예를 들어 256비트의 정수)입니다.&lt;/p>
&lt;h3 id="52-타원곡선-이산대수-문제ecdlp">5.2. 타원곡선 이산대수 문제(ECDLP)
&lt;/h3>&lt;p>타원곡선 암호의 안전성은 다음 문제의 어려움에 의존하고 있습니다.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>타원곡선 이산대수 문제(Elliptic Curve Discrete Logarithm Problem: ECDLP)&lt;/strong>
알려진 점 $P$(베이스 포인트)와 계산 결과인 점 $Q$가 주어졌을 때, $Q = kP$를 만족하는 스칼라 $k$를 구하시오.&lt;/p>
&lt;/blockquote>
&lt;p>$k$와 $P$로부터 $Q$를 계산하는 것(정방향)은 후술할 알고리즘을 사용하면 쉽지만(다항식 시간), $P$와 $Q$로부터 $k$를 역산하는 것(역방향)은 전수조사와 같은 무차별 대입 이외에는 효율적인 해법이 없어 사실상 불가능합니다(일방향 함수).
암호 프로토콜에서는 **$k$가 &amp;lsquo;개인키&amp;rsquo;, $Q$가 &amp;lsquo;공개키&amp;rsquo;**에 해당합니다.&lt;/p>
&lt;h3 id="53-double-and-add-알고리즘">5.3. Double-and-Add 알고리즘
&lt;/h3>&lt;p>$k$가 거대한 수(예: $2^{256}$)일 경우, $P$를 우직하게 $k$번 더하는 것은 우주의 수명이 다해도 끝나지 않습니다. 그래서 고속으로 스칼라 곱셈을 수행하기 위해 **Double-and-Add 방법(바이너리 방법)**이 사용됩니다.&lt;/p>
&lt;p>이는 정수의 거듭제곱을 고속으로 계산하는 &amp;lsquo;반복 제곱법&amp;rsquo;의 타원곡선 버전입니다. 스칼라 $k$를 2진수로 표현하고, 최상위 비트부터 차례대로 처리합니다.&lt;/p>
&lt;ol>
&lt;li>결과를 유지할 점 $R$을 $\mathcal{O}$로 초기화한다.&lt;/li>
&lt;li>$k$의 최상위 비트부터 최하위 비트까지 다음을 반복한다:
&lt;ul>
&lt;li>$R$을 2배로 한다 (Point Doubling: $R = 2R$)&lt;/li>
&lt;li>만약 현재 비트가 &lt;code>1&lt;/code>이라면, $R$에 $P$를 더한다 (Point Addition: $R = R + P$)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>이 알고리즘을 통해 계산량은 $O(k)$에서 $O(\log_2 k)$로 극적으로 감소하며, 현실적인 시간(밀리초 단위) 내에 계산이 가능해집니다.&lt;/p>
&lt;hr>
&lt;h2 id="6-타원곡선-디피-헬먼ecdh-키-교환">6. 타원곡선 디피-헬먼(ECDH) 키 교환
&lt;/h2>&lt;p>여기서는 ECC의 가장 대표적인 응용 사례인 &lt;strong>ECDH(Elliptic Curve Diffie-Hellman) 키 교환 프로토콜&lt;/strong>의 작동 원리를 해설합니다. ECDH는 도청이 가능한 통신 채널 상에서 앨리스와 밥이 안전하게 공통의 비밀키(세션 키)를 생성 및 공유하기 위한 메커니즘입니다(TLS 핸드셰이크의 핵심입니다).&lt;/p>
&lt;p>&lt;strong>【전제 파라미터(도메인 파라미터)】&lt;/strong>
양측은 미리 사용할 타원곡선 $E$, 소수 $p$, 그리고 베이스 포인트 $G$를 공유하고 있습니다. (예: NIST P-256이나 secp256k1 등)&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant Alice as "Alice (앨리스)"
participant Bob as "Bob (밥)"
Note over Alice,Bob: "공개 파라미터: 곡선 E, 베이스 포인트 G, 소수 p"
Alice->>Alice: "개인키 d_A (랜덤한 정수) 를 생성"
Alice->>Alice: "공개키 Q_A = d_A * G 를 계산"
Bob->>Bob: "개인키 d_B (랜덤한 정수) 를 생성"
Bob->>Bob: "공개키 Q_B = d_B * G 를 계산"
Alice->>Bob: "공개키 Q_A 를 전송 (평문)"
Bob->>Alice: "공개키 Q_B 를 전송 (평문)"
Alice->>Alice: "공유 시크릿 S = d_A * Q_B 를 계산"
Bob->>Bob: "공유 시크릿 S = d_B * Q_A 를 계산"
Note over Alice,Bob: "S = d_A * (d_B * G) = d_B * (d_A * G) = (d_A * d_B) * G"
Note over Alice,Bob: "양측의 계산 결과 S 는 완전히 일치한다!"&lt;/div>
&lt;p>도청자(이브)는 통신 경로 상에 흐르는 $G$, $Q_A$, $Q_B$를 가로챌 수 있지만, ECDLP의 어려움으로 인해 $Q_A = d_A \cdot G$로부터 앨리스의 개인키 $d_A$를 알아낼 수는 없습니다. 또한, $Q_A$와 $Q_B$를 곱해도 공유키 $S$가 되지 않으므로 도청자는 $S$를 계산할 수 없습니다.&lt;/p>
&lt;hr>
&lt;h2 id="7-구현의-함정-부채널-공격과-대책">7. 구현의 함정: 부채널 공격과 대책
&lt;/h2>&lt;p>이론적으로 완벽한 암호 알고리즘이라 하더라도 그것을 프로그램으로 구현하는 과정에서 취약점이 발생할 수 있습니다. 그것이 바로 **&amp;lsquo;부채널 공격(Side-Channel Attack)&amp;rsquo;**입니다.&lt;/p>
&lt;h3 id="71-타이밍-공격timing-attack">7.1. 타이밍 공격(Timing Attack)
&lt;/h3>&lt;p>앞서 언급한 Double-and-Add 알고리즘을 되돌아봅시다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 취약한 Double-and-Add 의 의사 코드
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Infinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">255&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointDoubling&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 항상 실행됨
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PointAddition&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// 비트가 1일 때만 실행됨!
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>이 구현에는 치명적인 결함이 있습니다. 비트가 &lt;code>1&lt;/code>일 때는 Point Addition이 실행되기 때문에 비트가 &lt;code>0&lt;/code>일 때보다 &lt;strong>계산 시간이 약간 더 길어집니다&lt;/strong>. 또한 프로세서의 분기 예측이나 캐시 메모리의 동작도 변하게 됩니다.
공격자가 이 계산 시간(혹은 소비 전력)의 미세한 차이를 수천 번 통계적으로 관측함으로써, &lt;strong>개인키 $k$의 비트열을 1비트씩 완전히 복원&lt;/strong>해 낼 수 있습니다. 이것이 타이밍 공격입니다.&lt;/p>
&lt;h3 id="72-constant-time-구현-montgomery-ladder">7.2. Constant-Time 구현: Montgomery Ladder
&lt;/h3>&lt;p>타이밍 공격을 방지하기 위해서는, &lt;strong>개인키의 비트 값과 관계없이 실행되는 명령어의 시퀀스와 계산 시간이 항상 일정한(Constant-Time)&lt;/strong> 알고리즘을 채택해야 합니다.&lt;/p>
&lt;p>그 대표적인 예가 **Montgomery Ladder(몽고메리 사다리)**입니다.&lt;/p>
&lt;div class="mermaid">graph TD
Start["초기화: R0 = O, R1 = P"] --> LoopStart["각 비트 i 에 대해 (최상위부터)"]
LoopStart --> Cond{"k_i 의 값은?"}
Cond -->|0| Branch0["R1 = R0 + R1&lt;br>R0 = 2 * R0"]
Cond -->|1| Branch1["R0 = R0 + R1&lt;br>R1 = 2 * R1"]
Branch0 --> LoopEnd["다음 비트로"]
Branch1 --> LoopEnd
LoopEnd --> LoopStart
LoopStart -.->|"모든 비트 완료"| End["종료: R0 가 결과 (kP)"]&lt;/div>
&lt;p>Montgomery Ladder의 아름다운 점은 비트가 &lt;code>0&lt;/code>이든 &lt;code>1&lt;/code>이든, **&amp;ldquo;항상 1번의 Point Addition과 1번의 Point Doubling&amp;rdquo;**이 실행된다는 것입니다. 이를 통해 계산 시간의 데이터 의존성이 완전히 배제됩니다.&lt;/p>
&lt;p>단, 분기(&lt;code>if (k_i == 0)&lt;/code>) 자체가 존재하면 컴파일러의 최적화나 CPU의 분기 예측에 의해 실행 시간이 변동할 위험이 남아 있습니다. 따라서 실제 Constant-Time 구현에서는 조건 분기(&lt;code>if&lt;/code>문)를 배제하고, **비트 연산을 이용한 조건부 스왑(Conditional Swap)**을 활용합니다.&lt;/p>
&lt;hr>
&lt;h2 id="8-c를-이용한-타원곡선-암호의-구현">8. C++를 이용한 타원곡선 암호의 구현
&lt;/h2>&lt;p>이제부터는 이론을 C++ 코드로 구현해 보겠습니다. 실용적인 암호 라이브러리(OpenSSL이나 libsodium 등)는 고도화된 어셈블리 최적화나 야코비 좌표계를 사용하지만, 여기서는 수학적 이해를 돕기 위해 &lt;strong>아핀(Affine) 좌표계를 이용한 알기 쉬운 Constant-Time 구현&lt;/strong>의 뼈대를 제시합니다.&lt;/p>
&lt;p>거대한 정수의 연산에는 &lt;code>boost::multiprecision::cpp_int&lt;/code>를 사용한다고 가정합니다.&lt;/p>
&lt;h3 id="81-모듈로-연산과-역원">8.1. 모듈로 연산과 역원
&lt;/h3>&lt;p>먼저 유한체 상의 연산 헬퍼 함수를 정의합니다. 페르마의 소정리에 의한 역원 계산을 구현합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;boost/multiprecision/cpp_int.hpp&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">boost&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">multiprecision&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 예시로 secp256k1 의 소수 p 와 파라미터
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">const&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">7&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 양의 나머지를 반환하는 모듈로 연산
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">x&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="n">r&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="nl">m&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">r&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 거듭제곱 나머지 계산 (x^y mod m)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">exp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">exp&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="mi">2&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="n">res&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">res&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">base&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">base&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">base&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exp&lt;/span> &lt;span class="o">/=&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">res&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 페르마의 소정리를 이용한 모듈로 역원
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="nf">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// m이 소수라는 전제: n^(m-2) ≡ n^(-1) mod m
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">powerMod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="82-점의-표현과-군-연산덧셈2배-연산">8.2. 점의 표현과 군 연산(덧셈·2배 연산)
&lt;/h3>&lt;p>무한원점을 플래그로 관리하는 &lt;code>Point&lt;/code> 구조체와 덧셈 공식을 구현합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Point&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 무한원점의 생성
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 일반적인 점의 생성
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">x&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">y&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">isInfinity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 타원곡선 상의 점의 덧셈 (R = P + Q)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">isInfinity&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// P + (-P) = 무한원점
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">lambda&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Doubling (P = Q 인 경우)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (3x^2 + a) / 2y
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Point Addition (P != Q 인 경우)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// lambda = (y2 - y1) / (x2 - x1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">num&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">den&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">modInverse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lambda&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">den&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">x3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">lambda&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">Q&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">y3&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">mod&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">lambda&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">x&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">x3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">y&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">x3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">y3&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="83-constant-time-conditional-swap-의-구현">8.3. Constant-Time Conditional Swap 의 구현
&lt;/h3>&lt;p>개인키의 비트 값에 따라 변수의 내용을 교환할 때, &lt;code>if&lt;/code>문을 사용하지 않고 비트 연산(마스크)만으로 교환을 수행합니다. 이를 통해 실행 경로가 완전히 일정해집니다.&lt;/p>
&lt;blockquote>
&lt;p>[!TIP]
실제 구현에서는 &lt;code>cpp_int&lt;/code>와 같이 동적으로 할당되는 다정밀도 정수 클래스는 Constant-Time 처리에 적합하지 않습니다. 메모리 할당이나 배열 크기의 변동에 따라 타이밍 정보가 유출되기 때문입니다. 실용적인 라이브러리에서는 고정 길이(예: uint64_t × 4요소 배열)로 표현하고, 비트 단위의 마스크 처리를 구현합니다. 다음은 개념적인 예시입니다.&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 개념적인 Constant-Time Swap (고정 길이 정수를 가정한 경우)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// bit 가 1 이면 P1 과 P2 를 교환하고, 0 이면 교환하지 않음
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">void&lt;/span> &lt;span class="nf">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bit 는 0 또는 1. 마스크는 bit=1 이면 모든 비트가 1(0xFF..), 0이면 모든 비트가 0.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// (여기서는 설명을 위해 고정 길이 BigInt 클래스의 각 워드를 w라 가정)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="cm">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t mask = 0 - (uint64_t)bit;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> for (int i = 0; i &amp;lt; NUM_WORDS; i++) {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> uint64_t dummy = mask &amp;amp; (P1.x.words[i] ^ P2.x.words[i]);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P1.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> P2.x.words[i] ^= dummy;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> // y좌표나 isInfinity 플래그도 동일하게 처리
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ※ boost::multiprecision 에서 완벽한 상수 시간 스왑은 어렵지만,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 여기서는 로직의 이해를 위해 분기를 통한 시뮬레이션에 그칩니다.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">bit&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">swap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">P1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">P2&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="84-montgomery-ladder-에-의한-스칼라-곱셈">8.4. Montgomery Ladder 에 의한 스칼라 곱셈
&lt;/h3>&lt;p>앞서 설명한 &lt;code>pointAdd&lt;/code>와 &lt;code>cswap&lt;/code>을 결합하여 안전한 스칼라 곱셈을 구현합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 스칼라 곱셈 k * P (Montgomery Ladder 방식)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">Point&lt;/span> &lt;span class="nf">scalarMultiply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cpp_int&lt;/span> &lt;span class="n">k&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Point&lt;/span> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Point&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// 무한원점
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Point&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">P&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// k 의 비트 길이를 가져옴 (secp256k1 이라면 256 비트)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">256&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">numBits&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">--&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// i번째 비트의 값을 가져옴 (0 또는 1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint8_t&lt;/span> &lt;span class="n">bit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">static_cast&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">uint8_t&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">bit_test&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">k&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">?&lt;/span> &lt;span class="mi">1&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bit == 1 이라면 R0 와 R1 을 스왑
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 항상 같은 연산을 실행 (Point Addition 과 Point Doubling)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">R1&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">R0&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">pointAdd&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// bit == 1 이었던 경우, 상태를 원래대로 되돌리기 위해 다시 스왑
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">cswap&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">R0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">R1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bit&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">R0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>이 구현 로직을 통해, 스칼라 $k$의 각 비트가 &lt;code>0&lt;/code>이든 &lt;code>1&lt;/code>이든, 각 루프 이터레이션 내에서 실행되는 연산(&lt;code>cswap&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>pointAdd&lt;/code> $\to$ &lt;code>cswap&lt;/code>)은 완전히 동일한 흐름이 되어, 타이밍이나 캐시 액세스 패턴의 차이를 통한 비밀 정보의 유출을 강력하게 방지할 수 있습니다.&lt;/p>
&lt;hr>
&lt;h2 id="9-요약">9. 요약
&lt;/h2>&lt;p>타원곡선 암호(ECC)는 처음 보았을 때는 &amp;ldquo;어째서 직선을 긋고 교점을 뒤집는 기하학적인 조작이 암호가 되는 걸까?&amp;rdquo; 하고 신기하게 느껴질 수도 있습니다. 하지만 유한체라는 이산적인 세계로 매핑함으로써 훌륭한 일방향 함수(이산대수 문제)를 구축할 수 있다는, 수학과 암호학의 기적적인 융합의 산물입니다.&lt;/p>
&lt;p>본 기사에서는 다음의 중요한 요점들을 해설했습니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>RSA 대비 우위성&lt;/strong>: 매우 짧은 키 길이로 강력한 보안을 제공하며, 현대의 모바일·IoT 시대에 최적화되어 있습니다.&lt;/li>
&lt;li>&lt;strong>군론과 유한체의 기초&lt;/strong>: ECC의 토대가 되는 수학적 구조.&lt;/li>
&lt;li>&lt;strong>덧셈과 2배 연산의 공식&lt;/strong>: 바이어슈트라스 방정식을 이용한 대수적인 군 연산의 구현 방법.&lt;/li>
&lt;li>&lt;strong>부채널 공격의 위협&lt;/strong>: 개인키의 비트에 의존하는 조건 분기가 치명적인 취약점을 발생시킨다는 점.&lt;/li>
&lt;li>&lt;strong>Constant-Time 구현&lt;/strong>: Montgomery Ladder와 Conditional Swap을 이용해 하드웨어 수준의 동작을 균일화하여 공격을 방지하는 C++ 코딩 기법.&lt;/li>
&lt;/ol>
&lt;p>실제 프로덕션 환경에서 동작하는 암호 라이브러리를 직접 만드는 것은 보안상 위험이 매우 높기 때문에 권장되지 않습니다(&amp;ldquo;Don&amp;rsquo;t roll your own crypto&amp;rdquo;). 하지만 그 내부에서 동작하고 있는 알고리즘과 수학적 배경을 깊이 이해하는 것은 더 안전하고 퍼포먼스가 높은 시스템을 설계 및 운영하는 엔지니어에게 둘도 없이 강력한 무기가 될 것입니다.&lt;/p>
&lt;p>다음 기사에서는 이 타원곡선을 이용한 디지털 서명 알고리즘인 **ECDSA(Elliptic Curve Digital Signature Algorithm)**의 메커니즘이나, 비트코인에서 채택된 **Schnorr 서명(슈노르 서명)**에 대해 한층 더 깊이 파고들어 보고자 합니다.&lt;/p></description></item></channel></rss>