來看一個橢圓曲線(elliptic curve)與直線(line)的聯立方程式,已知兩個交點分別是 P(xp, yp)及 Q(xq, yq),直線斜率是 s
y2 = x3 + ax2 + bx --- (1)
y = s(x -xp) + yp --- (2)
先假設 P 與 Q 是兩個不同點,通過這兩點的直線斜率 s 可以很容易計算出來:
s = (yp - yq) / (xp - xq) --- (3)
將第(2)式代入第(1)式得到
(s(x - xp) + yp)2 = x3 + ax2 + bx --- (4)
我們已知上述聯立方程式應該有 3 個解,我們目的就是要解出最後的第 3 交點(解),假設它是 R(xr, yr), 這 3 個交點的 x 座標分別是 xp, xq, xr, 正好是方程式的解,換句話說這 3 個解一定是上述聯立方程式的根,因此(4)式就可以寫成:
(x - xp)(x - xq)(x - xr) = 0 --- (5)
將第(4)式與第(5)式分別展開,但只需關注 x2 項的係數就可,無需全部展開:
(a - s2) x 2 = - (xp + xq + xr) x2 --- (6)
比較係數得出 xr 的關係式,加上第(2)與(3)式,就可以定義出一個 ECC 的加法運算法則(因為 P + Q = - R),經此推導.可知第 3 交點位置在 R(xr, yr)
s = (yp - yq) / (xp - xq) --- (7)
xr = s2 - xp - xq - a --- (8)
-yr = s(xp - xr) - yp --- (9)
可是當 P 與 Q 重疊時(dual root), 導致第(7)式的斜率無法運算,兩個點重疊(double)的斜率其實就是橢圓曲線的切線斜率,因此將式(1)分別對 x 作微分並移項得到
dy/dx = (3 x2 + 2 a x + b) / 2y --- (10)
將切點(xp, yp)代入公式就可算出切點的斜率,因為此時 P 與 Q 點重疊(xr, xq) = (yr, yq),我們可以定義出所謂的加倍運算法則(因為 P + P=2P = -R' 就是加倍的意思),只要修正用橢圓曲線的切點斜率(等於定義了兩個交點在同一位置)去取代直線斜率,這樣就可計算出另外第 3 交點的位置在 R'(xr, yr)
s = (3 x2 + 2a x + b) / 2y where (x, y)=(xp, yp) -- (11)
xr = s2 - 2xp - a --- (12)
-yr = s(xp - xr) - yp --- (13)
綜合上述,我們在橢圓曲線與直線交點的基礎規範下,進行 P + Q = -R 的運算,可以用加法程序(在第 7, 8, 9 式)或加倍程序(在第 11 ,12, 13 式)來計算出第 3 交點 R(xr, yr).其中加法程序是用在兩個不同點的相加, 而加倍程序則用在相同點的累加,只要知道一個交點,我們稱為之基準點(G),先透過加倍程序,找出其 2 倍(2P)座標點(也就是2G),利用加法程序將 2 倍座標點(2G)與基準座標點(G)相加(add)算出 3 倍座標點(3G),再利用兩倍的兩倍,累加計算出 4 倍座標點(4G), ... 以此類推得到 n 倍基準座標點(nG).這個 n(稱為 scale) 倍數的座標點,利用的是倍加原理(double and add)的疊代運算逐漸產生新的座標點,但有一點要注意的是當兩個座標點累加去計算出另一座標點的時候(不管是 P + Q = -R 或是 P + P =2P),我們不是要曲線與直線的交點座標 R, 而是要它鏡像點的座標 -R,上面聯立方程式推導的(xr, yr)是交點的座標,因為在 y 軸上,交點與其鏡像點座標是互為反數的關係,因此我們只要將上述推導出的 y 軸座標值轉成負數就可,這就是上述式子中用 -yr 的原因,因為它代表了座標點的位置. 用 Kotlin 語法加上它有 operator overloading 的特性,可以寫出很容易明瞭的程式:
import java.math.BigInteger // 大數運算先要載入 java.math.BigInteger 的模組:
class Curve383187 (key: BigInteger = BigInteger.ONE) { // Curve383187 :: y2=x3 + ax2 +bx mod p
private val p = BigInteger("2").pow(383).subtract( BigInteger("187") ) // p = 2383 - 187
private val a = BigInteger("229969") // a = 229969
private val b = BigInteger("1") // b=1
private var x = BigInteger("5")
private var y = BigInteger("4759238150142744228328102229734187233490253962521130945928672202662038422584867624507245060283757321006861735839455")
init { // key * G(x,y)
if (key != BigInteger.ONE) scale(key, x, y)
}
private infix fun BigInteger.mod(another: BigInteger) : BigInteger { return rem(another) } // %
private operator fun BigInteger.plus(another: BigInteger) : BigInteger { return add(another) mod p }// +
private operator fun BigInteger.minus(another: BigInteger) : BigInteger { return subtract(another) mod p }// -
private operator fun BigInteger.times(another: BigInteger) : BigInteger { return multiply(another) mod p }// *
private operator fun BigInteger.div(another: BigInteger) : BigInteger { return multiply(another.modInverse(p)) mod p } // ÷
fun isPoint() : Boolean { return y * y == x * x * x + a * x * x + b * x } // y2 = x3 + ax2 +bx
operator fun times(n: BigInteger) : Curve383187 {
var c = Curve383187( ) // new object
return c.scale(n, this.x, this.y) // return c object
}
private fun scale(n: BigInteger, Gx: BigInteger, Gy: BigInteger ) : Curve383187 {
var k = 1024 // number of bits
val num = n mod p // Double And Add algorithm to scale G(x,y)
if (num == BigInteger.ZERO) { println("Error, scale num is 0"); return this }
val big3=BigInteger("3")
val big2=BigInteger("2")
while( k-- > 0 ) if ( num.testBit(k) ) break
x = Gx; y = Gy // initialize P(x, y) = G(x,y)
while( k-- > 0 ){ // Doubler slope = (3x2 + 2ax + b) / 2y
var xp = x // store x to caculate 2P(x, y) = -R'(x, y)
var s = (big3 * x * x + big2 * a * x + b) / (big2 * y)
x = s * s - big2 * xp - a // R'.x = s2 - 2xp - a
y = s * (xp - x) - y // - R'.y = s(xp - x) - yp
if ( num.testBit(k) ) { // P(x, y) + G(x,y) = - R(x, y)
s = (y - Gy )/( x - Gx) // Adder slope = (y - G.y) / (x - G.x)
x = s * s - x - Gx - a // R.x = s2 - x - G.x - a
y = s * (Gx - x) - Gy // -R.y = s(G.x - x) - G.y
}
}
if (x < BigInteger.ZERO) x = x + p mod p
if (y < BigInteger.ZERO) y = y + p mod p
return this // return self object
} // end of scale
fun listpoint() {
println("\n\tx="+x.toString(16)+"\n\ty="+y.toString(16))
}
}// End of class Curve383187
fun main(args:Array < String > ) {
var keyA = BigInteger("9").pow(87).subtract(BigInteger("65") ) // Alice pickup a key
var keyB = BigInteger("4").pow(32).subtract(BigInteger("10") ) // Bob pickup a key
var key = keyA*keyB // Nobody knowns this share key
var pubA = Curve383187(keyA) // Alice send public key to Bob
var pubB = Curve383187(keyB) // Bob send public key to Alice
var keyECC= Curve383187(key) // Caculate the ECC of the secret to double check
var Alice= pubB * keyA // Alice use self key to decode pubB sent from Bob
var Bob = pubA * keyB // Bob use self key to decode pubA sent from Alice
pubA.listpoint() ; println("Public@ECC(x,y) from Alice key:\n\t"+keyA.toString())
pubB.listpoint() ; println("Public@ECC(x,y) from Bob key:\n\t" +keyB.toString())
keyECC.listpoint(); println("Share @ECC(x,y) from Secret key:\n\t"+key.toString())
Alice.listpoint() ; println("Alice key decode:")
Bob.listpoint() ; println("Bob key decode:")
println("\nAlice on curve ? "+Alice.isPoint()+ " Bob on curve ? " +Bob.isPoint())
}
輸出結果:
x=2a4c00dc2e8acb66b527ae0cddaeb9b373dfe0e7b3ef9b86e38b7b39d55e3f24f25cc5608a45e66acc96eddd40578daf
y=5c18f88677e650fa6cad33a14a961adc0db96739fcfb39c7b600a3e106ed0aafe705271408a522dd582ff6ce9d8fe37f
Public@ECC(x,y) from Alice key:
104495676331778315966103878903450701989608781073244439950619431748912396904023371704
x=2989c08b718a4fc3bfe8cc3da96e5d7d975f6c58802700eb2f5ca018e70bbdb3d5c03671053eed8ee94adaed23dfcac0
y=37eb8fa79a5ee1caa076518b1abf3249e5fd560a95acf3ad6e22a27055d51c9dcb974988c9a2f99b6f68afcece7c7570
Public@ECC(x,y) from Bob key:
18446744073709551606
x=381dcd3a1bdea34760212d276c7d21940d315a4d547af3c520aba80a2ff4e38e0e548dd9d0038c1ce5c3eb36acf6960b
y=3491be994e90f4e9b28352b5c0495c5f395dba99fe2fa870553351be77e363c67392e3c3feb2fed711b5d187c63afbbb
Share @ECC(x,y) from Secret key:
1927604998101503106558917489994263425013278054390180757461516411290410360277764861810797121646108156624
x=381dcd3a1bdea34760212d276c7d21940d315a4d547af3c520aba80a2ff4e38e0e548dd9d0038c1ce5c3eb36acf6960b
y=3491be994e90f4e9b28352b5c0495c5f395dba99fe2fa870553351be77e363c67392e3c3feb2fed711b5d187c63afbbb
Alice key decode:
x=381dcd3a1bdea34760212d276c7d21940d315a4d547af3c520aba80a2ff4e38e0e548dd9d0038c1ce5c3eb36acf6960b
y=3491be994e90f4e9b28352b5c0495c5f395dba99fe2fa870553351be77e363c67392e3c3feb2fed711b5d187c63afbbb
Bob key decode:
Alice on curve ? true Bob on curve ? true
沒有留言:
張貼留言