All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java-ec.com.unbound.common.crypto.ec.SunEC Maven / Gradle / Ivy

Go to download

This is a collection of JAVA libraries that implement Unbound cryptographic classes for JAVA provider, PKCS11 wrapper, cryptoki, and advapi

There is a newer version: 42761
Show newest version
package com.unbound.common.crypto.ec;

import javax.crypto.KeyAgreement;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.*;
import java.time.Clock;

public final class SunEC
{
  public static final class Curve
  {
    private ECGenParameterSpec genSpec;
    private AlgorithmParameters algParam;
    private ECParameterSpec spec;
    private EllipticCurve ec;
    private ECFieldFp field;
    public ECPoint G;
    public BigInteger q;
    public BigInteger p;
    public BigInteger a;
    public BigInteger b;
    public int bits;
    public int size;

    private Curve(String name)
    {
      genSpec = new ECGenParameterSpec(name);
      try
      {
        algParam = AlgorithmParameters.getInstance("EC");
        algParam.init(genSpec);
        spec = algParam.getParameterSpec(ECParameterSpec.class);
        q = spec.getOrder();
        G = spec.getGenerator();
        bits = q.bitLength();
        size = (bits + 7) / 8;
        ec = spec.getCurve();
        a = ec.getA();
        b = ec.getB();
        field = (ECFieldFp) ec.getField();
        p = field.getP();
      }
      catch (NoSuchAlgorithmException | InvalidParameterSpecException e)
      {
        throw new RuntimeException(e);
      }
    }

    private static class Arithmetic
    {
      public static final BigInteger ZERO = BigInteger.valueOf(0);
      public static final BigInteger ONE = BigInteger.valueOf(1);
      public static final BigInteger TWO = BigInteger.valueOf(2);
      public static final BigInteger FOUR = BigInteger.valueOf(4);

      private static final int[] jacobiTable = {0, 1, 0, -1, 0, -1, 0, 1};

      public static int jacobi(BigInteger A, BigInteger B)
      {
        BigInteger a, b, v;
        long k = 1;

        k = 1;

        // test trivial cases
        if (B.equals(ZERO))
        {
          a = A.abs();
          return a.equals(ONE) ? 1 : 0;
        }

        if (!A.testBit(0) && !B.testBit(0))
        {
          return 0;
        }

        a = A;
        b = B;

        if (b.signum() == -1)
        { // b < 0
          b = b.negate(); // b = -b
          if (a.signum() == -1)
          {
            k = -1;
          }
        }

        v = ZERO;
        while (!b.testBit(0))
        {
          v = v.add(ONE); // v = v + 1
          b = b.divide(TWO); // b = b/2
        }

        if (v.testBit(0))
        {
          k = k * jacobiTable[a.intValue() & 7];
        }

        if (a.signum() < 0)
        { // a < 0
          if (b.testBit(1))
          {
            k = -k; // k = -k
          }
          a = a.negate(); // a = -a
        }

        // main loop
        while (a.signum() != 0)
        {
          v = ZERO;
          while (!a.testBit(0))
          { // a is even
            v = v.add(ONE);
            a = a.divide(TWO);
          }
          if (v.testBit(0))
          {
            k = k * jacobiTable[b.intValue() & 7];
          }

          if (a.compareTo(b) < 0)
          { // a < b
            // swap and correct intermediate result
            BigInteger x = a;
            a = b;
            b = x;
            if (a.testBit(1) && b.testBit(1))
            {
              k = -k;
            }
          }
          a = a.subtract(b);
        }

        return b.equals(ONE) ? (int) k : 0;
      }

