Katman 1 Yayında

Nokta Katlama (Point Doubling)

Eğri Üzerinde Nokta Matematiği · Teğet Yöntemi · İmplicit Diferansiyel Türetme · Double-and-Add Algoritmasının Temeli

Zorluk Akademik
Okuma Süresi 16 Dakika
Kod Desteği Rust (Doubling)
Kritik Yapı Taşı Skaler Çarpım (kG)

Bir önceki konuda (\(\textbf{Nokta Toplama}\)) iki farklı noktayı nasıl toplayacağımızı öğrendik. Formüllerin kalbi şuydu: iki noktadan geçen doğrunun eğriye kesişimini bul, yansımasını al. Ancak o formüllerin önünde görünmez bir kısıtlama vardı: iki nokta farklı olmalıydı, yani \(x_1 \neq x_2\). Peki ya aynı noktayı kendisiyle toplamak istersek? Yani \(P + P = 2P\) hesabını?

Bu soru, görünüşte basit bir özel durumu tanımlar; ama aslında nokta katlama, eliptik eğri kriptografisinin en kritik yapı taşıdır. Bir gizli anahtar \(k\), büyük olasılıkla 256 bitlik bir tam sayıdır ve \(Q = k \cdot G\) hesabı binlerce nokta katlaması içerir. Bitcoin'in bir anahtar türetmesi, TLS'in oturum anahtarı üretmesi, Ethereum'un bir imzalaması — hepsinin merkezinde nokta katlama vardır. Bu işlemi anlamak, skaler çarpımı ve dolayısıyla tüm ECC protokollerini anlamak demektir.

Nokta katlamayı nokta toplamadan ayrı bir formülle çözmek zorunda olmamız, tamamen geometrik bir zorunluluktan kaynaklanır. İki farklı nokta için "ikisi arasından geçen doğru" diye bir şey vardır. Ama tek bir nokta için bu tanım anlamsızlaşır. Yerine geçen kavram, o noktada eğriye çizilen teğet doğrusudur. Bu teğetin eğriye ikinci kez kesiştiği nokta ve ardından yapılan yansıma, \(2P\) sonucunu verir.

Neden Teğet? Toplama Limitinin Geometrik Açıklaması

Geometrik sezgiyi kuralım. \(P + Q\) toplamının tanımını hatırlayın: \(P\) ve \(Q\) arasından geçen doğruyu çiz, eğriyle üçüncü kesişim noktasını bul, yansımasını al. Şimdi \(Q\)'yu yavaş yavaş \(P\)'ye yaklaştırdığınızı düşünün. \(Q \to P\) limitinde, iki farklı noktadan geçen doğru ne olur? Bu iki nokta birbirlerine sonsuz yaklaştıkça, aralarından geçen kesen doğru (secant line), P noktasındaki teğet doğrusuna dönüşür.

Matematiksel olarak bu, diferansiyel hesabın temel tanımıyla örtüşür: bir eğrinin bir noktasındaki teğeti, o noktaya yaklaşan iki nokta arasındaki kesen doğrunun limitidir. Dolayısıyla nokta katlama, limit anlamında nokta toplamadan doğar — ayrı bir kural değil, aynı geometrinin özel bir durumudur. Bu bakış açısı, grup yapısının tutarlılığını da garanti eder: grup aksiyomları \(P + P\) için de bozulmadan geçerlidir, çünkü bu işlem içsel olarak aynı geometrik çerçeveden türetilmiştir.

Teğet ile Kesen Arasındaki Köprü
İki farklı nokta \(P = (x_1, y_1)\) ve \(Q = (x_2, y_2)\) arasındaki kesenin eğimi: \[m_{kesen} = \frac{y_2 - y_1}{x_2 - x_1}\] \(Q \to P\) limitini aldığımızda bu, L'Hôpital kuralıyla veya implicit diferansiyasyonla eğrinin \(P\) noktasındaki türevine dönüşür. Weierstrass denklemi \(y^2 = x^3 + ax + b\)'nin her iki tarafını \(x\)'e göre diferansiye edersek teğetin eğimini buluruz — bu, nokta katlama formülünün özüdür.

İmplicit Diferansiyasyon ile Teğet Eğiminin Türetimi

Weierstrass denklemini analitik olarak çözmek yerine — yani \(y\)'yi \(x\)'in açık bir fonksiyonu olarak yazmak yerine — her iki tarafı doğrudan \(x\)'e göre diferansiye ediyoruz. Bu yönteme implicit diferansiyasyon denir ve eğrinin her noktasında teğetin eğimini verir.

Adım 1 · Weierstrass Tabanı
y^2 = x^3 + ax + b
Meal: Eliptik eğrinin Weierstrass kısa formundaki genel tanımıdır.

Katsayılar (a, b) eğrinin şeklini belirler ve tekil olmama şartını (\(4a^3 + 27b^2 \neq 0\)) sağlar.

Adım 2 · İmplicit Türev
\frac{d}{dx}(y^2) = \frac{d}{dx}(x^3 + ax + b)
Meal: Her iki tarafı doğrudan x değişkenine göre diferansiye ederiz.

x'e bağlı türevi alarak teğet doğrusunun eğim fonksiyonuna giden yolu açarız.

Adım 3 · Zincir Kuralı
2y \cdot \frac{dy}{dx} = 3x^2 + a
Meal: Sol tarafa zincir kuralı uygulanır çünkü y de x'in bir fonksiyonudur.

\(\frac{dy}{dx}\) terimi, y koordinatının x'e göre değişim oranını (teğet eğimini) temsil eder.

Adım 4 · Teğet Eğimi (m)
m = \frac{dy}{dx} = \frac{3x^2 + a}{2y}
Meal: \(\frac{dy}{dx}\) için çözerek teğet doğrusunun eğim formülünü buluruz.

Bu formül, nokta katlama aritmetiğinde eğimi (slope) doğrudan hesaplamamızı sağlar.

Bu formül, nokta katlama işleminin matematiksel kalbidir. Dikkat edilmesi gereken iki kritik durum şimdiden görünür olur:

  • Payda \(2y = 0\) ise: Bu, \(y = 0\) anlamına gelir. Eğri üzerinde y-koordinatı sıfır olan noktalar, x-eksenini tam olarak keser ve eğrinin bu noktalarda teğeti dik (dikey) bir doğrudur. Dolayısıyla \(2P = \mathcal{O}\) (sonsuz nokta) olur. Bu noktalar mertebesi 2 olan noktalardır — onlar hakkında bir sonraki bölümde ayrıntılı duracağız.
  • Pay \(3x^2 + a = 0\) ise: Teğet yatay (\(m = 0\)) olur. Bu, teğetin eğriye ikinci kez kestiği noktanın, aynı y-koordinatında tam tersinde yer aldığı anlamına gelir. Yatay teğet, eğrinin yerel bir minimum ya da maksimumunu işaret eder ve \(2P\)'nin özel bir konumda bulunduğunu gösterir.

Sonlu alanlarda (\(\mathbb{F}_p\)) bu türev formülü aynen kullanılır, ancak bölme işlemi yerine çarpımsal ters kullanılır. Gerçek sayılardaki sürekli eğri sezgisi tamamen geçerliliğini korur; yalnızca aritmetik modüler hale gelir.

Katlama Formülleri: \(2P\) Koordinatlarının Hesabı

Adım 1 · Teğet Eğimi (m)
m \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod{p}
Meal: Payda \(2y_1\)'in modüler çarpımsal tersini hesaplayıp pay ile çarparız.

Sonlu alanda bölme yerine Fermat'ın Küçük Teoremi veya Genişletilmiş Öklid kullanılır.

Adım 2 · x₃ Koordinatı
x_3 \equiv m^2 - 2x_1 \pmod{p}
Meal: Teğetin çift kökü (P noktası) sebebiyle Vieta formülünde \(-2x_1\) gelir.

Normal nokta toplamındaki \(x_3 = m^2 - x_1 - x_2\) kuralı ile tam bir geometrik tutarlılık içindedir.

Adım 3 · y₃ Koordinatı
y_3 \equiv m(x_1 - x_3) - y_1 \pmod{p}
Meal: Doğru üzerindeki üçüncü kesişim noktasının y-eksenine göre yansımasını alırız.

Bu yansıma, eliptik eğri grubunun ters eleman (\(P + (-P) = \mathcal{O}\)) kuralını sağlar.

Bu adım nokta toplama ile birebir aynıdır: teğet doğrusunun \(x_3\) noktasındaki değerini hesaplayıp x-eksenine yansıtıyoruz (negatifini alıyoruz). Üç formül bir arada:

▸ KATLAMA FORMÜL SETİ — Weierstrass \(y^2 = x^3 + ax + b\) üzerinde \(2P = (x_3, y_3)\)
m \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod{p}
x_3 \equiv m^2 - 2x_1 \pmod{p}
y_3 \equiv m(x_1 - x_3) - y_1 \pmod{p}
Kısıtlama: \(y_1 \neq 0\) olmalı. Eğer \(y_1 = 0\) ise teğet diktir ve \(2P = \mathcal{O}\) (sonsuz nokta).

Dejenere Durum: \(y_1 = 0\) ve Mertebe-2 Noktaları

Katlama formüllerinde paydanın \(2y_1\) olduğunu gördük. Eğer \(y_1 = 0\) ise bu payda sıfırlanır ve formül çöker — daha doğrusu, teğet eğimi sonsuz (\(\infty\)) olur, yani teğet doğrusu tam olarak diktir.

Bir noktanın y-koordinatının sıfır olması, o noktanın tam olarak x-ekseninde yattığı anlamına gelir. Eğrinin x-eksenine göre ayna simetrisi olduğunu hatırlayın: her \((x, y)\) noktası için \((x, -y)\) de eğri üzerindedir. \(y = 0\) olduğunda \(-y = 0\) da sıfırdır, yani nokta kendi negatifi ile özdeştir: \(-P = P\). Bu çarpıcı özellik ne anlama gelir?

P + (-P) = \mathcal{O} \implies P + P = \mathcal{O} \implies 2P = \mathcal{O}

Bir noktanın kendisi ile toplandığında sonsuz noktayı vermesi, grubun mertebe-2 (order-2) bir eleman içerdiği anlamına gelir. Bu noktalar eliptik eğrinin 2-torsion noktaları olarak adlandırılır. Kriptografik eğrilerde bu tür noktalar dikkatle yönetilir: güvenli bir üretici nokta \(G\) seçilirken \(2G \neq \mathcal{O}\) koşulu, yani \(G\)'nin mertebesi 2'den büyük olmalı koşulu zorunlu tutulur.

Pratikte secp256k1 ve P-256 gibi kriptografik eğrilerde tanımlanan üretici noktanın mertebesi, göresel asal (prime order) bir gruptur — yani bu grubun hiçbir elemanı mertebe-2 değildir. Bu tasarım kararı, hem katlama formülünün her zaman güvenle uygulanabilmesini sağlar, hem de grubun yapısını kriptografik saldırılara karşı dayanıklı kılar.

🔗

Nokta Toplama ile Katlama: Farklar ve Bağlantılar

Kriter Nokta Toplama (\(P + Q\)) Nokta Katlama (\(2P\))
Koşul \(P \neq Q\), yani \(x_1 \neq x_2\) \(P = Q\), yani aynı nokta kendisiyle
Geometrik Araç İki noktadan geçen kesen doğru (secant line) P noktasında eğriye çizilen teğet doğrusu
Eğim Formülü \(m = (y_2 - y_1)(x_2 - x_1)^{-1} \bmod p\) \(m = (3x_1^2 + a)(2y_1)^{-1} \bmod p\)
\(x_3\) Formülü \(m^2 - x_1 - x_2 \bmod p\) \(m^2 - 2x_1 \bmod p\)
\(y_3\) Formülü \(m(x_1 - x_3) - y_1 \bmod p\) — her iki durumda aynı
Dejenere Durum \(x_1 = x_2\) ve \(y_1 = -y_2\) → \(\mathcal{O}\) \(y_1 = 0\) → \(\mathcal{O}\) (mertebe-2)
Kriptografik Kullanım Genel grup işlemi, protokol seviyesi Skaler çarpım döngüsünün her adımı (\(kG\) hesabı)
🔢

Adım Adım Sayısal Örnek: \(\mathbb{F}_{97}\) Üzerinde \(2P\)

Aynı eğri ve alan üzerinde devam edelim: \(y^2 = x^3 + 7\) (\(a = 0, b = 7\)), \(p = 97\). Başlangıç noktamız olarak \(P = (3, 6)\) seçelim — \(a = 0\) olduğu için katlama formülü özellikle temizleşir.

1
Teğet Eğimini Hesapla
\(a = 0\) olduğundan pay basitleşir: \(3x_1^2 + 0 = 3x_1^2\). Payda için \((2 \cdot 6)^{-1} = 12^{-1} \bmod 97\)'yi hesaplıyoruz. Fermat Teoremi: \(12^{95} \bmod 97 = 89\).
m \equiv (3 \cdot 3^2) \cdot (2 \cdot 6)^{-1} \equiv 27 \cdot 12^{-1} \equiv 27 \cdot 89 \equiv 2403 \equiv 2403 - 24 \cdot 97 \equiv 75 \pmod{97}
2
x Koordinatını Bul
Katlama formülünde \(-x_1 - x_2 = -2x_1\) olduğuna dikkat edin. \(m^2\) hesaplanıp \(2x_1\) çıkarılıyor.
x_3 \equiv 75^2 - 2 \cdot 3 \equiv 5625 - 6 \equiv 5619 \equiv 5619 - 57 \cdot 97 \equiv 5619 - 5529 \equiv \mathbf{90} \pmod{97}
3
y Koordinatını Bul
\((x_1 - x_3)\) negatif çıkarsa \(p\) eklenerek pozitife alınır: \(3 - 90 = -87 \equiv 97 - 87 = 10 \pmod{97}\).
y_3 \equiv 75 \cdot (3 - 90) - 6 \equiv 75 \cdot 10 - 6 \equiv 750 - 6 \equiv 744 \equiv 744 - 7 \cdot 97 \equiv 744 - 679 \equiv \mathbf{65} \pmod{97}
Eğri Üzerinde Doğrulama
\(2P = (90, 65)\) noktasının gerçekten \(y^2 = x^3 + 7 \pmod{97}\) denklemini sağladığını kontrol edelim:
65^2 \equiv 4225 \equiv 4225 - 43 \cdot 97 \equiv 4225 - 4171 \equiv 54 \pmod{97}
90^3 + 7 \equiv 729000 + 7 \equiv 729007 \equiv 729007 \bmod 97 \equiv 54 \pmod{97} \quad \checkmark
Sonuç
\(P = (3, 6)\) noktasının katlaması sonuç noktayı doğrulandı. Bu nokta da tamamen \(\{0,\ldots,96\}\) kümesi içinde kalıyor; sistem kapalı ve tutarlı.
2P = (90,\ 65)

Katlama ile Skaler Çarpım: Double-and-Add Bağlantısı

Nokta katlamanın kriptografik açıdan neden bu kadar stratejik olduğunu anlamak için bir adım geriye çekilelim. ECC'de merkezi işlem, gizli anahtar \(k\) ve üretici nokta \(G\) ile gerçekleştirilen skaler çarpımdır: \(Q = k \cdot G\). Bu işlem matematiksel olarak \(G\)'nin \(k\) kez kendisiyle toplanmasıdır: \(G + G + G + \ldots + G\).

Eğer bunu naif bir döngüyle yapacak olsaydık — yani \(k\) adım \(G\) ekleseydik — 256 bitlik bir anahtar için \(2^{256}\) operasyon gerekirdi; evrenin ömründen uzun bir süre. Bunun yerine kullanılan Double-and-Add (İkile ve Topla) algoritması, ikili sayma sistemini kullanarak bu hesabı \(O(\log_2 k)\) operasyona, yani yaklaşık 256 adıma indirir.

Algoritmanın iki temel operasyonu vardır: Nokta toplama ve nokta katlama. Her bit için:

Bit Değeri Yapılan İşlem İçerik
Her bit Double (Katla) Mevcut sonucu 2 ile katla: \(R \leftarrow 2R\). Her zaman yapılır.
Bit = 1 Add (Topla) Üretici noktayı ekle: \(R \leftarrow R + G\). Yalnızca bit 1 olduğunda.
Bit = 0 Sadece Double Ekleme atlanır, yalnızca katlama yapılır.

Örnek olarak \(k = 13\) için:\(13 = 1101_2\) (binary). Algoritma şöyle çalışır:

Bit 1: Double → R = 2G, Add → R = 3G
Bit 1: Double → R = 6G, Add → R = 7G
Bit 0: Double → R = 14G (ekleme yok)
Bit 1: Double → R = 28G, Add → R = 29G...

256 bit için bu, 256 katlama + en fazla 256 toplama işlemi demektir. Toplamda \(\sim\)512 operasyon, birkaç milisaniye. Ve bu hesabın tersini yapmak — yani sadece \(G\) ve \(Q = kG\) bilindiğinde \(k\)'yı bulmak — hâlâ kriptografik açıdan imkânsız kabul edilmektedir.

Güvenlik Notu: Yan Kanal Saldırıları ve Sabit Zamanlı Katlama
Double-and-Add algoritmasında bit değerine bağlı olarak farklı işlemler yapılması (bit 0 → sadece double, bit 1 → double + add) bir güvenlik zafiyeti yaratır: saldırganlar CPU zaman ölçümü, güç tüketimi veya elektromanyetik yayılım analizi yoluyla hangi bitlerin 0, hangilerinin 1 olduğunu tespit edebilir ve gizli anahtarı elde edebilir. Bu timing/power side-channel attack olarak bilinir. Gerçek kütüphanelerde bunun yerine her bit için eşit sayıda işlem yapan constant-time Montgomery Ladder algoritması kullanılır.
🦀

Rust ile Nokta Katlama Implementasyonu

Aşağıdaki Rust kodu, nokta katlama operasyonunu point-addition.rs'teki altyapı üzerine genişletir. Aynı EllipticCurve struct'ı kullanılır; double() metodu ayrı olarak implemente edilmiş, scalar_mul() ise Double-and-Add algoritmasını uçtan uca çalıştırır. Sabit zamanlı bir conditional_select primitive'i de eklenmiştir.

ECC ARITHMETIC LAYER

point_doubling.rs

Nokta Katlama / Skaler Çarpım / Double-and-Add / Fp Aritmetik
MODULE READY
point_doubling.rs RUST
● Point Doubling · Scalar Mul · Fp
12345 678910 1112131415 1617181920 2122232425 2627282930 3132333435 3637383940 4142434445 4647484950 5152535455 5657585960 6162636465 6667686970 7172737475 7677787980
/// point_doubling.rs — EllipticCurve'e double() ve scalar_mul() ekleniyor.
/// point_addition.rs'teki Point enum ve EllipticCurve struct üzerine inşa edilir.
use crate::{EllipticCurve, Point};

impl EllipticCurve {
    /// Bir noktayı kendisiyle toplar: 2P.
    /// Dejenere durum: y₁ = 0 ise teğet dik, 2P = Infinity döner.
    pub fn double(&self, p: Point) -> Point {
        match p {
            // 2 * O = O (birim eleman sabit kalır)
            Point::Infinity => Point::Infinity,

            Point::Coordinate(x1, y1) => {
                // Dejenere: y₁ = 0 → teğet dik → 2P = O
                if y1 == 0 {
                    return Point::Infinity;
                }

                // m = (3x₁² + a) · (2y₁)⁻¹ mod p
                let numerator = (3 * x1 % self.p
                    * x1 % self.p
                    + self.a) % self.p;

                let denominator = self.mod_inv(2 * y1 % self.p);
                let m = numerator * denominator % self.p;

                // x₃ = m² - 2x₁ mod p
                let x3 = (m * m % self.p
                    + 2 * self.p          // negatif taşmayı önle
                    - 2 * x1 % self.p) % self.p;

                // y₃ = m(x₁ - x₃) - y₁ mod p
                let y3 = (m * ((x1 + self.p - x3) % self.p) % self.p
                    + self.p - y1) % self.p;

                Point::Coordinate(x3, y3)
            }
        }
    }

    /// Double-and-Add ile k·P skaler çarpımını hesaplar.
    /// Karmaşıklık: O(log₂ k) — 256-bit k için ~512 adım.
    pub fn scalar_mul(&self, mut k: u128, point: Point) -> Point {
        let mut result = Point::Infinity; // Birim eleman ile başla
        let mut addend = point;         // Katlanacak baz nokta

        while k > 0 {
            // En düşük bit 1 ise mevcut addend'i ekle
            if k & 1 == 1 {
                result = self.add(result, addend);
            }
            // Her adımda baz noktayı katla: G → 2G → 4G → 8G …
            addend = self.double(addend);
            k >>= 1; // bir sonraki bite geç
        }
        result
    }
}

fn main() {
    // y² = x³ + 7 (mod 97) üzerinde P = (3, 6)
    let curve = EllipticCurve { a: 0, p: 97 };
    let p = Point::Coordinate(3, 6);

    // Nokta katlama: 2P
    let doubled = curve.double(p);
    println!("2P = {:?}", doubled); // Beklenen: (90, 65)

    // Skaler çarpım: 13 * P
    let k13 = curve.scalar_mul(13, p);
    println!("13P = {:?}", k13);

    // Grup mertebesi doğrulaması: eğer n * G = O ise n mertebedir
    // (küçük örnek için n deneme yanılma ile bulunabilir)
    let p_doubled_again = curve.double(
        Point::Coordinate(0, 0)  // y = 0 → dejenere test
    );
    assert_eq!(p_doubled_again, Point::Infinity, "y=0 → 2P = O olmalı");
    println!("Dejenere durum doğrulandı: y=0 → 2P = O");
}