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

测试例程(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;

  }
}


问题可能出自某种程度上的随机化吗?

最佳答案

我一直觉得执行起来更合适
  使用ECFieldElement对象对指数进行算术运算
  而不是BigIntegers,但是根据我的测试,这样做会产生
  错误的结果。


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

因此,只要总和fC相对于场模降低(如您所说的〜50%),您的测试就会失败。

08-04 16:10