      public static BigInteger sqrtP(BigInteger a, BigInteger p)
              throws IllegalArgumentException
      {

        BigInteger v = null;

        if (a.compareTo(ZERO) < 0)
        {
          a = a.add(p);
        }

        if (a.equals(ZERO))
        {
          return ZERO;
        }

        if (p.equals(TWO))
        {
          return a;
        }

        // p = 3 mod 4
        if (p.testBit(0) && p.testBit(1))
        {
          if (jacobi(a, p) == 1)
          { // a quadr. residue mod p
            v = p.add(ONE); // v = p+1
            v = v.shiftRight(2); // v = v/4
            return a.modPow(v, p); // return a^v mod p
            // return --> a^((p+1)/4) mod p
          }
          throw new IllegalArgumentException("No quadratic residue: " + a + ", " + p);
        }

        long t = 0;

        // initialization
        // compute k and s, where p = 2^s (2k+1) +1

        BigInteger k = p.subtract(ONE); // k = p-1
        long s = 0;
        while (!k.testBit(0))
        { // while k is even
          s++; // s = s+1
          k = k.shiftRight(1); // k = k/2
        }

        k = k.subtract(ONE); // k = k - 1
        k = k.shiftRight(1); // k = k/2

        // initial values
        BigInteger r = a.modPow(k, p); // r = a^k mod p

        BigInteger n = r.multiply(r).remainder(p); // n = r^2 % p
        n = n.multiply(a).remainder(p); // n = n * a % p
        r = r.multiply(a).remainder(p); // r = r * a %p

        if (n.equals(ONE))
        {
          return r;
        }

        // non-quadratic residue
        BigInteger z = TWO; // z = 2
        while (jacobi(z, p) == 1)
        {
          // while z quadratic residue
          z = z.add(ONE); // z = z + 1
        }

        v = k;
        v = v.multiply(TWO); // v = 2k
        v = v.add(ONE); // v = 2k + 1
        BigInteger c = z.modPow(v, p); // c = z^v mod p

        // iteration
        while (n.compareTo(ONE) == 1)
        { // n > 1
          k = n; // k = n
          t = s; // t = s
          s = 0;

          while (!k.equals(ONE))
          { // k != 1
            k = k.multiply(k).mod(p); // k = k^2 % p
            s++; // s = s + 1
          }

          t -= s; // t = t - s
          if (t == 0)
          {
            throw new IllegalArgumentException("No quadratic residue: " + a + ", " + p);
          }

          v = ONE;
          for (long i = 0; i < t - 1; i++)
          {
            v = v.shiftLeft(1); // v = 1 * 2^(t - 1)
          }
          c = c.modPow(v, p); // c = c^v mod p
          r = r.multiply(c).remainder(p); // r = r * c % p
          c = c.multiply(c).remainder(p); // c = c^2 % p
          n = n.multiply(c).mod(p); // n = n * c % p
        }
        return r;
      }

      public static BigInteger subP(BigInteger a, BigInteger b, BigInteger p)
      {
        if (a.compareTo(b) >= 0) return a.subtract(b);
        return a.add(p).subtract(b);
      }

      public static BigInteger divP(BigInteger a, BigInteger b, BigInteger p)
      {
        BigInteger inv = b.modInverse(p);
        return a.multiply(inv).mod(p);
      }
    }

    private BigInteger subP(BigInteger x, BigInteger y)
    {
      return Arithmetic.subP(x, y, p);
    }

    private BigInteger divP(BigInteger x, BigInteger y)
    {
      return Arithmetic.divP(x, y, p);
    }

    public ECPoint add(ECPoint a, ECPoint b)
    {
      BigInteger x2, y2;
      BigInteger x0 = a.getAffineX();
      BigInteger y0 = a.getAffineY();
      BigInteger x1 = b.getAffineX();
      BigInteger y1 = b.getAffineY();
      BigInteger s;
      if (a.equals(b))
      {
        BigInteger TWO = BigInteger.valueOf(2);
        BigInteger THREE = BigInteger.valueOf(3);
        s = divP(x0.multiply(x0).multiply(THREE).add(this.a).mod(p), y0.multiply(TWO.mod(p)));
      }
      else
      {
        s = divP(subP(y0, y1), subP(x0, x1));
      }

      x2 = subP(subP(s.multiply(s).mod(p), x0), x1);
      y2 = subP(subP(x0, x2).multiply(s).mod(p), y0);
      return new ECPoint(x2, y2);
    }


    public ECPrivateKey getPrivateKey(BigInteger d)
    {
      try
      {
        return (ECPrivateKey) KeyFactory.getInstance("EC").generatePrivate(new ECPrivateKeySpec(d, spec));
      }
      catch (Exception e)
      {
        throw new IllegalArgumentException(e);
      }
    }

    public ECPublicKey getPublicKey(ECPoint point)
    {
      try
      {
        return (ECPublicKey) KeyFactory.getInstance("EC").generatePublic(new ECPublicKeySpec(point, spec));
      }
      catch (Exception e)
      {
        throw new IllegalArgumentException(e);
      }
    }

