• Source
    1. //Bitcoin, Ethereum etc多樣密碼貨幣都用secp256k1這條橢圓曲線。
    2. //本程式實做了secp256k1這條橢圓曲線上的「純量乘法」(未優化)。要明白
    3. //ECC的困難在於,已知兩點Q, P且某未知正整數n使得Q=[n]P,求n=?
    4. //此稱為EC Discrete Log難題。
    5. //programmed by anwendeng
    6. import java.security.spec.*;
    7. import java.security.SecureRandom;
    8. import java.math.*;
    9.  
    10. class Main
    11. //secp256k1
    12. {
    13. //橢圓曲線E: y^2=x^3+a*x+b (mod p)
    14. static EllipticCurve E;
    15. static BigInteger a=BigInteger.ZERO;
    16. static BigInteger b=BigInteger.valueOf(7);
    17. static ECFieldFp Fp;
    18. //p=2**256 - 2**32 - 977
    19. static BigInteger p=new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",16);
    20.  
    21. final static BigInteger ZERO=BigInteger.ZERO;
    22. final static BigInteger ONE=BigInteger.ONE;
    23. final static BigInteger TWO=BigInteger.valueOf(2);
    24. final static BigInteger THREE=BigInteger.valueOf(3);
    25. final static BigInteger FOUR=BigInteger.valueOf(4);
    26. final static BigInteger Int27=BigInteger.valueOf(27);
    27. final static ECPoint Inf=ECPoint.POINT_INFINITY;
    28.  
    29. static BigInteger x(ECPoint P){ return P.getAffineX();}
    30. static BigInteger y(ECPoint P){ return P.getAffineY();}
    31.  
    32. public static ECPoint add(ECPoint P, ECPoint Q)
    33. {//P+Q
    34. BigInteger m;// 穿越P,Q直線斜率
    35. if (P.equals(Inf)) return Q;
    36. else if (Q.equals(Inf)) return P;
    37. else if (P.equals(Q) && y(P).equals(ZERO))
    38. return Inf;
    39. else if (x(P).equals(x(Q)) && !y(P).equals(y(Q)))
    40. return Inf;
    41. else if (P.equals(Q))
    42. //m=(3*x(P)^2+a)*(2*y(P))^(-1)%p
    43. m=THREE.multiply(x(P).modPow(TWO,p)).add(a).
    44. multiply(TWO.multiply(y(P)).modInverse(p)).mod(p);
    45. else
    46. //m=(y(Q)-y(P))*(x(Q)-x(P))^(-1)%p
    47. m=y(Q).subtract(y(P)).multiply(x(Q).subtract(x(P)).
    48. modInverse(p)).mod(p);
    49.  
    50. //x(R)=m^2-x(P)-x(Q)%p
    51. BigInteger xR=m.modPow(TWO,p).subtract(x(P)).
    52. subtract(x(Q)).mod(p);
    53.  
    54. //y(R)=m*(x(P)-x(R))-y(P)%p
    55. BigInteger yR=m.multiply(x(P).subtract(xR)).
    56. subtract(y(P)).mod(p);
    57. return new ECPoint(xR,yR);
    58. }
    59.  
    60. public static ECPoint minus(ECPoint P)
    61. {//[-1]P
    62. BigInteger yP=y(P).negate().mod(p);
    63. return new ECPoint(x(P),yP);
    64. }
    65.  
    66. public static ECPoint multiply(BigInteger n, ECPoint P)
    67. {//使用LSBF二元法算[n]P
    68. if(n.signum()<0)
    69. {//n<0
    70. n=n.negate();
    71. P=minus(P);
    72. //[n]P=[-n](-P)
    73. }
    74. ECPoint R=Inf;
    75. while (!n.equals(ZERO))
    76. {
    77. if(n.testBit(0))// n%2==1
    78. R=add(R,P);
    79. n=n.shiftRight(1);// n=n>>1
    80. P=add(P,P);
    81. }
    82. return R;
    83. }
    84.  
    85. public static void main(String[] agv) throws Exception
    86. {
    87. SecureRandom rnd=new SecureRandom();
    88. System.out.println(p.bitLength()+"-bit質數p=\n"+p);
    89. Fp=new ECFieldFp(p);
    90.  
    91. //base point G的座標
    92. BigInteger xP=new BigInteger("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",16);
    93. BigInteger yP=new BigInteger("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",16);
    94. ECPoint P=new ECPoint(xP,yP);
    95.  
    96. E=new EllipticCurve(Fp,a,b);
    97. System.out.println("橢圓曲線E/Fp:");
    98. System.out.println("a="+a);
    99. System.out.println("b="+b);
    100.  
    101. System.out.println("點G(=P)座標:");
    102. System.out.println("xP="+xP);
    103. System.out.println("yP="+yP);
    104.  
    105. BigInteger n;
    106.  
    107. ECPoint Q,Q2;
    108. long start,end,t0,t1;;
    109. double ratio;
    110.  
    111. for(int i=0;i<5;i++){
    112. n=new BigInteger(254,rnd);
    113. System.out.println("=====================================================");
    114. System.out.println("n="+n);
    115. start=System.nanoTime();
    116. Q=multiply(n,P);
    117. end=System.nanoTime();
    118.  
    119. System.out.println("Q=[n]P座標:");
    120. if (Q.equals(Inf)) System.out.println("Inf");
    121. System.out.println("xQ="+x(Q));
    122. System.out.println("yQ="+y(Q));
    123. t0=end-start;
    124.  
    125. //System.out.println(Q.equals(Q2));
    126. System.out.printf("multiply()計算時間: %12d nanosec.\n",t0);
    127. }
    128. }
    129. }
    130.