Eine ähnliche Frage hat eine Antwort in Python, die auf das bitcointalk-Forum verweist:
Aber ich würde gerne wissen, wie ein Java-Programm für die gleiche Konvertierung geschrieben werden kann? Mir ist aufgefallen, dass Java den Byte-Datentyp verwendet und ich nicht verstehen kann, wie man mit Werten arbeitet.
Ja, Sie können einen 33-Byte-komprimierten öffentlichen Schlüssel in einen 65-Byte-unkomprimierten öffentlichen Schlüssel in Java konvertieren.
Hier ist der Code zum Ausführen der Operation. Es ist korrekt, robust und erfordert nur Java SE-Klassen (keine anderen Bibliotheken) - aber ich entschuldige mich für die Länge der Implementierung.
import java.math.BigInteger;
import java.util.Arrays;
static final BigInteger MODULUS =
new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
static final BigInteger CURVE_A = new BigInteger("0");
static final BigInteger CURVE_B = new BigInteger("7");
// Given a 33-byte compressed public key, this returns a 65-byte uncompressed key.
byte[] decompressPubkey(byte[] compKey) {
// Check array length and type indicator byte
if (compKey.length != 33 || compKey[0] != 2 && compKey[0] != 3)
throw new IllegalArgumentException();
final byte[] xCoordBytes = Arrays.copyOfRange(compKey, 1, compKey.length);
final BigInteger xCoord = new BigInteger(1, xCoordBytes); // Range [0, 2^256)
BigInteger temp = xCoord.pow(2).add(CURVE_A);
temp = sqrtMod(temp.add(CURVE_B));
boolean tempIsOdd = temp.testBit(0);
boolean yShouldBeOdd = compKey[0] == 3;
if (tempIsOdd != yShouldBeOdd)
temp = temp.negate().mod(MODULUS);
final BigInteger yCoord = temp;
// Copy the x coordinate into the new
// uncompressed key, and change the type byte
byte[] result = Arrays.copyOf(compKey, 65);
result[0] = 4;
// Carefully copy the y coordinate into uncompressed key
final byte[] yCoordBytes = yCoord.toByteArray();
for (int i = 0; i < 32 && i < yCoordBytes.length; i++)
result[result.length - 1 - i] = yCoordBytes[yCoordBytes.length - 1 - i];
return result;
}
// Given x, this returns a value y such that y^2 % MODULUS == x.
BigInteger sqrtMod(BigInteger value) {
assert (MODULUS.intValue() & 3) == 3;
BigInteger pow = MODULUS.add(BigInteger.ONE).shiftRight(2);
BigInteger result = value.modPow(pow, MODULUS);
assert result.pow(2).mod(MODULUS).equals(value);
return result;
}
Meine Bitcoin-Kryptografiebibliothek implementiert zwar die Modulo-Prime-Feldarithmetik, sollte aber auch die Funktionalität zum Dekomprimieren öffentlicher Schlüssel hinzufügen ...
022A779D25B43F04C3DD8A27B079FF4C6BECFBDE1419F1CF0B5CDA2AB001517884
könnten Sie bitte überprüfen? scheitert anassert result.pow(2).mod(MODULUS).equals(value);
temp
(x^2+a) mit x multiplizieren, bevor Sie b hinzufügen und aufrufen sqrtMod
. Damit die zweite Assertion korrekt funktioniert, müssen Sie entweder das Argument auf sqrtMod
Modulo p reduzieren oder die Assertion auf Kongruenz statt auf Gleichheit prüfen lassen.Sie können Bouncycastle ECPoint verwenden, um diese Konvertierung durchzuführen:
static ECParameterSpec SPEC = ECNamedCurveTable.getParameterSpec("secp256k1");
static byte[] compressedToUncompressed(byte[] compKey) {
ECPoint point = SPEC.getCurve().decodePoint(compKey);
byte[] x = point.getXCoord().getEncoded();
byte[] y = point.getYCoord().getEncoded();
// concat 0x04, x, and y, make sure x and y has 32-bytes:
return concat(new byte[] {0x04}, x, y);
}
In openssl können Sie die Funktionen EC_POINT_point2oct und EC_POINT_oct2point verwenden, um zwischen komprimiert und unkomprimiert zu konvertieren.
Überprüfen Sie, ob das erste Oktett POINT_CONVERSION_UNCOMPRESSED enthält, wenn Sie wissen möchten, ob es komprimiert ist.
Jestin
prof.Zoom
Jestin