    public static byte[] ecdh(KeyAgreement ka, ECPrivateKey prv, ECPublicKey pub)
    {
      try
      {
        if (ka==null) ka = KeyAgreement.getInstance("ECDH");
        ka.init(prv);
        ka.doPhase(pub, true);
        return ka.generateSecret();
      }
      catch (Exception e)
      {
        throw new IllegalArgumentException(e);
      }
    }
    public static byte[] ecdh(ECPrivateKey prv, ECPublicKey pub)
    {
      return ecdh(null, prv, pub);
    }

    public ECPoint mul(ECPrivateKey prvKey, BigInteger d, ECPublicKey pubKey, ECPoint p)
    {
      return mul(null, prvKey, d, pubKey, p);
    }

    public ECPoint mul(KeyAgreement ka, ECPrivateKey prvKey, BigInteger d, ECPublicKey pubKey, ECPoint p)
    {
      if (prvKey == null) prvKey = getPrivateKey(d);

      if (pubKey == null) pubKey = getPublicKey(p);
      if (p == null) p = pubKey.getW();

      BigInteger x = new BigInteger(1, ecdh(ka, prvKey, pubKey));

      BigInteger d1 = prvKey.getS().add(BigInteger.ONE);
      ECPrivateKey next = getPrivateKey(d1);
      BigInteger xNext = new BigInteger(1, ecdh(next, pubKey));

      BigInteger y0 = recoverY(x, false);
      ECPoint point = new ECPoint(x, y0);
      BigInteger xTest = add(point, p).getAffineX();
      if (xTest.equals(xNext)) return point;

      BigInteger y1 = field.getP().subtract(y0);
      return new ECPoint(x, y1);
    }

    public ECPoint mul(BigInteger d, ECPoint p)
    {
      return mul(null, d, null, p);
    }

    private BigInteger recoverY(BigInteger x, boolean bit0)
    {
      BigInteger a = ec.getA();
      BigInteger b = ec.getB();
      BigInteger p = field.getP();
      BigInteger y2 = x.multiply(x).add(a).multiply(x).add(b).mod(p);
      BigInteger y = Arithmetic.sqrtP(y2, p);

      if (bit0 != y.testBit(0))
      {
        y = p.subtract(y).mod(p);
      }
      return y;
    }


  }

  static public Curve getSecP256R1()
  {
    return new Curve("secp256r1");
  }

  static public Curve getSecP256K1() { return new Curve("secp256k1"); }

  static public Curve getSecP384R1() { return new Curve("secp384r1"); }

  static public Curve getSecP521R1() { return new Curve("secp521r1"); }



  static void test(SunEC.Curve cc,  com.unbound.common.crypto.ec.Curve curve) throws Exception
  {
    assert(cc.p.equals(curve.getP()));
    assert(cc.b.equals(curve.getB()));
    assert(cc.q.equals(curve.getQ()));
    assert(cc.a.equals(curve.getA()));

    ECPoint GG = cc.G;

    Point G = curve.G;
    assert(!G.isInfinity());
    assert(G.equals(GG));
    assert(G.getX().equals(GG.getAffineX()));
    assert(G.getY().equals(GG.getAffineY()));
    assert(G.isOnCurve());

    ECPoint GG2 = cc.add(GG, GG);
    Point G2 = G.dbl();
    assert(G2.equals(GG2));

    ECPoint GG3 = cc.add(GG2, GG); GG3 = cc.add(GG3, GG3); GG3 = cc.add(GG3, GG);
    Point G3 = G.add(G2);
    G3 = G3.dbl();
    G3 = G3.add(G);
    assert(G3.equals(GG3));
    assert(G3.getX().equals(GG3.getAffineX()));
    assert(G3.getY().equals(GG3.getAffineY()));
    assert(G3.isOnCurve());

    BigInteger dd = new BigInteger(254, new SecureRandom());

    int n = 10000;
/*
    ECPoint GG4 = null;
    ECPrivateKey prvKey = cc.getPrivateKey(dd);
    ECPublicKey pubKey = cc.getPublicKey(GG);
    KeyAgreement ka;
    try { ka = KeyAgreement.getInstance("ECDH"); }
    catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); }
    long t1 = Clock.systemUTC().millis();
    for (int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy