Java - Bouncy Castle中的椭圆曲线场元算法
Java - Elliptic Curve Field Element Arithmetic in Bouncy Castle
我的印象是使用 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_BigInteger
和 testMultDistributativity_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;
}
}
问题可能出在随机化上吗?
I have been under the impression that it is more proper to perform
arithmetic operations on exponents using ECFieldElement objects
instead of BigIntegers, but according to my tests, doing so yields
incorrect results.
没有!绝对不能使用 ECFieldElement 处理指数(ECPoint.multiply 的标量参数)。标量应以组顺序为模相互相加,可通过 ECCurve.getOrder.
获得
因此,只要总和 fC 相对于场模量减少(如您所说,约为 50%),您的测试就会失败。
我的印象是使用 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_BigInteger
和 testMultDistributativity_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;
}
}
问题可能出在随机化上吗?
I have been under the impression that it is more proper to perform arithmetic operations on exponents using ECFieldElement objects instead of BigIntegers, but according to my tests, doing so yields incorrect results.
没有!绝对不能使用 ECFieldElement 处理指数(ECPoint.multiply 的标量参数)。标量应以组顺序为模相互相加,可通过 ECCurve.getOrder.
获得因此,只要总和 fC 相对于场模量减少(如您所说,约为 50%),您的测试就会失败。