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)
Öne Çıkanlar
1
Teğet Yöntemi: Implicit Diferansiyel Türetme

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.

2
Skaler Çarpımın Temeli: Double-and-Add

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.

3
Dejenere Durum: Mertebe-2 Noktaları

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.

BÖLÜM 08

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.

Three.js Simülasyonu

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.

WebGL motoru başlatılıyor…
CANLI HESAP MATRİSİ Bekliyor...
Mod: Teğet Araması (P)
λ = 0.00
2P = —
Teğet
−2P
Yansıma
2P
Preset
İnteraktif Demo Rehberi

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.

01

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ş.

02

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.

03

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.

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.

\(y^2 = x^3 + ax + b\)
\(\frac{d}{dx}(y^2) = \frac{d}{dx}(x^3 + ax + b)\)
\(2y \cdot \frac{dy}{dx} = 3x^2 + a\)
\(m = \frac{dy}{dx} = \frac{3x^2 + a}{2y}\)

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.

\(m \equiv (3x_1^2 + a) \cdot (2y_1)^{-1} \pmod{p}\)
Bu formüldeki \((2y_1)^{-1}\), modüler çarpımsal tersidir. Fermat'ın Küçük Teoremi ile \((2y_1)^{p-2} \bmod p\) olarak hesaplanır. Gerçek sayılardaki bölme işleminin sonlu alanlardaki tam karşılığıdı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):

\(x_3 \equiv m^2 - 2x_1 \pmod{p}\)
Nokta toplamadaki formülle karşılaştırın: \(x_3 = m^2 - x_1 - x_2\). Katlama durumunda \(x_1 = x_2\) olduğundan \(-x_1 - x_2 = -2x_1\) olur — formüller tutarlıdır.
\(y_3 \equiv m(x_1 - x_3) - y_1 \pmod{p}\)

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).
g�?�

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:

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

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ı)
g���

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: \(y^2 = x^3 + 7\) \(p = 97\) \(a = 0\) \(P = (3, 6)\)
\(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}\)
\(m \equiv 27 \cdot 12^{-1} \equiv 27 \cdot 89\)
\(m \equiv 2403 \equiv 2403 - 24 \cdot 97 \equiv\) 75 \(\pmod{97}\)
✓ Sonuç: \(m = 75\)
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\)
\(x_3 \equiv 5625 - 6 \equiv 5619\)
\(x_3 \equiv 5619 - 57 \cdot 97 \equiv\) 90 \(\pmod{97}\)
✓ Sonuç: \(x_3 = 90\)
\((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\)
\(y_3 \equiv 75 \cdot 10 - 6 \equiv 750 - 6\)
\(y_3 \equiv 744 - 7 \cdot 97 \equiv\) 65 \(\pmod{97}\)
✓ Sonuç: \(y_3 = 65\)

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 54 \pmod{97}\)
\(90^3 + 7 \equiv 729000 + 7 \equiv 729007 \equiv 54 \pmod{97}\)
\(54 \equiv 54\) \(\checkmark\)

\(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ı.

⊗ Sonuç: \(2P = (90,\ 65)\)
g���

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:

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.
g���

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
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
/// 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");
}