Java - Bouncy Castle中的椭圆曲线场元算法

时间:2017-08-18 14:52:58

标签: java cryptography bouncycastle elliptic-curve

我一直认为使用ECFieldElement对象而不是BigIntegers对exponents执行算术运算更合适,但根据我的测试,这样做会产生不正确的结果。

测试例程(JUnit):

class ArithmeticTest
{

  @Test
  public void testMultDistributativity_BigInteger()
  {
      ECPoint g = getG();

      for (int i=0; i<100; i++)
      {
        BigInteger a, b, c;

        a = randomIntInField(false);
        b = randomIntInField(false);
        c = a.add(b);

        ECPoint gA = g.multiply(a);
        ECPoint gB = g.multiply(b);
        ECPoint gC = g.multiply(c);
        ECPoint sum = gA.add(gB);

        assertEquals(gC, sum);
      }
  }

  @Test
  public void testMultDistributativity_ECFieldElement_SmallValues()
  {
      assertTrue(checkMultDistributativity_ECFieldElement(BigInteger.ONE, BigInteger.TEN));
  }

  @Test
  public void testMultDistributativity_ECFieldElement_RandomValues()
  {
      BigInteger a, b;
      int failureCount=0;

      for (int i=0; i<1000; i++)
      {
        a = randomIntInField(false);
        b = randomIntInField(false);

        if (!checkMultDistributativity_ECFieldElement(a, b))
            failureCount++;
      }

      assertTrue(failureCount==0, "Failed on " + Integer.toString(failureCount) + " out of 1000 runs.");
  }

  private boolean checkMultDistributativity_ECFieldElement(BigInteger a, BigInteger b)
  {
      ECFieldElement fA, fB, fC;
      ECPoint gA, gB, gC, sum;

      fA = getFieldElement(a);
      fB = getFieldElement(b);
      fC = fA.add(fB);

      gA = getG().multiply(a);
      gB = getG().multiply(b);
      gC = getG().multiply(fC.toBigInteger());
      sum = gA.add(gB);

      return gC.equals(sum);
  }

testMultDistributativity_BigIntegertestMultDistributativity_ECFieldElement_SmallValues成功,但testMultDistributativity_ECFieldElement_RandomValues失败了一半的测试用例。

顺便提及,1/2是两个随机字段元素加起来大于字段顺序的概率。我不明白这会如何搞砸。

加载曲线:

  private java.security.spec.EllipticCurve curve;
  private org.bouncycastle.math.ec.ECCurve bcCurve;
  private ECNamedCurveParameterSpec spec;
  private final BigInteger fieldOrder;
  private static final int FIELD_ELEMENT_BIT_SIZE = 256;

  static {
    Security.insertProviderAt(new BouncyCastleProvider(), 1);
  }

  public ArithmeticTest()
  {
    spec= ECNamedCurveTable.getParameterSpec("secp256r1");
    bcCurve = spec.getCurve();

    ECNamedCurveSpec conversionSpec = new ECNamedCurveSpec(spec.getName(), spec.getCurve(), spec.getG(), spec.getN());
    curve = conversionSpec.getCurve();

    fieldOrder = new BigInteger ("ffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 16);
  }

这些是辅助功能:

  private ECPoint getG()
  {
    return spec.getG();
  }

  private ECFieldElement getFieldElement(BigInteger i)
  {
    return bcCurve.fromBigInteger(i);
  }

  private randomIntInField(boolean nonzero)
  {
    final int ARGUMENT_IS_LARGER = -1;
    SecureRandom rand = new SecureRandom();
    BigInteger result;
    int watchDog = 1000;

    do {
        result = new BigInteger(FIELD_ELEMENT_BIT_SIZE, rand);

        if (--watchDog == 0)
            throw new RuntimeException("Damn what are the odds?");
    }
    while ( nonzero && result.equals(BigInteger.ZERO) || result.compareTo(fieldOrder)!= ARGUMENT_IS_LARGER);

    return result;

  }
}

问题可能来自于某种程度的随机化吗?

1 个答案:

答案 0 :(得分:2)

  

我一直认为表演更合适   使用ECFieldElement对象对指数进行算术运算   而不是BigIntegers,但根据我的测试,这样做会产生   结果不正确。

没有!指数(ECPoint.multiply的标量参数)绝对不能使用ECFieldElement处理。 Scalars应以模块组的顺序相互添加,可通过ECCurve.getOrder获得。

因此,无论何时总和fC相对于场模数降低(约50%,如你所说),你的测试就会失败。