Nokta katlama işlemi, kesen doğru yerine teğet doğrusu kullanılır. Teğetin eğimi, implicit diferansiyel türev ile λ = (3x² + a) / 2y formülünden hesaplanır. Bu işlem, P + P = 2P hesabının geometrik temelidir.
256-bitlik bir gizli anahtar k için Q = k·G hesabı, binlerce nokta katlaması içerir. Double-and-Add algoritması, bu işlemi O(log₂k) karmaşıklığa indirerek ECC'nin verimliliğini sağlar. Bitcoin, TLS ve Ethereum'un temelinde bu algoritma yatar.
y₁ = 0 olduğunda payda sıfırlanır ve formül çöker. Bu durumda 2P = 𝒪 (sonsuz nokta) olur. Kriptografik eğrilerde güvenli üretici nokta seçimi, mertebe-2 noktalardan kaçınarak sistemin dayanıklılığını artırır.
Nokta Matematiği: Geometrik Katlama
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.
Teğet Sarkaç (Tangent Accelerator)
Tek bir noktayı (P) hareket ettirerek teğet doğrusunun eğimini anlık izleyin. "Katla" butonuna bastığınızda, teğet uzayıp -2P'yi vuracak ve yansıyarak 2P noktasını kilitleyecek.
Kullanım Kılavuzu: Teğet Sarkaç
Bu simülasyon, eliptik eğri y² = x³ - 4x üzerinde nokta katlama işlemini teğet animasyonu ile gösterir. Eğri neon tüp (TubeGeometry) olarak render edilir; nokta koordinatları Nokta Toplama demosu ile aynı t eşlemesini kullanır. SCALAR = 1.2 ile görselleştirilir.
Nokta Kontrolü
P slider: t parametresi [-100, 100] aralığında. Loop bileşeni (|t| ≤ 50): x in [-2, 0]. Açık dal (|t| > 50): x in [2, 10]. Teğet sarkacı otomatik olarak eğriye teğet kalır.
Önerilen değer: P=-90 (alt dal, x≈7.1). y=0 durumunda dikey teğet moduna geçiş.
Teğet Modu
λ (lambda) hesabı: λ = (3x² - 4) / (2y). Dikey mod: |y| < 0.001 olduğunda λ=∞, 2P=∞ (sonsuz atış).
Kriz senaryosu: Dikey modda lazer sonsuza gider, animasyon devre dışı. Buton opacity 0.5.
Animasyon ve Kamera
Animasyon adımları: Teğet uzatma (1.5s) → −2P kesişimi + shockwave → yansıma → 2P kilitleme. Kamera: OrbitControls ile döndürün; sağ üstteki ◎ Merkezle varsayılan görünüme döner.
Görsel Harita: Sağ üstte P/−2P/2P renkleri; animasyonla aktif noktalar vurgulanır. Cam HUD sol üstte λ, 2P özeti ve adım izleme sunar.
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.
İ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.
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ı
Teğetin eğimini bulduktan sonra, nokta toplamadaki üç adımı aynı şekilde uygularız. Tek fark şudur: genel toplama formüllerinde iki ayrı nokta \(P = (x_1, y_1)\) ve \(Q = (x_2, y_2)\) vardı; katlama formüllerinde ise tek bir nokta \(P = (x_1, y_1)\) mevcuttur ve \(x_2 = x_1\), \(y_2 = y_1\) olarak düşünülür.
Teğet doğrusu \(y = m(x - x_1) + y_1\)'i Weierstrass denklemine koyduğumuzda kübik bir denklem elde ederiz. Vieta formüllerine göre bu kübik denklemin üç kökünün toplamı \(m^2\)'ye eşittir. Köklerden ikisi \(x_1\) ve \(x_1\) olduğundan (katlama, P'yi kendine eklemek olduğu için \(x_1\) çift kök):
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:
Dejenere Durum: \(y_1 = 0\) ve Mertebe-2 Noktaları
Eliptik eğri üzerindeki nokta toplama ve katlama (doubling) formülleri incelendiğinde, işlemin paydasında yer alan \(2y_1\) terimi kritik bir rol oynar. Eğer bir \(P = (x_1, y_1)\) noktası için \(y_1 = 0\) şartı sağlanırsa, bu payda sıfıra eşitlenir ve standart formül hesaplanamaz hale gelir; yani işlem "çöker". Geometrik perspektiften bakıldığında bu durum, söz konusu noktadaki teğet doğrusunun eğiminin sonsuz (\(\infty\)) olduğu, başka bir deyişle teğet doğrusunun x-eksenine tam olarak dik (vertikal) bir konumda olduğu anlamına gelir.
Bir noktanın y-koordinatının sıfır olması, bu noktanın doğrudan x-ekseni üzerinde konumlandığını işaret eder. Weierstrass formundaki eliptik eğrilerin x-eksenine göre yansıyan bir ayna simetrisine sahip olduğu gerçeği göz önüne alındığında, eğri üzerindeki her \((x, y)\) noktası için onun negatifi olan \((x, -y)\) noktası da eğri üzerinde yer alır. Ancak \(y = 0\) olduğu özel durumda \(-y = 0\) olduğundan, nokta kendi negatifi ile özdeştir; yani \(P = -P\) denklemi sağlanır. Bu geometrik özdeşlik, eliptik grup teorisinde oldukça dikkat çekici bir sonuca yol açar:
Bir noktanın kendisi ile toplanması sonucunda "sonsuzdaki noktayı" (\(\mathcal{O}\)) vermesi, grubun mertebe-2 (order-2) bir eleman barındırdığını kanıtlar. Matematiksel literatürde bu tür noktalar "2-torsion noktaları" olarak adlandırılır. Kriptografik sistemlerin tasarımı aşamasında, bu noktalar potansiyel bir zafiyet kaynağı olabileceği için oldukça titizlikle yönetilir. Özellikle güvenli bir üretici nokta \(G\) seçimi sırasında \(2G \neq \mathcal{O}\) koşulu esas alınır; bu, seçilen üreticinin mertebesinin 2'den kesinlikle büyük olması gerektiğini şart koşar.
Pratik uygulamalarda kullanılan secp256k1 veya NIST P-256 gibi standart kriptografik eğrilerde, tanımlanan üretici noktanın oluşturduğu grubun mertebesi büyük bir asal sayıdır. Bu tercih, grubun "asal mertebeli" (prime order) olmasını sağlayarak, grup içerisinde hiçbir elemanın mertebe-2 olmamasını garantiler. Bu stratejik tasarım kararı, hem katlama formüllerinin hiçbir istisnai durumla karşılaşmadan (sıfıra bölme hatası almadan) güvenle uygulanabilmesine olanak tanır hem de grubun alt gruplara bölünmesini engelleyerek Polig-Hellman gibi kriptografik saldırılara karşı sistemin direncini en üst seviyeye çıkarır.
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\)
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.
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:
\(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ı.
Katlama ile Skaler Çarpım: Double-and-Add Bağlantısı
Nokta katlama (point doubling) operasyonunun kriptografik sistemlerde neden vazgeçilmez ve stratejik bir öneme sahip olduğunu kavramak için, eliptik eğri şifrelemesinin (ECC) çalışma prensibine daha yakından bakmamız gerekir. ECC protokollerindeki temel hesaplama yükü, bir gizli anahtar olan \(k\) skaler değeri ile eğri üzerindeki tanımlı bir üretici nokta \(G\) arasında gerçekleştirilen skaler çarpım işlemidir: \[ Q = k \cdot G \] Matematiksel tanımı itibarıyla bu işlem, üretici nokta \(G\)'nin kendisiyle \(k\) kez ardışık olarak toplanması, yani \(G + G + G + \ldots + G\) dizisinin hesaplanmasıdır. Eğer bu işlemi teorik olarak "naif" bir toplama döngüsüyle uygulamaya çalışsaydık, \(k\) değerinin büyüklüğü ile doğru orantılı olarak işlem karmaşıklığı da doğrusal bir şekilde artardı.
Modern kriptografide kullanılan standart bir 256-bitlik anahtar uzunluğu göz önüne alındığında, naif bir döngü yaklaşımı yaklaşık \(2^{256}\) adet toplama operasyonu gerektirirdi; bu devasa rakam, günümüzün en hızlı işlemcilerinin dahi hesaplamasını tamamlaması için evrenin yaşından çok daha uzun bir süreye ihtiyaç duyacağı anlamına gelir. Bu verimsizliği ortadan kaldırmak için, ikili sayı sisteminin (binary representation) gücünden yararlanan Double-and-Add (İkile ve Topla) algoritması devreye girer. Bu algoritma, gizli anahtarı \(k\) bitlerine ayırarak süreci modüler bir yapıya dönüştürür; her adımda noktayı ya "katlar" (double) ya da toplama işlemi (add) gerçekleştirir. Bu yöntem, işlem karmaşıklığını \(O(k)\) seviyesinden, çok daha verimli olan \(O(\log_2 k)\) seviyesine, yani toplamda yaklaşık 256 adıma kadar indirgeyerek, kriptografik işlemlerin milisaniyeler içerisinde güvenle tamamlanmasını mümkün kılar.
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:
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.
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.
/// 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");
}